Mercurial > wow > reaction
changeset 22:1b9323256a1b
Merging in 1.0 dev tree
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Fri, 07 Mar 2008 22:10:55 +0000 |
parents | 90bf38d48efd |
children | dba04d85c799 |
files | Bindings.xml Buttons.lua Defaults.lua KeybindDialog.xml Options.lua README.html ReAction.toc classes/ReAction.lua classes/ReAction_ActionDisplay.lua classes/ReAction_ActionType.lua classes/ReAction_ColorScheme.lua classes/ReAction_PetActionDisplay.lua classes/ReAction_PetActionType.lua classes/ReBar.lua classes/ReBar.xml lib/AceAddon-2.0/AceAddon-2.0.lua lib/AceConsole-2.0/AceConsole-2.0.lua lib/AceDB-2.0/AceDB-2.0.lua lib/AceEvent-2.0/AceEvent-2.0.lua lib/AceLibrary/AceLibrary.lua lib/AceLocale-2.2/AceLocale-2.2.lua lib/AceOO-2.0/AceOO-2.0.lua lib/Dewdrop-2.0/Dewdrop-2.0.lua libs/AceAddon-2.0/AceAddon-2.0.lua libs/AceConsole-2.0/AceConsole-2.0.lua libs/AceDB-2.0/AceDB-2.0.lua libs/AceEvent-2.0/AceEvent-2.0.lua libs/AceLibrary/AceLibrary.lua libs/AceLocale-2.2/AceLocale-2.2.lua libs/AceOO-2.0/AceOO-2.0.lua libs/Dewdrop-2.0/._Dewdrop-2.0.lua libs/Dewdrop-2.0/Dewdrop-2.0.lua libs/FuBarPlugin-2.0/FuBarPlugin-2.0.lua libs/ReAnchor-1.0/ReAnchor-1.0.lua libs/ReBound-1.0/ReBound-1.0.lua libs/Tablet-2.0/Tablet-2.0.lua locale-enUS.lua main.lua |
diffstat | 38 files changed, 13341 insertions(+), 20456 deletions(-) [+] |
line wrap: on
line diff
--- a/Bindings.xml Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -<Bindings> - <Binding name="REACTION_TOGGLELOCK" header="REACTION"> - ReActionAddOn:ToggleLocked() - </Binding> - <Binding name="REACTION_TOGGLEKEYBIND"> - ReActionAddOn:ToggleKeybindMode() - </Binding> -</Bindings>
--- a/Buttons.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,412 +0,0 @@ --- Buttons.lua --- --- Defines button types for use with the ReAction AddOn --- - -local AceOO = AceLibrary("AceOO-2.0") -local ReBound = AceLibrary("ReBound-1.0"):new("ReAction") - -local Action = AceOO.Class( - ReAction, - ReAction.ActionType, - ReAction.ActionDisplay, - ReAction.DefaultColorScheme -) - -local PetAction = AceOO.Class( - ReAction, - ReAction.PetActionType, - ReAction.PetActionDisplay, - ReAction.DefaultColorScheme -) - - -ReAction:AddButtonType( "Action", Action, 120 ) -ReAction:AddButtonType( "Pet Action", PetAction, 10 ) - - - ------------------------ --- static class members ------------------------ -Action.defaultProfile = { - type = "ReAction", - subtype = "Action", - buttons = { }, - selfcast = nil, - keyBindLoc = "TOPRIGHT", - keyBindRightLoc = "RIGHT", - stackCountLoc = "BOTTOMRIGHT", - showKeyBind = true, - showKeyBindRight = false, - showStackCount = true, - showMacroText = true, - showBorder = true, - keyBindColorCode = false, - hideCooldown = false, - hideGlobalCooldown = false, -} - -PetAction.defaultProfile = { - type = "ReAction", - subtype = "Pet Action", - buttons = { }, - keyBindLoc = "TOPRIGHT", - showKeyBind = false, - showGrid = false, - showBorder = true, - keyBindColorCode = false, -} - - - ------------------------ --- static class methods ------------------------ -function Action:GetDefaultProfile() - return self.defaultProfile -end - -function PetAction:GetDefaultProfile() - return self.defaultProfile -end - - - -local labelPlacementOptions = { - "TOP", - "BOTTOM", - "LEFT", - "RIGHT", - "TOPLEFT", - "TOPRIGHT", - "BOTTOMLEFT", - "BOTTOMRIGHT" -} - - -function Action:GenerateOptionsTable( config, buttonListFunc ) - - local function refresh() - for _, b in pairs(buttonListFunc()) do - b:UpdateAction() - b:UpdateTooltip() - b:UpdateDisplay() - end - end - - local function setOpacity(field, value) - if not config.opacity then - config.opacity = { } - end - config.opacity[field] = (value and value / 100) - refresh() - end - - local function getOpacity(field, default) - local o = config.opacity and config.opacity[field] or (default and default/100) or 1 - return o * 100 - end - - return { - type = "group", - args = { - selfcast = { - type = "text", - name = "Self Cast", - desc = "Choose a modifier key to hold down or an alternate button to click to self-cast spells. ".. - "'default' uses the settings in the Interface Options Advanced panel (use this to achieve 'smart self cast'). ".. - "'right-click' self-casting is not supported for multi-page bars.", - get = function() return config.selfcast or "default" end, - set = function(opt) - if opt == "default" then opt = nil end - config.selfcast = opt - for _, b in pairs(buttonListFunc()) do - b:UpdateSelfcast() - end - end, - validate = { "default", "none", "alt", "ctrl", "shift", "right-click" }, - order = 101 - }, - - opacity = { - type = "group", - name = "Opacity", - desc = "Set options for variable button opacity", - args = { - usable = { - type = "range", - name = "Usable", - desc = "Button opacity when the action is currently usable", - min = 0, - max = 100, - step = 1, - get = function() return getOpacity("usable") end, - set = function(x) setOpacity("usable", x) end, - order = 1, - }, - - notUsable = { - type = "range", - name = "Not Usable", - desc = "Button opacity when the action is currently not usable", - min = 0, - max = 100, - step = 1, - get = function() return getOpacity("notUsable") end, - set = function(x) setOpacity("notUsable",x) end, - order = 2, - }, - - oom = { - type = "range", - name = "Out of Power", - desc = "Button opacity when the action is not usable due to not enough mana/energy/rage. ".. - "By default this uses the generic 'not-usable' setting.", - min = 0, - max = 100, - step = 1, - get = function() return getOpacity("oom",getOpacity("notUsable")) end, - set = function(x) setOpacity("oom", x ~= getOpacity("notUsable") and x) end, - order = 3, - }, - - oorange = { - type = "range", - name = "Out of Range", - desc = "Button opacity when the action is not usable due to the target not being in range. ".. - "By default this uses the generic 'not-usable' setting.", - min = 0, - max = 100, - step = 1, - get = function() return getOpacity("ooRange",getOpacity("notUsable")) end, - set = function(x) setOpacity("ooRange", x ~= getOpacity("notUsable") and x) end, - order = 4, - }, - - empty = { - type = "range", - name = "Empty Slot", - desc = "Button opacity when the button's action slot is empty. By default this is 0 (fully transparent), ".. - "but note that they still block mouse clicks. Empty slots are automatically made opaque (per the ".. - "'usable' opacity setting) when moving actions around.", - min = 0, - max = 100, - step = 1, - get = function() return getOpacity("empty",0) end, - set = function(x) setOpacity("empty",x) end, - order = 5, - }, - - hideEmpty = { - type = "toggle", - name = "Hide Empty Slots", - desc = "Hides empty action slots rather than changing their opacity. This has the advantage that empty slots ".. - "don't block mouse clicks. WARNING: this makes it impossible to re-arrange actions with drag-and-drop ".. - "while in combat.", - get = function() return config.hideEmptySlots end, - set = function() config.hideEmptySlots = not config.hideEmptySlots ; refresh() end, - order = 6, - }, - - }, - order = 102, - }, - - displaysep = { - type = "header", - name = " ", - desc = " ", - order = 103, - }, - - showkeybind = { - type = "toggle", - name = "Show Hotkey", - desc = "Toggle show/hide hot key labels", - get = function() return config.showKeyBind end, - set = function() config.showKeyBind = not config.showKeyBind ; refresh() end, - order = 104, - }, - - keyloc = { - type = "text", - name = "Hotkey Location", - desc = "Sets hotkey location", - get = function() return config.keyBindLoc end, - set = function(loc) config.keyBindLoc = loc ; refresh() end, - hidden = function() return not config.showKeyBind end, - validate = labelPlacementOptions, - order = 105, - }, - - showKeyBindRight = { - type = "toggle", - name = "Show Right-click Hotkey", - desc = "Toggle show/hide right-click hot key labels", - get = function() return config.showKeyBindRight end, - set = function() config.showKeyBindRight = not config.showKeyBindRight ; refresh() end, - order = 106, - }, - - rightkeyloc = { - type = "text", - name = "Right-click Hotkey Location", - desc = "Sets right-click hotkey location", - get = function() return config.keyBindRightLoc end, - set = function(loc) config.keyBindRightLoc = loc ; refresh() end, - hidden = function() return not config.showKeyBindRight end, - validate = labelPlacementOptions, - order = 107, - }, - - colorhotkeys = { - type = "toggle", - name = "Colorize Hotkeys", - desc = "Toggles coloring hotkeys based on the modifier key. Out-of-range coloring is always enabled.", - get = function() return config.keyBindColorCode end, - set = function() config.keyBindColorCode = not config.keyBindColorCode ; refresh() end, - hidden = function() return not config.showKeyBind and not config.showKeyBindRight end, - order = 109, - }, - - showstackcount = { - type = "toggle", - name = "Show Stack Count", - desc = "Toggle show/hide stack count labels", - get = function() return config.showStackCount end, - set = function() config.showStackCount = not config.showStackCount ; refresh() end, - order = 110, - }, - - stackloc = { - type = "text", - name = "Stack Count Location", - desc = "Sets stack count location", - get = function() return config.stackCountLoc end, - set = function(loc) config.stackCountLoc = loc ; refresh() end, - hidden = function() return not config.showStackCount end, - validate = labelPlacementOptions, - order = 111, - }, - - showmacrotext = { - type = "toggle", - name = "Show Macro Names", - desc = "Toggle show/hide macro name labels", - get = function() return config.showMacroText end, - set = function() config.showMacroText = not config.showMacroText ; refresh() end, - order = 112, - }, - - hidecooldown = { - type = "toggle", - name = "Hide Cooldowns", - desc = "Hides all cooldown displays on buttons. Toggling this on does not hide currently running cooldowns.", - get = function() return config.hideCooldown end, - set = function() config.hideCooldown = not config.hideCooldown ; refresh() end, - order = 114, - }, - - hideglobalcooldown = { - type = "toggle", - name = "Hide Global Cooldown", - desc = "Disables the global cooldown from being displayed on buttons.", - get = function() return config.hideGlobalCooldown end, - set = function() config.hideGlobalCooldown = not config.hideGlobalCooldown ; refresh() end, - hidden = function() return not config.hideCooldown end, - order = 115, - }, - - --[[ - hideborder = { - type = "toggle", - name = "Hide Border", - desc = "Toggles hiding of the button border frame.", - get = function() return not config.showBorder end, - set = function() config.showBorder = not config.showBorder ; refresh() end, - },]] - } - } -end - - -function PetAction:GenerateOptionsTable( config, buttonListFunc ) - - local function refresh() - for _, b in pairs(buttonListFunc()) do - b:UpdateAction() - b:UpdateTooltip() - b:UpdateDisplay() - end - end - - return { - type = "group", - args = { - keyloc = { - type = "text", - name = "Hotkey Location", - desc = "Sets hotkey location", - get = function() return config.keyBindLoc end, - set = function(loc) config.keyBindLoc = loc ; refresh() end, - validate = { "TOP", "BOTTOM", "LEFT", "RIGHT", "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT" }, - }, - - showkeybind = { - type = "toggle", - name = "Show Hotkey", - desc = "Toggle show/hide hot key labels", - get = function() return config.showKeyBind end, - set = function() config.showKeyBind = not config.showGrid ; refresh() end, - }, - - showgrid = { - type = "toggle", - name = "Always Show Buttons", - desc = "Show button placeholders when no action is assigned or on the cursor. Note that buttons are always shown when bars are unlocked.", - get = function() return config.showGrid end, - set = function() config.showGrid = not config.showGrid ; refresh() end, - }, - - colorhotkeys = { - type = "toggle", - name = "Colorize Hotkeys", - desc = "Toggles coloring hotkeys based on the modifier key. Out-of-range coloring is always enabled.", - get = function() return config.keyBindColorCode end, - set = function() config.keyBindColorCode = not config.keyBindColorCode ; refresh() end, - }, - - --[[ - hideborder = { - type = "toggle", - name = "Hide Border", - desc = "Toggles hiding of the button border frame.", - get = function() return not config.showBorder end, - set = function() config.showBorder = not config.showBorder ; refresh() end, - },]] - } - } -end - - - ----------------------- --- Instance methods ----------------------- -function Action.prototype:init( id ) - Action.super.prototype.init(self) - - self:SetupDisplay("ReActionButton"..id) - self:SetupAction() - ReBound:Register(self:GetActionFrame()) -end - -function PetAction.prototype:init( id ) - Action.super.prototype.init(self) - - self:SetupDisplay("ReActionPetButton"..id) - self:SetupAction() - ReBound:Register(self:GetActionFrame()) -end -
--- a/Defaults.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -local function tcopy(t) - local r = { } - for k, v in pairs(t) do - r[k] = (type(v) == "table" and tcopy(v) or v) - end - return r -end - --- ReAction default variable tables -local defaultActionConfig = ReAction:GetButtonType("Action"):GetDefaultProfile() -local defaultPetActionConfig = ReAction:GetButtonType("Pet Action"):GetDefaultProfile() - - --- default saved variables -ReAction_DefaultProfile = { - hideArt = false, - bars = { }, - bindings = { } -} - -ReAction_DefaultBarConfig = { - ["ReAction"] = { - ["Action"] = { - visible = true, - size = 36, - spacing = 6, - rows = 1, - columns = 12, - pages = nil, - opacity = 100, - anchor = { - frame = "UIParent", - point = "CENTER", - relPoint = "CENTER", - x = 0, - y = 0, - }, - btnConfig = tcopy(defaultActionConfig) - }, - ["Pet Action"] = { - visible = true, - parent = "PetActionBarFrame", - size = 30, - spacing = 8, - rows = 1, - columns = 10, - pages = nil, - opacity = 100, - anchor = { - frame = "UIParent", - point = "CENTER", - relPoint = "CENTER", - x = 0, - y = 0, - }, - btnConfig = tcopy(defaultPetActionConfig), - } - }, -} - --- startup layout replicates Blizzard layout (only set on first-run or reset) -ReAction_DefaultBlizzardBars = { - - -- main paged action bar - [1] = { - visible = true, - size = 36, - spacing = 6, - rows = 1, - columns = 12, - growLeft = false, - growUp = false, - columnMajor = false, - pages = { - n = 6, - showControls = true, - controlsLoc = "Blizzard", - autoStanceSwitch = true, -- priests will get a shadowform bar switch, unlike blizzard's - autoStealthSwitch = true, -- this is different from blizzard's layout, only for druids - }, - opacity = 100, - anchor = { - frame = "MainMenuBarArtFrame", - point = "BOTTOMLEFT", - relPoint = "BOTTOMLEFT", - x = 3, - y = 0, - }, - btnConfig = tcopy(defaultActionConfig), - }, - - -- pet action bar - [10] = { - visible = true, - parent = "PetActionBarFrame", - size = 30, - spacing = 8, - rows = 1, - columns = 10, - growLeft = false, - growUp = false, - columnMajor = false, - pages = nil, - opacity = 100, - anchor = { - frame = "PetActionBarFrame", - point = "BOTTOMLEFT", - relPoint = "BOTTOMLEFT", - x = 31, - y = -1, - }, - btnConfig = tcopy(defaultPetActionConfig), - }, - -} - --- default settings for action IDs match Blizzard's settings... --- ... except on the main bar extra pages, which map directly to the default shapeshift IDs --- rather than mirroring the multi action bars, to give access to all 120 actions -local bars = ReAction_DefaultBlizzardBars - -for i = 1, 12 do - bars[1].btnConfig.buttons[i] = { - id = i, - actions = { - i, - 72+i, - 84+i, - 96+i, - 108+i, - 12+i - } - } -end - -for i = 1, 10 do - bars[10].btnConfig.buttons[i] = { id = i } -end - -
--- a/KeybindDialog.xml Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,108 +0,0 @@ -<Ui xmlns="http://www.blizzard.com/wow/ui/" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> - - - <Frame name="ReActionKeybindDialog" frameStrata="DIALOG" movable="true" hidden="true" enableMouse="true"> - <Size> - <AbsDimension x="270" y="95"/> - </Size> - <Anchors> - <Anchor point="CENTER"/> - </Anchors> - <TitleRegion> - <Size> - <AbsDimension x="200" y="30"/> - </Size> - <Anchors> - <Anchor point="TOP"> - <Offset> - <AbsDimension x="0" y="-10"/> - </Offset> - </Anchor> - </Anchors> - </TitleRegion> - <Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true"> - <BackgroundInsets> - <AbsInset left="4" right="4" top="4" bottom="4"/> - </BackgroundInsets> - <TileSize> - <AbsValue val="16"/> - </TileSize> - <EdgeSize> - <AbsValue val="16"/> - </EdgeSize> - </Backdrop> - <Layers> - <Layer level="ARTWORK"> - <FontString inherits="GameFontNormalLarge" text="REACTION_KEYBIND_TITLE" justifyH="CENTER"> - <Size> - <AbsDimension x="200" y="30"/> - </Size> - <Anchors> - <Anchor point="TOP"> - <Offset> - <AbsDimension x="0" y="-10"/> - </Offset> - </Anchor> - </Anchors> - </FontString> - <FontString inherits="GameFontNormalSmall" text="REACTION_KEYBIND_SUBTITLE" justifyH="CENTER"> - <Size> - <AbsDimension x="240" y="70"/> - </Size> - <Anchors> - <Anchor point="TOP"> - <Offset> - <AbsDimension x="0" y="-10"/> - </Offset> - </Anchor> - </Anchors> - </FontString> - </Layer> - </Layers> - <Frames> - <Button inherits="GameMenuButtonTemplate" text="REACTION_KEYBIND_DONE"> - <Size> - <AbsDimension x="112" y="28"/> - </Size> - <Anchors> - <Anchor point="BOTTOMLEFT" relativePoint="BOTTOM"> - <Offset> - <AbsDimension x="10" y="10"/> - </Offset> - </Anchor> - </Anchors> - <Scripts> - <OnClick> - this:GetParent().save = true - this:GetParent():Hide() - </OnClick> - </Scripts> - </Button> - <Button inherits="GameMenuButtonTemplate" text="REACTION_KEYBIND_REVERT"> - <Size> - <AbsDimension x="112" y="28"/> - </Size> - <Anchors> - <Anchor point="BOTTOMRIGHT" relativePoint="BOTTOM"> - <Offset> - <AbsDimension x="-10" y="10"/> - </Offset> - </Anchor> - </Anchors> - <Scripts> - <OnClick> - this:GetParent():Hide() - </OnClick> - </Scripts> - </Button> - </Frames> - <Scripts> - <OnLoad> - table.insert(UISpecialFrames, this:GetName()) - </OnLoad> - </Scripts> - </Frame> - -</Ui>
--- a/Options.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ --- Ace2 global options tables for ReAction - - --- autogenerate the NewBar sub-types table -local function GenerateNewBarArgs() - local args = { } - for _, name in pairs(ReAction:GetButtonTypeList() ) do - args[name] = { - type="execute", - name=name, - desc=name, - } - end - return args -end - - -ReActionConsoleOptions = { - type="group", - args={ - lock = { - type = "execute", - name = "lock", - desc = "Locks action bars and disables rearrangement", - func = "Lock", - }, - - unlock = { - type = "execute", - name = "unlock", - desc = "Unlocks action bars and enables rearrangement", - func = "Unlock", - }, - - keybind = { - type = "toggle", - name = "keybind", - desc = "keybind setup mode", - get = "GetKeybindMode", - set = "SetKeybindMode", - }, - - hideart = { - type = "toggle", - name = "hideart", - desc = "Hide default Blizzard action bar artwork and XP bar", - get = "IsArtHidden", - set = "ToggleHideArt", - }, - - create = { - type = "group", - name = "create", - pass = true, - func = "NewBar", - args = GenerateNewBarArgs(), - desc = "Create a new bar", - }, - - resetall = { - type = "execute", - name = "resetall", - desc = "Resets to single bar in the default position", - func = "ResetBars", - }, - } -} - - -ReActionGlobalMenuOptions = { - type = "group", - -- handler = nil, -- NOTE: this variable isn't defined yet, must be added later - args={ - lockbars = { - type = "toggle", - name = "Lock Bars", - desc = "Locks action bars and disables rearrangement", - get = "IsLocked", - set = "ToggleLocked", - order = 1, - }, - - lockbtns = { - type = "toggle", - name = "Lock Buttons", - desc = "Prevents buttons from being dragged off accidentally. Shift-drag instead.", - get = function() return LOCK_ACTIONBAR == "1" end, - set = function() LOCK_ACTIONBAR = (LOCK_ACTIONBAR == "1" and "0" or "1") end, - order = 2, - }, - - new = { - type = "group", - name = "New bar", - pass = true, - func = "NewBar", - args = GenerateNewBarArgs(), - desc = "Create a new bar", - order = 3, - }, - - keybind = { - type = "toggle", - name = "Set Key Bindings", - desc = "keybind setup mode", - get = "GetKeybindMode", - set = "SetKeybindMode", - order = 4, - }, - - hidedefault = { - type = "toggle", - name = "Hide Default Main Menu Bar", - desc = "Hides default Blizzard main menu bar, including bag bar, micro menu bar, shapeshift bar, lag meter, and XP bar", - get = "IsArtHidden", - set = "ToggleHideArt", - order = 6, - }, - - } -} - - - - - -function GenerateReActionBarOptions( bar, main ) - local opts = { - type = "group", - handler = bar, - args = { - - sep1 = { - type = "header", - name = " ", - desc = " ", - order = 1, - }, - - hdr1 = { - type = "header", - name = "Options for Bar #"..bar.barID, - desc = "Options for Bar #"..bar.barID, - order = 2, - }, - - layout = { - type = "group", - name = "Layout", - desc = "Button ordering options", - order = 3, - args = { - growLeft = { - type = "toggle", - name = "Right to Left", - desc = "Lay out buttons right-to-left rather than left-to-right", - get = "GetGrowLeft", - set = "SetGrowLeft", - order = 3, - }, - - growUp = { - type = "toggle", - name = "Bottom to Top", - desc = "Lay out buttons bottom-to-top rather than top-to-bottom", - get = "GetGrowUp", - set = "SetGrowUp", - order = 4, - }, - - columnMajor = { - type = "toggle", - name = "Arrange in Columns", - desc = "Lay out buttons sequentially in columns, rather than in rows", - get = "GetColumnMajor", - set = "SetColumnMajor", - order = 5, - }, - - flip = { - type = "execute", - name = "Flip rows/columns", - desc = "Swaps the number of rows and columns, and inverts the button numbering", - func = "FlipRowsColumns", - order = 6, - }, - }, - }, - - paging = { - type = "group", - name = "Paging", - desc = "Multi-page options", - order = 4, - args = { - pages = { - type = "range", - name = "Number of Pages", - desc = "Sets the number of pages", - get = "GetPages", - set = "SetPages", - min = 1, - max = 10, - step = 1, - order = 1, - }, - - autostance = { - type = "toggle", - name = "Auto Stance Switch", - desc = "Automatically switch pages when changing stance or shapeshift form.", - get = "GetAutoStanceSwitch", - set = "ToggleAutoStanceSwitch", - order = 2, - }, - - autostealth = { - type = "toggle", - name = "Auto Stealth Switch", - desc = "Automatically switch pages when stealthing/unstealthing.", - get = "GetAutoStealthSwitch", - set = "ToggleAutoStealthSwitch", - order = 3, - }, - - hidecontrols = { - type = "toggle", - name = "Hide Paging Controls", - desc = "Hide the page up/down controls", - get = "ArePageControlsHidden", - set = "TogglePageControlsHidden", - order = 4, - disabled = "IsPagingDisabled", - }, - - controlsloc = { - type = "text", - name = "Control location", - desc = "Location of the page up/down controls", - get = function() return bar:GetPageControlsLoc() or "Blizzard" end, - set = function(loc) bar:SetPageControlsLoc(loc) end, - order = 5, - disabled = function() return bar:IsPagingDisabled() or bar:ArePageControlsHidden() end, - validate = { "Blizzard", "LEFT", "RIGHT", "TOP", "BOTTOM" } - }, - }, - }, - - visibility = { - type = "group", - name = "Visibility", - desc = "Set bar visibility options", - order = 5, - args = { - visible = { - type = "toggle", - name = "Always Visible", - desc = "The bar will always be visible.|n This setting overrides conditional settings below.", - get = "GetVisibility", - set = function() bar:SetVisibility(true) end, - order = 1, - }, - - hidden = { - type = "toggle", - name = "Always Hidden", - desc = "The bar will always be hidden, except when bars are unlocked.|n This setting overrides conditional settings below.", - get = function() return not bar:GetVisibility() end, - set = function() bar:SetVisibility(false) end, - order = 2, - }, - - spring = { - type = "toggle", - name = "Spring Bar Mode", - desc = "The bar is collapsed to a single button, which displays the last action used. Mousing over the button shows the entire bar.|n This setting overrides conditional settings below.", - get = function() end, - set = function() end, - hidden = true, - disabled = true, -- not yet implemented - order = 3, - }, - - conditional = { - type = "group", - name = "Auto Show", - desc = "Dynamically hide and show the entire bar based on certain conditions.", - hidden = true, - disabled = true, -- not yet implemented - order = 4, - args = { - - mouseover = { - type = "toggle", - name = "Show On Mouseover", - desc = "Show the bar only when the mouse is over it.", - disabled = true, -- not yet implemented - get = function() end, - set = function() end, - order = 1, - }, - - combat = { - type = "toggle", - name = "Show In Combat", - desc = "Show the bar only when in combat.", - disabled = true, -- not yet implemented - get = function() end, - set = function() end, - order = 2, - }, - - nocombat = { - type = "toggle", - name = "Hide in Combat", - desc = "Show the bar only when not in combat.", - disabled = true, -- not yet implemented - get = function() end, - set = function() end, - order = 3, - } - } - }, - - } - }, - - delete = { - type = "execute", - name = "Delete Bar #"..bar.barID, - desc = "Deletes bar #"..bar.barID, - func = function() main:DeleteBar(bar.barID) end, - order = 7 - }, - } - } - - -- generate the auto-hide options for shapeshift forms. Note that this will - -- only show forms that the character has learned, and the ordering may (? did this get fixed?) - -- vary from character to character of the same class - local args = opts.args.visibility.args.conditional.args - for i = 1, GetNumShapeshiftForms() do - local _, name = GetShapeshiftFormInfo(i) - args["stance"..i] = { - type = "toggle", - name = "Show In "..name, - desc = "Show the bar when in "..name.."." , - get = function() end, - set = function() end, - order = #args + 1, - disabled = true, - } - end - - return opts -end -
--- a/README.html Fri Mar 07 21:54:26 2008 +0000 +++ b/README.html Fri Mar 07 22:10:55 2008 +0000 @@ -1,292 +0,0 @@ -<html> -<head> -<title>ReAction: README</title> -<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> -<style type="text/css"> -<!-- -body { background-color: #FFFFCC; list-style-type: none} -p { margin-top: 0px; margin-bottom: 18px} -ul { line-height: 110%} ---> -</style> -</head> - -<body bgcolor="#FFFFFF" text="#000000"> -<h1 align="center">ReAction</h1> -<h3 align="center">AddOn for World of Warcraft</h3> -<p><font size="2">Current Version: 0.34 (alpha)<br> - Released: 09 Mar 2007</font><font size="2"><br> - WoW Version Compatibility: v2.0.10 / TOC 20003</font></p> -<h2>The Basics</h2> -<p>ReAction is a replacement for the default Blizzard action bars. It allows you - redefine your action button layout any way you like.</p> -<h2>Features</h2> -<ul> - <li>Move, resize, create, and arrange as many action bars as you want. Each - bar can contain any number of buttons arranged in a grid layout of any size - and spacing. The full complement of 120 action slots is supported.</li> - <li>Works with all types of actions, including abilities, items, and macros</li> - <li>Layout is done with the mouse, by dragging bars and bar edges on screen. - Automatically anchor bars to each other or the screen edges by holding shift - down as you drag.</li> - <li>Context menus provide independent configuration options for each bar.</li> - <li>Point and click keybinding interface. You can bind keys to left-click or - right-click independently.</li> - <li>Supports multiple 'pages' per bar, configured independently. Automatic stance, - form, and stealth switching among pages is supported, including Shadowform.</li> - <li>Pet action bar is fully supported and configurable.</li> - <li>Settings can be saved per account, realm, character, class, or independent - profile. </li> - <li>Compatible with OmniCC</li> - <li>Various configurable display options</li> -</ul> -<p>ReAction is built using the <a href="http://www.wowace.com/Wiki/Ace2">Ace2</a> - development framework.</p> -<h2>Using ReAction</h2> -<h3>Installation</h3> -<p>To install ReAction, drag the ReAction folder to your World of Warcraft/Interface/AddOns - folder. Exit World of Warcraft if it's running, then restart.</p> -<h3>Welcome to ReAction</h3> -<p>When you first enter World of Warcraft with ReAction installed, it will look - very similar to the default Blizzard UI, depending on what other AddOns are - installed. However, only the main menu bar is shown by default. Other bars can - be created as desired.</p> -<p>If you have FuBar installed, on the left side you should see the ReAction plugin - icon and label. If not, there should be a button on your minimap. In either - case, that button (the ReAction Control Button) is the gateway to configuring - ReAction.</p> -<p>ReAction has three modes of operation:</p> -<ul> - <li>Normal ("locked")</li> - <li>Configuration ("unlocked")</li> - <li>Keybinding</li> -</ul> -<p>(Technically it's 4 modes, because Config and Keybinding modes can both be - active at the same time).</p> -<p>You can toggle Configuration mode by shift-clicking the ReAction Control Button - and toggle Keybinding mode by alt-clicking the button. Global configuration - options are also available by right-clicking the ReAction button. There are - also a limited set of console commands that can be accessed with the "/reaction" - or "/rxn" slash-commands. Type /rxn in the chat box to print a list - of commands.</p> -<p>You can also set key bindings to toggle Configuration and Keybinding modes, - in the standard UI keybindings panel.</p> -<h3>Configuring ReAction</h3> -<p>Start by shift-clicking the ReAction button to enter Configuration mode. All - bars, including hidden bars, are shown in this mode and <b>normal button click - operation is disabled </b>(though keybindings still work). Mouse over the bars, - edges, and corners to see tooltip instructions for moving, resizing, and rearranging - them. Right click each bar for a menu of options pertaining to that bar. For - example, to change a hidden bar to a visible bar, right-click on a bar and choose - Visibility -> Always Visible. Tooltips for each menu option provide details.</p> -<p>When you're done configuring ReAction, shift-click the ReAction button again - to go back to Normal mode.</p> -<p>Configuration mode is not available if you are in combat, and is automatically - cancelled if you enter combat.</p> -<h3>Setting Keybindings</h3> -<p><b>ReAction buttons don't use the regular keybindings of the default UI.</b> - In order to get your buttons to use hotkeys, enter ReAction Keybinding Setup - mode by alt-clicking the ReAction Control Button (or choosing 'keybinding mode' - from the right-click menu). <b>ReAction button keybindings are not available - from the standard keybindings menu!</b> You <i>must</i> use the ReAction keybinding - interface. They're even greyed out in the keybinding menu with a textual reminder, - so there's no excuse!</p> -<p>Like configuration mode, normal button operation is disabled while in keybinding - mode (though again, any hotkeys you have assigned will work). With the keybinding - interface out, you can mouseover any ReAction button to see what its current - keybinding is. You can set the keybinding on a button by clicking the button, - then pressing the key. To clear a keybinding from a ReAction button, shift-click - the button. Tooltips will remind you of this interface. You can also right-click/shift-right-click - to set/clear a right-click hotkey, which will simulate right-clicking the button - (useful for complex macro actions, typically to save screen real estate). If - you've set up bars with multiple pages, you can also bind a key to the page - up/down buttons on a per-bar basis. Just make sure the buttons are showing (they - can be hidden later) and assign the keybinding like any other ReAction button.</p> -<p>Keybindings are saved on a per-profile basis. Keybinding mode is not available - if you are in combat, and is automatically cancelled if you enter combat. When - you first log in with ReAction, it steals the current keybindings from the default - main action bar (buttons 1-12) and assigns them to the corresponding buttons - on the default ReAction bar. This means that if you install ReAction, run with - it, and then disable it, your main bar will no longer have any keybindings and - they'll need to be reset. If you later enable ReAction again, it will remember - its own keybindings.</p> -<p>If a profile assigns a keybinding to a ReAction button, switching away from - that profile will clear the binding but will <b>not</b> restore the binding - to its previous state. If the new profile assigns that binding then, of course, - it will be in use. What this means is that any 'standard' keybinding action - that's bound to a key will become unbound when switching to a profile that uses - the key, and will have to be manually rebound later if you switch away from - that profile.</p> -<p><b>Remember to click the 'Save' button to save your keybindings! </b>If you - do not, they will automatically revert to the previous bindings when exiting - keybinding mode. This can be useful for "trying out" certain layouts - briefly, but can also be a serious gotcha — if you just hit 'Escape,' or - alt-click the ReAction Control Button, or enter combat while in keybinding mode, - your bindings will revert to their previous state.</p> -<h3>Playing with ReAction</h3> -<p>Once you get your keybindings and configuration set up, you're ready to go. - The buttons behave just like regular Blizzard buttons. However, at any time - when you're not in combat, you can quickly switch to configuration mode and - create a new bar, rearrange bars, hide/show a special-use bar, etc. Perfect - for when you get some goofy quest item that has to be used temporarily, or get - a new skill that doesn't fit on your current layout.</p> -<h2>Limitations</h2> -<ul> - <li>Due to a lack of certain functionality made available by Blizzard, dragging - and dropping actions onto action bars while in combat is a little funky. You - have to click the destination button rather than just release drag on it.</li> - <li>You can't configure the pet bar unless you actually have a pet out. </li> - <li>No support for shapeshift/stance bar (yet)</li> - <li>If you have a bar with empty buttons, even though they're invisible they - still block mouse input from reaching whatever might be under the button. - This is a workaround so that you can drag and drop actions onto hidden slots - during combat. This workaround can be disabled via a configuration option, - but then you can't drag and drop actions onto slots during combat. Pick your - poison, it's a limitation of Blizzard's protection scheme.</li> - <li>If you hide the default main menu bar, there is no substitute provided (yet) - for the XP bar, bag bar, or micro menu bar (although the hotkeys for them - still work). Other addons can provide these features until ReAction supports - them.</li> -</ul> -<h2>Known Issues</h2> -<ul> - <li>There may or may not be a particular case in which turning off a pet's attack - while using Eyes of the Beast doesn't work. Further investigation (and leveling - a hunter to get Eyes of the Beast :-P) is required.</li> - <li>The initial mapping of action IDs for shapeshift forms doesn't exactly match - Blizzard's mapping. When first starting up as a warrior, druid, or rogue, - you will probably need to move your actions around, and it will likely screw - up your layout if you swap back to the default UI.</li> - <li>Action IDs may not always be laid out in sequence, meaning that similar - layouts on different machines may put the actions in a different order. For - best results, copy the WTF/Account/<AccountName>/SavedVariables/ReAction.lua - from one computer to the other, when you get a setup you like.</li> - <li>There seems to be a big performance hit when first dragging a bar after - entering configuration mode, and when first enabling keybinding mode, if there - are several bars and a lot of buttons out. More investigation is necessary.</li> -</ul> -<h2>Future Plans</h2> -<ul> - <li>Add support for bag bar, shapeshift bar, and micro menu bar. May also add - XP bar to default unit frames for those who don't want to use a unit frame - addon to get the XP bar back.</li> - <li>More dynamic bar support: auto show/hide/fade on stance switch, in combat, - key pressed, etc.</li> - <li>"pop-up" bar support, in which a single button shows/hides a bar - when moused over</li> - <li>Better and more flexible interface for defining page transitions on stance/form - shift </li> - <li>Provide a method for normalizing the action ID layout, permitting better - compatibility when used on different computers.</li> - <li>Provide some additional console commands so that enterprising users can - macro certain configuration functionality (notably hiding and showing individual - bars) </li> - <li>Yet more configurable button display options (disable cooldown flash, different - borders, etc)</li> - <li>Button styles (Dreamlayout, CyCircled)</li> - <li>Localization</li> -</ul> -<h2>Version History</h2> -<p>Version 0.34:</p> -<ul> - <li>Fixed some bugs in the keybinding code, and further refined the ReBound - library. </li> -</ul> -<p>Version 0.33:</p> -<ul> - <li>Rewrote the keybinding interface (again). I think I finally like this version. - Keybindings are now saved and loaded with the profile, and honor the "character-specific - keybindings" setting in the Blizzard Keybinding pane. The default keybindings - for action bars are now greyed out in Blizzard's interface to remind you to - use ReAction to set bindings for action bars.</li> - <li>Moved the Action ID label on the buttons to the center of the button.</li> - <li>Added support for binding right-clicks to hotkeys on the main action buttons - only (no pet buttons). There is also an option (off by default) to display - and specify the location for right-click binding labels.</li> - <li>Tweaked the ordering of the bar menus. Some options will automatically show/hide - when they are relevant.</li> - <li>Converted the core of the keybinding code to an Ace2-style library: ReBound-1.0</li> - <li>Did a little bit of code cleanup in main.lua</li> - <li>Converted to MIT license</li> -</ul> -<p>Version 0.32:</p> -<ul> - <li>Fixed a bug with displaying cooldowns generating slews of errors</li> -</ul> -<p>Version 0.31:</p> -<ul> - <li>Fixed a bug where action IDs > 120 were being configured and allocated - in certain cases</li> - <li>Fixed a bug where hidden paging controls were reappearing when switching - pages</li> - <li>Fixed a script error that was popping up in certain conditions when starting - keybinding mode, and causing some buttons not to be bindable</li> - <li>Applied a fix that will (hopefully?) eliminate errors saying ACTIONBAR_UPDATE_STATE - was not registered (be on the lookout for recurrences of that one). Hopefully - this fix will eliminate several other intermittent errors that I think are - part of the same cause.</li> - <li>Added new options for controlling the opacity of buttons (which should now - actually work). Previous opacity settings (if any) will be lost and will need - to be re-applied after updating. There is also now a toggle to hide (rather - than alpha-zero) empty buttons, at the expense of not being able to drag actions - onto them during combat.</li> - <li>Action IDs now appear/disappear automatically when bars are unlocked. There - is no longer a menu item to show/hide them.</li> - <li>Changed the default startup bar configuration to only be the paged main - bar. This allows a default startup to create new bars without having to delete - some first. Will probably simplify even further in a future patch. Note this - doesn't fix the action-rearrangement setup headaches with warriors, druids, - and rogues.</li> - <li>Cooldowns can now be hidden - either all cooldowns or just global cooldowns.</li> -</ul> -<p>Version 0.3</p> -<ul> - <li>Complete rewrite of the innards for better modularity</li> - <li>Lots of bug fixes</li> - <li>Multi-paged bar support</li> - <li>Pet bar support</li> - <li>Auto stance/form/stealth switching</li> - <li>Lots and lots of new configuration options</li> -</ul> -<p>Version 0.2</p> -<ul> - <li>Bug fixes from 0.1</li> - <li>new keybinding interface</li> -</ul> -<p>Version 0.1</p> -<ul> - <li>Initial concept, button arrangement</li> -</ul> -<h2>Credits</h2> -<p>Huge credit to the <a href="http://www.wowace.com">Ace 2</a> development team, - whose framework provides a level of functionality that I consider critical to - the success of this addon. Similarly, enormous credit goes to <a href="http://ckknight.wowinterface.com">ckknight</a>, - whose Dewdrop menuing system and FuBar plugin system are ridiculously easy to - use.</p> -<p>Thanks to the authors of certain action bar mods that came before ReAction: - Bartender3, Bongos, FlexBar 2, and Trinity Bars. While I didn't steal any code - directly from you guys, your addons provided inspiration for various features - and options. Hopefully ReAction differentiates itself sufficiently that it's - not seen as simply a clone.</p> -<p>Finally, thanks to my alpha testers and stalwart adventuring companions: Deor, - Nogrim, Sorabel, and Yngvi (or, more to the point, their alts :-P).</p> -<h2>Copyright & License</h2> -<p>ReAction is distributed under the MIT license.</p> -<p>ReAction Copyright © 2007 Ryan Findley.</p> -<p>Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is furnished - to do so, subject to the following conditions:</p> -<p>The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software.</p> -<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p> -<p>World of Warcraft is a registered trademark of Blizzard Entertainment, Inc.</p> -</body> -</html>
--- a/ReAction.toc Fri Mar 07 21:54:26 2008 +0000 +++ b/ReAction.toc Fri Mar 07 22:10:55 2008 +0000 @@ -1,47 +1,16 @@ -## Interface: 20003 -## Title: ReAction |cff7fff7f -Ace2-|r -## Notes: An action bar and button layout tool +## Interface: 20300 +## Title: ReAction +## Notes: Action button layout and configuration ## DefaultState: enabled ## LoadOnDemand: 0 ## Author: Flick -## Version: 0.4 -## X-Description: An action bar and button layout tool +## Version: 1.0 +## SavedVariables: ReActionDB +## OptionalDeps: Ace2, DewdropLib, Waterfall ## X-Category: Action Bars -## SavedVariables: ReActionDB -## SavedVariablesPerCharacter: ReActionDBPC -## OptionalDeps: Ace2, FuBar -## X-Embeds: Ace2, Dewdrop, Tablet, FuBarPlugin, ReBound, ReAnchor +## X-Embeds: AceAddon-2.0, AceConsole-2.0, AceDB-2.0, AceEvent-2.0, AceHook-2.1, AceLibrary, AceLocale-2.2, AceModuleCore-2.0, AceOO-2.0, Dewdrop-2.0, Waterfall-1.0 -libs\AceLibrary\AceLibrary.lua -libs\AceOO-2.0\AceOO-2.0.lua -libs\AceAddon-2.0\AceAddon-2.0.lua -libs\AceDB-2.0\AceDB-2.0.lua -libs\AceConsole-2.0\AceConsole-2.0.lua -libs\AceEvent-2.0\AceEvent-2.0.lua -libs\AceLocale-2.2\AceLocale-2.2.lua -libs\Dewdrop-2.0\Dewdrop-2.0.lua -libs\Tablet-2.0\Tablet-2.0.lua -libs\FuBarPlugin-2.0\FuBarPlugin-2.0.lua -libs\ReBound-1.0\ReBound-1.0.lua -libs\ReAnchor-1.0\ReAnchor-1.0.lua - -locale-enUS.lua - -classes\ReBar.xml -classes\ReBar.lua - -classes\ReAction.lua -classes\ReAction_ActionType.lua -classes\ReAction_ActionDisplay.lua -classes\ReAction_ColorScheme.lua -classes\ReAction_PetActionType.lua -classes\ReAction_PetActionDisplay.lua - -Buttons.lua -Defaults.lua -Options.lua - -main.lua - -KeybindDialog.xml - +embeds.xml +locale.xml +ReAction.lua +modules.xml
--- a/classes/ReAction.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ --- --- ReAction is a base class for action button management. It provides a --- framework for button setup, placement, recycling, keybinding, etc. --- It does not define any layout or actual action functionality, --- which is deferred to derived classes. --- --- ReAction implements the ReBar.IButton interface. It is designed to be used with ReBar --- for grouping and laying out buttons. --- --- Each instance of a ReAction-derived object is associated with a single action --- button frame, which may or may not have a one-to-one mapping with actionID. --- --- ReAction makes use of a configuration structure, which can (and should) be --- extended by implementations. A single config structure is shared amongst all --- ReAction class instances within a single ReBar group, so the structure should --- contain sub-tables for any property that needs to be defined on a per-button --- basis. Each button is passed a 'barIdx' parameter to be used as an index into --- such tables. --- --- The base config structure is as follows: --- --- config = { --- type = "ReAction", -- static string (used by ReBar) --- subtype = "string", -- ReAction implementation identifier (index into ReAction.buttonTypes) --- buttons = { --- id = n, -- global button ID number --- actions = { {paged list}, {paged list}, ... } -- indexed by self.barIdx --- } --- } --- - - -local AceOO = AceLibrary("AceOO-2.0") -local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc - - --- private constants --- TODO: localize these key names with GetBindingText(KEY_) -local keybindAbbreviations = { - ["Mouse Button "] = "M-", - ["Spacebar"] = "Sp", - ["Num Pad "] = "Num-", - ["Page Up"] = "PgUp", - ["Page Down"] = "PgDn", - [" Arrow"] = "", -} - - ------------------------- --- Interface Declarations ------------------------- - --- The ActionType interface defines what the button does when it is clicked. At a --- minimum it must do the equivalent of SetAttribute("type", ...) and handle events that --- cause the action to change. --- ReAction implementations must provide this interface (implicitly or explicitly). -local IActionType = AceOO.Interface { - SetID = "function", -- SetID(id, [page]) optional argument indicates page #: omitting indicates default. self.config.idx[barIdx] must be updated. - GetID = "function", -- id = GetID([page]) optional argument indicates page #: omitting indicates current page - IsActionEmpty = "function", -- bool = IsActionEmpty() - SetupAction = "function", -- one-time setup - UpdateAction = "function", -- general action properties should be refreshed - PickupAction = "function", -- pick up the action on the button and put on the cursor - PlaceAction = "function", -- place the action on the cursor - UpdateTooltip = "function", -- update the tooltip with the action's info -} - --- The Display interface defines the "look and feel" of the action button. It should define the --- actual widgets and widget layout and provide methods to update the display. --- ReAction implementations must provide this interface (implicitly or explicitly). --- Note that ReAction implementations may also require additional display interfaces to be supported. --- --- Also note: the class 'new' method must take *only* the primary button ID as an argument. -local IDisplay = AceOO.Interface { - SetupDisplay = "function", -- SetupDisplay(buttonName), one-time setup - UpdateDisplay = "function", -- UpdateDisplay(), general display state should be refreshed - TempShow = "function", -- TempShow(visible), calls to this can be nested so keep track. - GetActionFrame = "function", -- f = GetActionFrame(), return a frame derived from SecureActionButtonTemplate (note: this is inherited unimplemented from ReBar.IButton) - GetBaseButtonSize = "function", -- sz = GetBaseButtonSize(), return size in pixels of the nominal button (square) - DisplayID = "function", -- DisplayID(show), true/false to show/hide the action ID (or equivalent) - DisplayHotkey = "function", -- DisplayHotkey(keyText, button), set the hotkey display text. 2nd argument specifies which button the hotkey is for, default is "LeftButton". -} - - ----------------------------- --- ReAction class definition ----------------------------- - -ReAction = AceOO.Class("AceEvent-2.0", ReBar.IButton, IActionType, IDisplay) -ReAction.virtual = true -ReAction.IActionType = IActionType -ReAction.IDisplay = IDisplay - - ------------------------ --- Static class members ------------------------ - -ReAction.recycler = CreateFrame("Frame",nil,UIParent) -ReAction.recycler:SetAllPoints(UIParent) -ReAction.recycler:Hide() - -ReAction.buttonTypes = { } - - - ------------------------ --- Static class methods ------------------------ - -function ReAction:AddButtonType( name, class, maxIDs ) - self.buttonTypes[name] = { subtype = class, maxIDs = maxIDs } -end - -function ReAction:GetButtonType( name ) - if name then - local t = self.buttonTypes[name] - if t then - return t.subtype, t.maxIDs - end - end -end - -function ReAction:GetButtonTypeList() - local list = { } - for name, _ in pairs(self.buttonTypes) do - table.insert(list,name) - end - return list -end - -function ReAction:GetAvailableID( subtype, hint ) - local class, maxIDs = self:GetButtonType(subtype) - - -- store the list of action buttons in use in the button type class factory - if class._idTbl == nil then class._idTbl = { } end - local t = class._idTbl - local id = nil - - -- find lowest ID not in use - for i = 1, maxIDs do - if t[i] == nil or t[i].inUse == false then - id = i - break - end - end - - if id == nil then return nil end -- all action ids are in use - - -- if a hint is given, see if that one is free instead, as long as it's < maxIDs - if hint and hint > 0 and hint <= maxIDs and (t[hint] == nil or t[hint].inUse == false) then - id = hint - end - - if t[id] == nil then - t[id] = { } - end - t[id].inUse = true - - return id, t[id] -end - -function ReAction:Acquire(config, barIdx, pages, buttonsPerPage) - local btnType = self:GetButtonType(config.subtype) - if not btnType then - error("ReAction: Unknown button type specified.") - end - pages = pages or 1 - - local ids = { } - local primary = nil - - for i = 1, pages do - local hint = config.buttons and config.buttons.actions[barIdx] - if hint == nil and i > 1 and ids[i-1] then - hint = ids[i-1] + (buttonsPerPage or 0) - end - local id, p = self:GetAvailableID(config.subtype, hint) - if id == nil then - break - end - primary = primary or p - if id then - ids[i] = id - end - end - - if primary then - if not primary.button then - primary.button = btnType:new(ids[1]) - end - if primary.button then - config.buttons.actions[barIdx] = ids - primary.button:Configure(config,barIdx) - end - end - - return primary and primary.button -end - -function ReAction:Release( b ) - if b then - for i = 1, #b.config.buttons.actions[b.barIdx] do - local id = b:GetID(i) - if id then - b.class._idTbl[id].inUse = false - end - end - b.config = nil - b:Recycle() - end -end - -function ReAction:ShowAllIds() - for _, t in pairs(self.buttonTypes) do - if t.subtype._idTbl then - for _, tbl in pairs(t.subtype._idTbl) do - if tbl.button then tbl.button:DisplayID(true) end - end - end - end - self.showIDs_ = true -end - -function ReAction:HideAllIds() - for _, t in pairs(self.buttonTypes) do - if t.subtype._idTbl then - for _, tbl in pairs(t.subtype._idTbl) do - if tbl.button then tbl.button:DisplayID(false) end - end - end - end - self.showIDs_ = false -end - - ----------------------- --- Instance methods ----------------------- - --- constructor - -function ReAction.prototype:init() - ReAction.super.prototype.init(self) -end - - --- ReBar.IButton interface - -function ReAction.prototype:BarUnlocked() - self:TempShow(true) - self:DisplayID(true) -end - -function ReAction.prototype:BarLocked() - self:TempShow(false) - self:DisplayID(false) -end - -function ReAction.prototype:PlaceButton(parent, point, x, y, sz) - local b = self:GetActionFrame() - local baseSize = self:GetBaseButtonSize() - local scale = baseSize and baseSize ~= 0 and ((sz or 1) / baseSize) or 1 - if scale == 0 then scale = 1 end - b:ClearAllPoints() - b:SetParent(parent) - b:SetScale(scale) - b:SetPoint(point,x/scale,y/scale) -end - -function ReAction.prototype:SetPages( n ) - n = tonumber(n) - local ids = self.config.buttons.actions[self.barIdx] - if n and n >= 1 then - -- note that as long as n >= 1 then id[1] will never be modified, which is what we want - -- because then the button frame ID would be out of sync with the static button name - while #ids < n do - local id = ReAction:GetAvailableID(self.config.subtype, ids[#ids] + #self.config.buttons.actions) - if id == nil then - break - end - self:SetID( id, #ids + 1 ) - table.insert(ids, id) - end - while #ids > n do - local id = table.remove(ids) - self:SetID( nil, #ids + 1 ) - self.class._idTbl[id].inUse = false - end - end -end - --- Event handlers - -function ReAction.prototype:UPDATE_BINDINGS() - self:DisplayHotkey(self:GetKeyBindingText("LeftButton", true),"LeftButton") - self:DisplayHotkey(self:GetKeyBindingText("RightButton",true),"RightButton") -end - - --- Internal functions - -function ReAction.prototype:Recycle() - self:UnregisterAllEvents() - - -- tuck the frame away - local b = self:GetActionFrame() - b:SetParent(ReAction.recycler) - b:ClearAllPoints() - b:SetPoint("TOPLEFT",0,0) - b:Hide() -end - -function ReAction.prototype:Configure( config, barIdx ) - self.config = config - self.barIdx = barIdx - - local ids = config.buttons.actions[barIdx] - self:SetID(ids[1]) -- default id - for i = 1, #ids do - self:SetID(ids[i], i) -- paged ids - end - self:UpdateAction() - self:UpdateDisplay() - self:DisplayHotkey(self:GetKeyBindingText(nil, true)) - - self:RegisterEvent("UPDATE_BINDINGS") -end - -function ReAction.prototype:SetKeyBinding( k, mouseBtn ) - if k == nil or kbValidate(k) then - local current = self:GetKeyBinding(mouseBtn) - if current then - SetBinding(current,nil) - end - if k then - SetBindingClick(k, self:GetActionFrame():GetName(), mouseBtn or "LeftButton") - end - end -end - -function ReAction.prototype:GetKeyBinding( mouseBtn ) - return GetBindingKey("CLICK "..self:GetActionFrame():GetName()..":"..(mouseBtn or "LeftButton")) -end - -function ReAction.prototype:GetKeyBindingText( mouseBtn, abbrev ) - local key = self:GetKeyBinding(mouseBtn) - local txt = key and GetBindingText(key, "KEY_", abbrev and 1) or "" - - if txt and abbrev then - -- further abbreviate some key names - for pat, rep in pairs(keybindAbbreviations) do - txt = string.gsub(txt,pat,rep) - end - end - return txt -end - -function ReAction.prototype:SetTooltip() - GameTooltip_SetDefaultAnchor(GameTooltip, self:GetActionFrame()) - self:UpdateTooltip() -end - -function ReAction.prototype:ClearTooltip() - tooltipTime = nil - GameTooltip:Hide() -end
--- a/classes/ReAction_ActionDisplay.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,452 +0,0 @@ --- The ReAction.ActionDisplay mixin defines 'regular' action button display functionality --- and is an implementation of the ReAction.IDisplay and ReAction.ActionType.IDisplay interfaces. --- --- This Mixin assumes that it has been mixed in with a ReAction-derived class which implements --- the ReAction.IActionType and ReAction.IColorScheme interfaces. --- --- This mixin uses properties of self.config to define display elements: --- --- self.config = { --- keyBindLoc = "POSITION", -- keybind anchor location --- stackCountLoc = "POSITION", -- stack count anchor location --- showKeyBind = true/false, -- show keybind labels --- showStackCount = true/false, -- show stack count labels --- showMacroText = true/false, -- show macro name labels --- showGrid = true/false, -- always show empty buttons --- hideCooldown = true/false, -- hide the cooldown timer --- hideGlobalCooldown = true/false, -- hide cooldown timers if duration < 1.5 seconds (global) --- opacity = { --- default = 0-100 [100], -- button opacity when the action is usable (default opacity) --- notUsable = 0-100 [100], -- button opacity when the action is not usable --- oom = 0-100 [notUsable], -- button opacity when the action is not usable due to OOM --- ooRange = 0-100 [notUsable], -- button opacity when the action is not usable due to out of range --- empty = 0-100 [0], -- button opacity when the action slot is empty --- }, --- hideEmptySlots = true/false, -- show/hide empty buttons rather than change opacity to 0 --- } --- - -local AceOO = AceLibrary("AceOO-2.0") - -ReAction.ActionDisplay = AceOO.Mixin { - -- ReAction.IDisplay interface - "SetupDisplay", - "UpdateDisplay", - "TempShow", - "GetActionFrame", - "GetBaseButtonSize", - "DisplayID", - "DisplayHotkey", - - -- ReAction.ActionType.IDisplay interface - "DisplayUsable", - "DisplayEquipped", - "DisplayAutoRepeat", - "DisplayInUse", - "DisplayIcon", - "DisplayName", - "DisplayCount", - "DisplayCooldown", - - -- Event handlers - "PostClick", - "OnDragStart", - "OnReceiveDrag", - "OnEnter", - "OnLeave", - "OnUpdate", - - -- internal functions - "ApplyLayout", - "ApplyStyle", - "StartFlash", - "StopFlash", - "IsFlashing", - "DisplayVisibility", -} - -local RAAD = ReAction.ActionDisplay - - --- private constants -local _G = getfenv(0) - -local equippedActionBorderColor = { r=0.00, g=1.00, b=0.00, a=0.35 } -- transparent green -local actionIDColor = { r=1.00, g=0.82, b=0.00, a=1.00 } -- gold - --- private functions --- extract and return color fields from a table, to be fed into SetVertexColor()/SetTextColor() -local function tcolor(c) - return c.r, c.g, c.b, c.a -end - - ------------------------------------ --- Interface Implementation Methods ------------------------------------ -function RAAD:SetupDisplay( name ) - -- create the button widget - local b = CreateFrame("CheckButton", name, nil, "SecureActionButtonTemplate, ActionButtonTemplate") - - -- store references to the various sub-frames of ActionButtonTemplate so we don't have to look it up all the time - self.frames = { - button = b, - hotkey = _G[name.."HotKey"], - count = _G[name.."Count"], - cooldown = _G[name.."Cooldown"], - macro = _G[name.."Name"], - icon = _G[name.."Icon"], - border = _G[name.."Border"], - flash = _G[name.."Flash"], - normalTexture = _G[name.."NormalTexture"], - actionID = nil, -- defer creating actionID font string until it's actually requested - } - - -- ??? odd: why do we have to increment the cooldown frame level to get it to show? - -- (otherwise it's behind the icon). The default UI doesn't have to (or at least I can't - -- find where it does) but for some reason we have to here. - self.frames.cooldown:SetFrameLevel(self.frames.cooldown:GetFrameLevel() + 1) - - -- create a right-click hotkey label - local hkr = b:CreateFontString(nil,"ARTWORK","NumberFontNormalSmallGray") - hkr:SetWidth(36) - hkr:SetHeight(10) - hkr:Hide() - self.frames.hotkeyright = hkr - - b:EnableMouse() - b:RegisterForDrag("LeftButton", "RightButton") - b:RegisterForClicks("AnyUp") - b:SetScript("PostClick", function(arg1) self:PostClick(arg1) end) - b:SetScript("OnDragStart", function(arg1) self:OnDragStart(arg1) end) - b:SetScript("OnReceiveDrag", function() self:OnReceiveDrag() end) - b:SetScript("OnEnter", function() self:OnEnter() end) - b:SetScript("OnLeave", function() self:OnLeave() end) - -- defer setting OnUpdate until actions are actually attached - - self.tmpShow_ = 0 -end - -function RAAD:UpdateDisplay() - self:ApplyLayout() - self:ApplyStyle() - self:DisplayVisibility() - -- refresh the action ID display - if ReAction.showIDs_ then - self:DisplayID(true) - end -end - -function RAAD:TempShow( visible ) - visible = visible and true or false -- force data integrity - self.showTmp_ = max(0, (self.showTmp_ or 0) + (visible and 1 or -1)) - self:DisplayVisibility() -end - -function RAAD:GetActionFrame() - return self.frames.button -end - -function RAAD:GetBaseButtonSize() - return 36 -end - -function RAAD:DisplayID( show ) - local f = self.frames.actionID - if show then - if not f then - -- create the actionID label - f = self.frames.button:CreateFontString(nil,"ARTWORK","NumberFontNormalSmall") - f:SetPoint("CENTER") - f:SetTextColor( tcolor(actionIDColor) ) - self.frames.actionID = f - end - f:SetText(tostring(self:GetID())) - f:Show() - elseif f then - f:Hide() - end -end - -function RAAD:DisplayHotkey(txt,button) - button = button or "LeftButton" - if button == "LeftButton" then - self.frames.hotkey:SetText(string.upper(txt or "")) - elseif button == "RightButton" then - self.frames.hotkeyright:SetText(string.upper(txt or "")) - end - self:UpdateUsable() -end - -function RAAD:DisplayUsable( isUsable, notEnoughMana, outOfRange ) - local f = self.frames - f.icon:SetVertexColor( self:GetIconColor(isUsable, notEnoughMana, outOfRange) ) - f.button:GetNormalTexture():SetVertexColor( self:GetBorderColor(isUsable, notEnoughMana, outOfRange) ) - f.hotkey:SetTextColor( self:GetHotkeyColor(isUsable, notEnoughMana, outOfRange, f.hotkey:GetText()) ) - f.hotkeyright:SetTextColor( self:GetHotkeyColor(isUsable, notEnoughMana, outOfRange, f.hotkeyright:GetText()) ) - - local o - if isUsable then - o = self.config.opacity and self.config.opacity.usable or 1 - else - o = self.config.opacity and self.config.opacity.notUsable or 1 - if notEnoughMana then - o = self.config.opacity and self.config.opacity.oom or o - elseif outOfRange then - o = self.config.opacity and self.config.opacity.ooRange or o - end - end - - self.currentOpacity = o -- store for use in DisplayVisibility - self:DisplayVisibility() -end - -function RAAD:DisplayEquipped( equipped ) - local b = self.frames.border - if equipped then - b:Show() - else - b:Hide() - end -end - -function RAAD:DisplayAutoRepeat( r ) - if r then - self:StartFlash() - else - self:StopFlash() - end -end - -function RAAD:DisplayInUse( inUse ) - self.frames.button:SetChecked( inUse and 1 or 0 ) -end - -function RAAD:DisplayIcon( texture ) - local f = self.frames.button - local icon = self.frames.icon - if texture then - icon:SetTexture(texture) - icon:Show() - self.rangeTimer = -1 - f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") - if f:GetScript("OnUpdate") == nil then - f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end) - end - else - icon:Hide() - self.rangeTimer = nil - f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") - f:SetScript("OnUpdate",nil) - end - self:DisplayVisibility() -end - -function RAAD:DisplayCooldown( start, duration, enable ) - enable = (enable > 0 ) and not self.config.hideCooldown and (not self.config.hideGlobalCooldown or duration > 1.5) and 1 or 0 - CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enable) -end - -function RAAD:DisplayName( name ) - self.frames.macro:SetText(name and tostring(name) or "") -end - -function RAAD:DisplayCount( count ) - self.frames.count:SetText(count and tostring(count) or "") -end - - - - - ----------------------- --- Event Handlers ----------------------- -function RAAD:PostClick() - self:UpdateInUse() -end - -function RAAD:OnDragStart() - if LOCK_ACTIONBAR ~= "1" or IsShiftKeyDown() then - self:PickupAction() - end -end - -function RAAD:OnReceiveDrag() - self:PlaceAction() -end - -function RAAD:OnEnter() - self:SetTooltip() -- from ReAction base class - self.tooltipTime = TOOLTIP_UPDATE_TIME -end - -function RAAD:OnLeave() - self:ClearTooltip() -- from ReAction base class - self.tooltipTime = nil -end - -function RAAD:OnUpdate(elapsed) - -- handle flashing - if self:IsFlashing() then - self.flashtime = self.flashtime - elapsed - if self.flashtime <= 0 then - local overtime = -self.flashtime - if overtime >= ATTACK_BUTTON_FLASH_TIME then - overtime = 0 - end - self.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime - - local f = self.frames.flash - if f then - if f:IsVisible() then - f:Hide() - else - f:Show() - end - end - end - end - - -- Handle range indicator - if self.rangeTimer then - self.rangeTimer = self.rangeTimer - elapsed - if self.rangeTimer <= 0 then - self:UpdateUsable() - self.rangeTimer = TOOLTIP_UPDATE_TIME - end - end - - -- handle tooltip update - if self.tooltipTime then - self.tooltipTime = self.tooltipTime - elapsed - if self.tooltipTime <= 0 then - if GameTooltip:IsOwned(self.frames.button) then - self:UpdateTooltip() - self.tooltipTime = TOOLTIP_UPDATE_TIME - else - self.tooltipTime = nil - end - end - end -end - - - ----------------------- --- Internal methods ----------------------- - -local function placeLabel( label, anchor ) - local top = string.match(anchor,"TOP") - local bottom = string.match(anchor, "BOTTOM") - label:ClearAllPoints() - label:SetWidth(40) - label:SetPoint(top or bottom or "CENTER",0,top and 2 or bottom and -2 or 0) - local j - if string.match(anchor,"LEFT") then - j = "LEFT" - elseif string.match(anchor,"RIGHT") then - j = "RIGHT" - else - j = "CENTER" - end - label:SetJustifyH(j) -end - - -function RAAD:ApplyLayout() - local f = self.frames - - if self.config.keyBindLoc then - placeLabel(f.hotkey, self.config.keyBindLoc) - end - - if self.config.keyBindRightLoc then - placeLabel(f.hotkeyright, self.config.keyBindRightLoc) - end - - if self.config.stackCountLoc then - placeLabel(f.count, self.config.stackCountLoc) - end - - if self.config.showKeyBind then - f.hotkey:Show() - else - f.hotkey:Hide() - end - - if self.config.showKeyBindRight then - f.hotkeyright:Show() - else - f.hotkeyright:Hide() - end - - if self.config.showStackCount then - f.count:Show() - else - f.count:Hide() - end - - if self.config.showMacroName then - f.macro:Show() - else - f.macro:Hide() - end - -end - -function RAAD:ApplyStyle() - local f = self.frames - -- for now, just a static style - f.hotkey:SetFontObject(NumberFontNormal) - f.hotkeyright:SetFontObject(NumberFontNormalSmall) - f.count:SetFontObject(NumberFontNormalYellow) - f.border:SetVertexColor( tcolor(equippedActionBorderColor) ) -end - -function RAAD:StartFlash() - self.flashing = true - self.flashtime = 0 -end - -function RAAD:StopFlash() - self.flashing = false - self.frames.flash:Hide() -end - -function RAAD:IsFlashing() - return self.flashing -end - -function RAAD:DisplayVisibility() - local b = self.frames.button - - if b:GetAttribute("statehidden") then - -- can't hide/show in combat - if not InCombatLockdown() then - b:Hide() - end - elseif self.showTmp_ and self.showTmp_ > 0 then - b:GetNormalTexture():SetAlpha(0.5) - if self:IsActionEmpty() then - self.frames.cooldown:Hide() - if not InCombatLockdown() and not b:IsShown() then - b:Show() - end - end - b:SetAlpha(1) - elseif not self:IsActionEmpty() then - b:GetNormalTexture():SetAlpha(1.0) - b:SetAlpha(self.currentOpacity or (self.config.opacity and self.config.opacity.usable) or 1) - else - if self.config.hideEmptySlots then - if not InCombatLockdown() then - b:Hide() - end - else - b:SetAlpha(self.config.opacity and self.config.opacity.empty or 0) - end - end -end -
--- a/classes/ReAction_ActionType.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,360 +0,0 @@ --- The ReAction.ActionType mixin defines 'regular' action button functionality --- and is an implementation of the ReAction.IActionType interface. --- --- The Mixin assumes that it is being mixed in with a ReAction-derived class --- which implements the ReAction.IDisplay and ReAction.ActionType.IDisplay interfaces. --- --- This mixin using the following configuration properties: --- --- self.config = { --- selfcast = nil / "alt" / "ctrl" / "shift" / "auto" / "none". nil (default) = use Interface Options menu setting. --- } --- - -local AceOO = AceLibrary("AceOO-2.0") - -ReAction.ActionType = AceOO.Mixin { - -- ReAction.IActionType interface - "SetID", - "GetID", - "SetupAction", - "UpdateAction", - "PickupAction", - "PlaceAction", - "IsActionEmpty", - "UpdateTooltip", - - -- event handlers - "ACTIONBAR_SLOT_CHANGED", - "PLAYER_ENTERING_WORLD", - "ACTIONBAR_SHOWGRID", - "ACTIONBAR_HIDEGRID", - "ACTIONBAR_UPDATE_STATE", - "ACTIONBAR_UPDATE_USABLE", - "UNIT_INVENTORY_CHANGED", - "CRAFT_SHOW", - "PLAYER_ENTER_COMBAT", - "PLAYER_LEAVE_COMBAT", - "START_AUTOREPEAT_SPELL", - "STOP_AUTOREPEAT_SPELL", - "OnAttributeChanged", - - -- internal functions - "UpdateSelfcast", - "UpdateIcon", - "UpdateInUse", - "UpdateCount", - "UpdateMacroText", - "UpdateUsable", - "UpdateCooldown", - "UpdateActionEvents", -} - -local RAAT = ReAction.ActionType - - --- Required display elements -RAAT.IDisplay = AceOO.Interface { - DisplayUsable = "function", -- DisplayUsable(bool, notEnoughMana, outOfRange), change display to indicate action usable/unusable - DisplayEquipped = "function", -- DisplayEquipped(bool) - DisplayAutoRepeat = "function", -- DisplayAutoRepeat(bool) - DisplayInUse = "function", -- DisplayInUse(bool) - DisplayIcon = "function", -- DisplayIcon(texture), nil means empty slot - DisplayName = "function", -- DisplayName(text), macro names - DisplayCount = "function", -- DisplayCount(number), stack count - DisplayCooldown = "function", -- DisplayCooldown(start,duration,enable) -} - - ---------------------------------------- --- ReAction.IActionType interface implementation ---------------------------------------- -function RAAT:SetID( id, page ) - local f = self:GetActionFrame() - id = tonumber(id) -- force data integrity - page = tonumber(page) - local button = page and ("-page"..page) or "*" - if id then - f:SetAttribute("*action"..button, id) - if page and page > 1 and self.config.selfcast == "right-click" then - -- disable right-click auto-cast - self.config.selfcast = nil - end - elseif page then - f:SetAttribute("*action"..button, ATTRIBUTE_NOOP) - end - self:UpdateSelfcast() -end - -function RAAT:GetID(page) - local f = self:GetActionFrame() - page = tonumber(page) - local button = page and ("page"..page) or SecureStateChild_GetEffectiveButton(f) - return SecureButton_GetModifiedAttribute(f, "action", button) -end - -function RAAT:SetupAction() - local f = self:GetActionFrame() - f:SetAttribute("useparent*", true) - f:SetAttribute("type", "action") - - self:RegisterEvent("PLAYER_ENTERING_WORLD") - self:RegisterEvent("ACTIONBAR_SLOT_CHANGED") - self:RegisterEvent("ACTIONBAR_SHOWGRID") - self:RegisterEvent("ACTIONBAR_HIDEGRID") - - self:UpdateSelfcast() - - f:SetScript("OnAttributeChanged", function(frame,name,value) self:OnAttributeChanged(name,value) end) -end - -function RAAT:UpdateAction() - self:UpdateIcon() - self:UpdateCount() - self:UpdateMacroText() - self:UpdateUsable() - self:UpdateCooldown() - self:UpdateActionEvents() -end - -function RAAT:PickupAction() - PickupAction(self:GetID()) - self:UpdateAction() -end - -function RAAT:PlaceAction() - if not InCombatLockdown() then - -- PlaceAction() is protected. However the user can still drop a new action - -- onto a button while in combat by dragging then clicking, because - -- UseAction() appears to swap the cursor action for the current action if - -- an action is on the cursor. - PlaceAction(self:GetID()) - -- the ACTIONBAR_SLOT_CHANGED event will handle the update - end -end - -function RAAT:IsActionEmpty() - local slot = self:GetID() - return not(slot and HasAction(slot)) -end - -function RAAT:UpdateTooltip() - local action = self:GetID() - if action and GameTooltip:IsOwned(self:GetActionFrame()) then - GameTooltip:SetAction(action) - end -end - - - - - - - ------------------------------ --- Event Handling ------------------------------ -function RAAT:ACTIONBAR_SLOT_CHANGED(slot) - if slot == 0 or slot == self:GetID() then - self:UpdateAction() - end -end - -function RAAT:PLAYER_ENTERING_WORLD() - self:UpdateAction() -end - -function RAAT:ACTIONBAR_SHOWGRID() - self:TempShow(true) -end - -function RAAT:ACTIONBAR_HIDEGRID() - self:TempShow(false) -end - -function RAAT:ACTIONBAR_UPDATE_STATE() - self:UpdateInUse() -end - -function RAAT:ACTIONBAR_UPDATE_USABLE() - self:UpdateUsable() - self:UpdateCooldown() -end - -function RAAT:UNIT_INVENTORY_CHANGED(unit) - if unit == "player" then - self:UpdateIcon() - self:UpdateCount() - end -end - -function RAAT:CRAFT_SHOW() - self:UpdateInUse() -end - -function RAAT:PLAYER_ENTER_COMBAT() - if IsAttackAction(self:GetID()) then - self:DisplayAutoRepeat(true) - self:UpdateInUse() - end -end - -function RAAT:PLAYER_LEAVE_COMBAT() - if IsAttackAction(self:GetID()) then - self:DisplayAutoRepeat(false) - self:UpdateInUse() - end -end - -function RAAT:START_AUTOREPEAT_SPELL() - if IsAutoRepeatAction(self:GetID()) then - self:DisplayAutoRepeat(true) - end -end - -function RAAT:STOP_AUTOREPEAT_SPELL() - if not IsAttackAction(self:GetID()) then - self:DisplayAutoRepeat(false) - self:UpdateInUse() - end -end - -function RAAT:OnAttributeChanged(name, value) - if self.config then - self:UpdateAction() - self:UpdateDisplay() - end -end - - - - ---------------------------------- --- Internal methods ---------------------------------- -function RAAT:UpdateSelfcast() - if not InCombatLockdown() then - local c = self.config and self.config.selfcast - local f = self:GetActionFrame() - - f:SetAttribute("alt-unit*",nil) - f:SetAttribute("ctrl-unit*",nil) - f:SetAttribute("shift-unit*",nil) - f:SetAttribute("*unit2",nil) - if c == nil then - f:SetAttribute("unit",nil) - f:SetAttribute("checkselfcast", true) - else - f:SetAttribute("checkselfcast",ATTRIBUTE_NOOP) - f:SetAttribute("unit","none") -- "none" gives you the glowing cast hand if no target selected, or casts on target if target selected - if c == "none" then - -- nothing to do - elseif c == "alt" or c == "ctrl" or c == "shift" then - f:SetAttribute(c.."-unit*","player") - elseif c == "right-click" then - if f:GetAttribute("*action-page2") then - -- right-click modifier not supported with multipage - self.config.selfcast = nil - f:SetAttribute("unit",nil) - f:SetAttribute("checkselfcast",true) - else - f:SetAttribute("*unit2","player") - end - end - end - end -end - -function RAAT:UpdateIcon() - local action = self:GetID() - local texture = action and GetActionTexture(action) - - self:DisplayIcon(action and texture) - self:DisplayEquipped(action and IsEquippedAction(action)) - self:UpdateInUse() - self:UpdateUsable() - self:UpdateCooldown() -end - -function RAAT:UpdateInUse() - local action = self:GetID() - if action and (IsCurrentAction(action) or IsAutoRepeatAction(action)) then - self:DisplayInUse(true) - else - self:DisplayInUse(false) - end -end - -function RAAT:UpdateCount() - local action = self:GetID() - if action and (IsConsumableAction(action) or IsStackableAction(action)) then - self:DisplayCount(GetActionCount(action)) -- will display a 0 if none remaining - else - self:DisplayCount(nil) -- will display nothing - end -end - -function RAAT:UpdateMacroText() - local action = self:GetID() - self:DisplayName(action and GetActionText(action)) -end - -function RAAT:UpdateUsable() - local action = self:GetID() - if action and HasAction(action) then - local isUsable, notEnoughMana = IsUsableAction(action) - local outOfRange = IsActionInRange(action) == 0 - self:DisplayUsable(isUsable and not outOfRange, notEnoughMana, outOfRange) - else - self:DisplayUsable(false, false, false) - end -end - -function RAAT:UpdateCooldown() - local action = self:GetID() - if action then - self:DisplayCooldown(GetActionCooldown(action)) - end -end - -function RAAT:UpdateActionEvents() - local action = self:GetID() - if action and HasAction(action) then - if not self.actionEventsRegistered then - self:RegisterEvent("ACTIONBAR_UPDATE_STATE") - self:RegisterEvent("ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("UPDATE_INVENTORY_ALERTS", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("PLAYER_AURAS_CHANGED", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("PLAYER_TARGET_CHANGED", "ACTIONBAR_UPDATE_USABLE") - self:RegisterEvent("UNIT_INVENTORY_CHANGED") - self:RegisterEvent("CRAFT_SHOW") - self:RegisterEvent("CRAFT_CLOSE", "CRAFT_SHOW") - self:RegisterEvent("TRADE_SKILL_SHOW", "CRAFT_SHOW") - self:RegisterEvent("TRADE_SKILL_CLOSE", "CRAFT_SHOW") - self:RegisterEvent("PLAYER_ENTER_COMBAT") - self:RegisterEvent("PLAYER_LEAVE_COMBAT") - self:RegisterEvent("START_AUTOREPEAT_SPELL") - self:RegisterEvent("STOP_AUTOREPEAT_SPELL") - self.actionEventsRegistered = true - end - elseif self.actionEventsRegistered then - self:UnregisterEvent("ACTIONBAR_UPDATE_STATE") - self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE") - self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN") - self:UnregisterEvent("UPDATE_INVENTORY_ALERTS") - self:UnregisterEvent("PLAYER_AURAS_CHANGED") - self:UnregisterEvent("PLAYER_TARGET_CHANGED") - self:UnregisterEvent("UNIT_INVENTORY_CHANGED") - self:UnregisterEvent("CRAFT_SHOW") - self:UnregisterEvent("CRAFT_CLOSE") - self:UnregisterEvent("TRADE_SKILL_SHOW") - self:UnregisterEvent("TRADE_SKILL_CLOSE") - self:UnregisterEvent("PLAYER_ENTER_COMBAT") - self:UnregisterEvent("PLAYER_LEAVE_COMBAT") - self:UnregisterEvent("START_AUTOREPEAT_SPELL") - self:UnregisterEvent("STOP_AUTOREPEAT_SPELL") - self.actionEventsRegistered = false - end -end -
--- a/classes/ReAction_ColorScheme.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ --- ReAction.IColorScheme is an interface to describe color schemes for hotkey labels and --- icon/border colorization, depending on the current state. --- - -local AceOO = AceLibrary("AceOO-2.0") - -ReAction.IColorScheme = AceOO.Interface { - GetHotkeyColor = "function", -- r,g,b,a = GetHotkeyColor( isUsable, notEnoughMana, outOfRange, [bindingText] ) - GetIconColor = "function", -- r,g,b,a = GetIconColor( isUsable, notEnoughMana, outOfRange ) - GetBorderColor = "function", -- r,g,b,a = GetBorderColor( isUsable, notEnoughMana, outOfRange ) -} - - - --- ReAction.DefaultColorScheme is a Mixin implementation of ReAction.IColorScheme which --- supports the standard Blizzard colorization plus optional hotkey modifier-driven colorization --- and colorizing icons red (in addition to hotkeys) when out of range. --- --- DefaultColorScheme makes use of self.config as follows: --- --- self.config = { --- keyBindColorCode = true/false, -- color-code keybindings based on modifier key --- } - - -ReAction.DefaultColorScheme = AceOO.Mixin { - "GetHotkeyColor", - "GetModifiedHotkeyColor", -- returns the default modified color (if configured) - "GetIconColor", - "GetBorderColor" -} - - --- private variables -local hotKeyDefaultColor = { r=1.00, g=1.00, b=1.00, a=1.00 } -- white -local hotKeyDisabledColor = { r=0.60, g=0.60, b=0.60, a=1.00 } -- 60% gray -local hotKeyOutOfRangeColor = { r=1.00, g=0.20, b=0.20, a=1.00 } -- red - -local actionUsableColor = { r=1.00, g=1.00, b=1.00, a=1.00 } -- white -local actionNotUsableColor = { r=0.40, g=0.40, b=0.40, a=1.00 } -- 40% gray -local actionNotEnoughManaColor = { r=0.20, g=0.20, b=0.70, a=1.00 } -- medium blue -local actionOutOfRangeColor = { r=1.00, g=0.20, b=0.20, a=1.00 } -- red - -local hotKeyModifierColors = { - S = { r=0.60, g=0.60, b=1.00, a=1.00 }, -- shift (blue) - C = { r=1.00, g=0.82, b=0.00, a=1.00 }, -- ctrl (gold) - A = { r=0.10, g=1.00, b=0.10, a=1.00 }, -- alt (green) - M = { r=0.90, g=0.30, b=1.00, a=1.00 }, -- mouse (purple) -} - --- build list of modifier keys (as a string) from table above -local hotKeyModifiers = "" -for k, _ in pairs(hotKeyModifierColors) do - hotKeyModifiers = hotKeyModifiers..k -end - --- private functions --- extract and return color fields from a table, to be fed into SetVertexColor()/SetTextColor() -local function tcolor(c) - return c.r, c.g, c.b, c.a -end - - - --- mixin methods - -local RADCS = ReAction.DefaultColorScheme - -function RADCS:GetHotkeyColor( isUsable, notEnoughMana, outOfRange, bindingTxt ) - if isUsable or notEnoughMana then - return tcolor(self:GetModifiedHotkeyColor(bindingTxt)) - elseif outOfRange then - return tcolor(hotKeyOutOfRangeColor) - else - return tcolor(hotKeyDisabledColor) - end -end - -function RADCS:GetModifiedHotkeyColor(txt) - local c = hotKeyDefaultColor - if txt and self.config.keyBindColorCode then - local modKey = string.match( txt or "", "(["..hotKeyModifiers.."])%-") - c = modKey and hotKeyModifierColors[modKey] or c - end - return c -end - -function RADCS:GetIconColor( isUsable, notEnoughMana, outOfRange ) - if isUsable then - return tcolor(actionUsableColor) - elseif notEnoughMana then - return tcolor(actionNotEnoughManaColor) - elseif outOfRange then - return tcolor(actionOutOfRangeColor) - else - return tcolor(actionNotUsableColor) - end -end - -function RADCS:GetBorderColor( isUsable, notEnoughMana, outOfRange ) - if isUsable or notEnoughMana or outOfRange then - return tcolor(actionUsableColor) - else - return tcolor(actionNotUsableColor) - end -end -
--- a/classes/ReAction_PetActionDisplay.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,325 +0,0 @@ --- The ReAction.PetActionDisplay mixin defines 'regular' action button display functionality --- and is an implementation of the ReAction.IDisplay and ReAction.ActionType.IDisplay interfaces. --- --- This Mixin assumes that it has been mixed in with a ReAction-derived class which implements --- the ReAction.IActionType and ReAction.IColorScheme interfaces. --- --- This mixin uses properties of self.config to define display elements: --- --- self.config = { --- keyBindLoc = "POSITION", -- keybind anchor location --- showKeyBind = true/false, -- show keybind labels --- showGrid = true/false, -- always show empty buttons --- } --- - -local AceOO = AceLibrary("AceOO-2.0") - -ReAction.PetActionDisplay = AceOO.Mixin { - -- ReAction.IDisplay interface - "SetupDisplay", - "UpdateDisplay", - "TempShow", - "GetActionFrame", - "GetBaseButtonSize", - "DisplayID", - "DisplayHotkey", - - -- ReAction.PetActionType.IDisplay interface - "DisplayAutoCast", - "DisplayAutoCastable", - "DisplayInUse", - "DisplayUsable", - "DisplayIcon", - "DisplayCooldown", - - -- Event handlers - "PreClick", - "PostClick", - "OnDragStart", - "OnReceiveDrag", - "OnEnter", - "OnLeave", - - -- internal functions - "ApplyLayout", - "ApplyStyle", - "DisplayVisibility", -} - -local RAPAD = ReAction.PetActionDisplay - - --- private constants -local _G = getfenv(0) - -local actionIDColor = { r=1.00, g=0.82, b=0.00, a=1.00 } -- gold - - --- private functions --- extract and return color fields from a table, to be fed into SetVertexColor()/SetTextColor() -local function tcolor(c) - return c.r, c.g, c.b, c.a -end - - ------------------------------------ --- Interface Implementation Methods ------------------------------------ -function RAPAD:SetupDisplay( name ) - -- create the button widget - local b = CreateFrame("CheckButton", name, nil, "ActionButtonTemplate, SecureActionButtonTemplate") - b:EnableMouse() - b:RegisterForDrag("LeftButton", "RightButton") - b:RegisterForClicks("AnyUp") - b:SetScript("PreClick", function(arg1) self:PreClick(arg1) end) - b:SetScript("PostClick", function(arg1) self:PostClick(arg1) end) - b:SetScript("OnDragStart", function(arg1) self:OnDragStart(arg1) end) - b:SetScript("OnReceiveDrag", function() self:OnReceiveDrag() end) - b:SetScript("OnEnter", function() self:OnEnter() end) - b:SetScript("OnLeave", function() self:OnLeave() end) - - - b:SetWidth(30) - b:SetHeight(30) - - local tx = b:GetNormalTexture() - tx:ClearAllPoints() - tx:SetWidth(54) - tx:SetHeight(54) - tx:SetPoint("CENTER",0,-1) - - local autoCastable = b:CreateTexture(nil, "OVERLAY") - autoCastable:SetTexture("Interface\\Buttons\\UI-AutoCastableOverlay") - autoCastable:SetWidth(58) - autoCastable:SetHeight(58) - autoCastable:SetPoint("CENTER") - autoCastable:Hide() - - local autoCast = CreateFrame("Model",nil,b) - autoCast:SetModel("Interface\\Buttons\\UI-AutoCastButton.mdx") - autoCast:SetScale(1.2) - autoCast:SetAllPoints() - autoCast:SetSequence(0) - autoCast:SetSequenceTime(0,0) - autoCast:SetFrameStrata("HIGH") -- Otherwise it won't appear on top of the icon for some reason - autoCast:Hide() - - - local cd = _G[name.."Cooldown"] - cd:SetScale(1); - cd:ClearAllPoints(); - cd:SetWidth(33); - cd:SetHeight(33); - cd:SetPoint("CENTER", -2, -1); - - -- store references to the various sub-frames of ActionButtonTemplate so we don't have to look it up all the time - self.frames = { - button = b, - autoCastable = autoCastable, --_G[name.."AutoCastable"], - autoCast = autoCast, --_G[name.."AutoCast"], - hotkey = _G[name.."HotKey"], - cooldown = cd, - icon = _G[name.."Icon"], - normalTexture = tx, --_G[name.."NormalTexture2"], - actionID = nil, -- defer creating actionID font string until it's actually requested - } - - self.tmpShow_ = 0 -end - -function RAPAD:UpdateDisplay() - self:ApplyLayout() - self:ApplyStyle() - self:DisplayVisibility() - -- refresh the action ID display - if ReAction.showIDs_ then - self:DisplayID(true) - end -end - -function RAPAD:TempShow( visible ) - visible = visible and true or false -- force data integrity - self.showTmp_ = max(0, (self.showTmp_ or 0) + (visible and 1 or -1)) - self:DisplayVisibility() -end - -function RAPAD:GetActionFrame() - return self.frames.button -end - -function RAPAD:GetBaseButtonSize() - return 30 -end - -function RAPAD:DisplayID( show ) - local f = self.frames.actionID - if show then - if not f then - -- create the actionID label - f = self.frames.button:CreateFontString(nil,"ARTWORK","NumberFontNormalSmall") - f:SetPoint("BOTTOMLEFT") - f:SetTextColor( tcolor(actionIDColor) ) - self.frames.actionID = f - end - f:SetText(tostring(self:GetID())) - f:Show() - elseif f then - f:Hide() - end -end - -function RAPAD:DisplayHotkey(txt,button) - if button == nil or button == "LeftButton" then - -- only left-button hotkeys supported - self.frames.hotkey:SetText(string.upper(txt or "")) - end -end - -function RAPAD:DisplayInUse( inUse ) - self.frames.button:SetChecked( inUse and 1 or 0 ) -end - -function RAPAD:DisplayUsable( usable ) - SetDesaturation(self.frames.icon, (not usable) and 1 or nil) -- argument is backward - self.frames.hotkey:SetTextColor(self:GetHotkeyColor(usable, false, false, self.frames.hotkey:GetText()) ) -end - -function RAPAD:DisplayAutoCast( show ) - if show then - self.frames.autoCast:Show() - else - self.frames.autoCast:Hide() - end -end - -function RAPAD:DisplayAutoCastable( show ) - if show then - self.frames.autoCastable:Show() - else - self.frames.autoCastable:Hide() - end -end - -function RAPAD:DisplayIcon( texture ) - local f = self.frames.button - local icon = self.frames.icon - if texture then - icon:SetTexture(texture) - icon:Show() - f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") - else - f:SetScript("OnUpdate",nil) - icon:Hide() - f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") - end - self:DisplayVisibility() -end - -function RAPAD:DisplayCooldown( start, duration, enable ) - CooldownFrame_SetTimer(self.frames.cooldown, start, duration, enable) -end - - - - - - ----------------------- --- Event Handlers ----------------------- -function RAPAD:PreClick() - -- not sure why we have to do this - self.frames.button:SetChecked(0) -end - -function RAPAD:PostClick() - self:UpdateAction() -end - -function RAPAD:OnDragStart() - if LOCK_ACTIONBAR ~= "1" or IsShiftKeyDown() then - self:PickupAction() - end -end - -function RAPAD:OnReceiveDrag() - self:PlaceAction() -end - -function RAPAD:OnEnter() - self:SetTooltip() -- from ReAction base class -end - -function RAPAD:OnLeave() - self:ClearTooltip() -- from ReAction base class -end - - - ----------------------- --- Internal methods ----------------------- - -local function placeLabel( label, anchor ) - local top = string.match(anchor,"TOP") - local bottom = string.match(anchor, "BOTTOM") - label:ClearAllPoints() - label:SetWidth(40) - label:SetPoint(top or bottom,0,top and 2 or -2) - local j - if string.match(anchor,"LEFT") then - j = "LEFT" - elseif string.match(anchor,"RIGHT") then - j = "RIGHT" - else - j = "CENTER" - end - label:SetJustifyH(j) -end - - -function RAPAD:ApplyLayout() - local f = self.frames - - if self.config.keyBindLoc then - placeLabel(f.hotkey, self.config.keyBindLoc) - end - - if self.config.showKeyBind then - f.hotkey:Show() - else - f.hotkey:Hide() - end - - if self.config.showBorder then - f.normalTexture:SetAlpha(1) - else - f.normalTexture:SetAlpha(0) - end -end - -function RAPAD:ApplyStyle() - -end - -function RAPAD:DisplayVisibility() - local b = self.frames.button - - -- can't hide/show in combat - if not InCombatLockdown() then - if b:GetAttribute("statehidden") then - b:Hide() - elseif not self:IsActionEmpty() then - b:GetNormalTexture():SetAlpha(1.0) - b:Show() - elseif self.showTmp_ and self.showTmp_ > 0 or self.config.showGrid then - b:GetNormalTexture():SetAlpha(0.5) - self.frames.cooldown:Hide() - b:Show() - else - b:Hide() - end - end -end -
--- a/classes/ReAction_PetActionType.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +0,0 @@ --- The ReAction.PetActionType mixin defines Pet action button functionality --- and is an implementation of the ReAction.IActionType interface. --- --- The Mixin assumes that it is being mixed in with a ReAction-derived class --- which implements the ReAction.IDisplay and ReAction.PetActionType.IDisplay interfaces. - -local AceOO = AceLibrary("AceOO-2.0") - -ReAction.PetActionType = AceOO.Mixin { - -- ReAction.IDisplay interface - "SetID", - "GetID", - "SetupAction", - "UpdateAction", - "PickupAction", - "PlaceAction", - "IsActionEmpty", - "UpdateTooltip", - - -- Event handlers - "PLAYER_ENTERING_WORLD", - "PLAYER_CONTROL_LOST", - "PLAYER_CONTROL_GAINED", - "PLAYER_FARSIGHT_FOCUS_CHANGED", - "UNIT_PET", - "UNIT_FLAGS", - "UNIT_AURA", - "PET_BAR_UPDATE", - "PET_BAR_UPDATE_COOLDOWN", - "PET_BAR_SHOWGRID", - "PET_BAR_HIDEGRID", - - -- Internal functions - "UpdateCooldown", -} - -local RAPAT = ReAction.PetActionType - --- Required display elements -RAPAT.IDisplay = AceOO.Interface { - DisplayAutoCast = "function", -- DisplayAutoCast(bool) - DisplayAutoCastable = "function", -- DisplayAutoCastable(bool) - DisplayIcon = "function", -- DisplayIcon(texture), Display the icon texture (nil for empty slot) - DisplayCooldown = "function", -- DisplayCooldown(start, duration, enable), display cooldown timer - DisplayInUse = "function", -- DisplayInUse(bool), display whether the action is in use - DisplayUsable = "function", -- DisplayUsable(bool), display whether the action can be used now -} - - --- private constants -local actionIDColor = { r=1.00, g=0.82, b=0.00, a=1.00 } -- gold - --- private functions --- extract and return color fields from a table, to be fed into SetVertexColor()/SetTextColor() -local function tcolor(c) - return c.r, c.g, c.b, c.a -end - ---------------------------------------- --- ReAction.IActionType interface implementation ---------------------------------------- -function RAPAT:SetID( id ) -- paging not supported - id = tonumber(id) -- force data integrity - if id then - local f = self:GetActionFrame() - f:SetAttribute("action",id) - -- the following is the goofy hack to work around Blizzard not exporting the pet functions securely - f:SetAttribute("clickbutton2",getglobal("PetActionButton"..id)) - end -end - -function RAPAT:GetID() - return SecureButton_GetModifiedAttribute(self:GetActionFrame(), "action", button) -end - -function RAPAT:SetupAction() - local b = self:GetActionFrame() - -- Blizzard didn't support TogglePetAutocast functionality in - -- SecureButton_OnClick(), so we have to spoof it - -- by delegating right-clicks to the hidden default action buttons - b:SetAttribute("type", "pet") - b:SetAttribute("type2", "click") - - -- shift-clicking to drag locked buttons off - b:SetAttribute("checkselfcast", true) - b:SetAttribute("useparent-unit", true) - - self:RegisterEvent("PLAYER_ENTERING_WORLD") - self:RegisterEvent("PLAYER_CONTROL_LOST"); - self:RegisterEvent("PLAYER_CONTROL_GAINED"); - self:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED"); - self:RegisterEvent("UNIT_PET"); - self:RegisterEvent("UNIT_FLAGS"); - self:RegisterEvent("UNIT_AURA"); - self:RegisterEvent("PET_BAR_UPDATE"); - self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN"); - self:RegisterEvent("PET_BAR_SHOWGRID"); - self:RegisterEvent("PET_BAR_HIDEGRID"); - - self:UpdateAction() -end - -function RAPAT:UpdateAction() - local id = self:GetID() - if id then - local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id); - self:DisplayIcon( isToken and getglobal(texture) or texture ) - self:DisplayInUse( isActive ) - self:DisplayAutoCastable( autoCastAllowed ) - self:DisplayAutoCast( autoCastEnabled ) - self:DisplayCooldown( GetPetActionCooldown(id) ) - self:DisplayUsable(GetPetActionsUsable()) - -- If it's a 'token' save away the tooltip name for updateTooltip - self.isToken = isToken - if isToken then - self.tooltipName = getglobal(name) - self.tooltipSubtext = subtext - end - end -end - -function RAPAT:PickupAction() - PickupPetAction(self:GetID()) - self:UpdateAction() -end - -function RAPAT:PlaceAction() - if not InCombatLockdown() then - PlacePetAction(self:GetID()) - end - self:UpdateAction() -end - -function RAPAT:IsActionEmpty() - local id = self:GetID() - return not(id and GetPetActionInfo(id)) -end - -function RAPAT:UpdateTooltip() - local id = self:GetID() - if GameTooltip:IsOwned(self:GetActionFrame()) and id then - if self.isToken then - GameTooltip:SetText(self.tooltipName, 1.0, 1.0, 1.0) - if ( self.tooltipSubtext ) then - GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5); - end - GameTooltip:Show(); - else - if GameTooltip:SetPetAction(id) then - self.tooltipTime = TOOLTIP_UPDATE_TIME - end - end - else - self.tooltipTime = nil - end -end - - ------------------------------ --- Event Handling ------------------------------ -function RAPAT:PLAYER_ENTERING_WORLD() - self:UpdateAction() -end - -function RAPAT:PLAYER_CONTROL_LOST() - self:UpdateAction() -end - -function RAPAT:PLAYER_CONTROL_GAINED() - self:UpdateAction() -end - -function RAPAT:PLAYER_FARSIGHT_FOCUS_CHANGED() - self:UpdateAction() -end - -function RAPAT:UNIT_PET(unit) - if unit == "player" then - self:UpdateAction() - end -end - -function RAPAT:UNIT_FLAGS(unit) - if unit == "pet" then - self:UpdateAction() - end -end - -function RAPAT:UNIT_AURA(unit) - if unit == "pet" then - self:UpdateAction() - end -end - -function RAPAT:PET_BAR_UPDATE() - self:UpdateAction() -end - -function RAPAT:PET_BAR_UPDATE_COOLDOWN() - self:UpdateCooldown() -end - -function RAPAT:PET_BAR_SHOWGRID() - self:TempShow(true) -end - -function RAPAT:PET_BAR_HIDEGRID() - self:TempShow(false) -end - - -------------------------------------- --- Internal functions -------------------------------------- -function RAPAT:UpdateCooldown() - local id = self:GetID() - if id then - self:DisplayCooldown( GetPetActionCooldown(id) ) - end -end
--- a/classes/ReBar.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,822 +0,0 @@ --- private constants -local anchoredLabelColor = { r = 1.0, g = 0.82, b = 0.0 } -local nonAnchoredLabelColor = { r = 1.0, g = 1.0, b = 1.0 } - -local DRAG_UPDATE_RATE = 0.125 -- cap at 8 Hz - -local nStancePages = { - WARRIOR = 3, - ROGUE = 0, - HUNTER = 0, - DRUID = 3, -- updated to 4 if talented - PALADIN = 0, - SHAMAN = 0, -- As far as I know, ghost wolf is not a proper shapeshift form, it's just a buff - MAGE = 0, - PRIEST = 0, -- updated to 1 if talented - WARLOCK = 0, -} - -local stanceMaps = { - WARRIOR = { - -- note: warriors are never in shapeshift form 0. - [1] = "*:1", -- battle stance. All states go to state (page) 1. - [2] = "*:2", -- defensive stance. All states go to state (page) 2. - [3] = "*:3", -- berserker stance. All states go to state (page) 3. - }, - ROGUE = {}, - HUNTER = {}, - DRUID = { - [0] = "*:1", -- humanoid form. All states go to state (page) 1. - [1] = "*:2", -- bear/dire bear form. All states go to state (page) 2. - [2] = "*:1", -- aquatic form. All states to go state (page) 1 (same as humanoid) - [3] = "*:3", -- cat form. All states go to state (page) 3 - [4] = "*:1", -- travel form. All states go to state (page) 1 (same as humanoid) - [5] = "*:4", -- oomkin/tree form [talent only]. All states go to state (page) 4 - [6] = "*:1", -- flight form. All states go to state (page) 1 (same as humanoid) (??? How does this work with oomkin/tree?) - }, - PALADIN = {}, - SHAMAN = {}, - MAGE = {}, - PRIEST = { - [0] = "*:1", -- normal form. All states go to page 1. - [1] = "*:2", -- shadowform (talent only). All states go to page 2. - }, - WARLOCK = {}, -} - -local stealthMaps = { - WARRIOR = "", - ROGUE = "1:2", -- go to page 2 for rogues - HUNTER = "", - DRUID = "3:5", -- we'll replace with 1:2 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree - PALADIN = "", - SHAMAN = "", - MAGE = "", - PRIEST = "", -} - -local unstealthMaps = { - WARRIOR = "", - ROGUE = "2:1", -- go to page 1 for rogues - HUNTER = "", - DRUID = "5:3", -- we'll replace with 2:1 if stance mapping is not enabled, and page 5 with 6 if oomkin/tree - PALADIN = "", - SHAMAN = "", - MAGE = "", - PRIEST = "", -} - --- Immediately fix if a druid with oomkin or tree (note: can't have both) -local _, playerClass = UnitClass("player") -if playerClass == "DRUID" and GetNumShapeshiftForms() > 4 then - nStancePages.DRUID = 4 - stanceMaps.DRUID[5] = "*:4" - stealthMaps.DRUID = "3:6" - unstealthMaps.DRUID ="6:3" -end - --- Immediately fix if a priest with shadowform -if playerClass == "PRIEST" and GetNumShapeshiftForms() > 1 then - nStancePages.PRIEST = 2 -end - -local AceOO = AceLibrary("AceOO-2.0") -local ReAnchor = AceLibrary("ReAnchor-1.0") - --- ReBar is an Ace 2 class prototype object. -ReBar = AceOO.Class("AceEvent-2.0", ReAnchor, ReAnchor.IAnchorable) - - ----------------------- --- Static members ----------------------- --- IButtonClass is an interface required of any button class type (not the class objects themselves) to be used with the bar -ReBar.IButtonClass = AceOO.Interface { - Acquire = "function", -- btn = Acquire(config, barIdx, pages, buttonsPerPage) - -- analogous to new(), this should re-use recycled frames for memory efficiency - Release = "function", -- Release(btn) should hide and dispose of the button (and recycle it) -} - --- IButton is an interface required of any button objects to be used with the bar -ReBar.IButton = AceOO.Interface { - GetActionFrame = "function", -- obtains the action frame, presumably inherited from SecureActionButtonTemplate or similar. - BarLocked = "function", -- BarLocked() called when the bar is locked. - BarUnlocked = "function", -- BarUnlocked() called when the bar is unlocked. - PlaceButton = "function", -- PlaceButton(parent, anchorPoint, offsetX, offsetY, squareSz), one-stop position and size setting - SetPages = "function", -- SetPages(n): sets number of pages for multi-paging. Can error if paging not supported. -} - --- wrap UIParent and WorldFrame in objects which implement the ReAnchor.IAnchorable interface -local UIParentPlaceable = { - GetFrame = function() return UIParent end, - GetAnchorage = function() return ReAnchor.anchorInside end, -} - -local WorldFramePlaceable = { - GetFrame = function() return WorldFrame end, - GetAnchorage = function() return ReAnchor.anchorInside end, -} - -ReBar.anchorTargets = { - UIParentPlaceable, - WorldFramePlaceable -} - -ReBar.UIParentAnchorTarget = { - UIParentPlaceable -} - - - - - - --------------------- --- instance methods --------------------- --- construction and destruction -function ReBar.prototype:init( config, id ) - ReBar.super.prototype.init(self) - - self.config = config - self.barID = id - self.buttons = { } - self.locked = true - - self.buttonClass = config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) - if not AceOO.inherits(self.buttonClass, ReBar.IButton) then - error("ReBar: Supplied Button type does not meet required interface.") - end - - - -- create the bar and control widgets - local name = "ReBar"..id - self.barFrame = CreateFrame("Frame", name, config.parent and getglobal(config.parent) or UIParent, "ReBarTemplate") - self.controlFrame = getglobal(self.barFrame:GetName().."Controls") - self.controlFrame.reBar = self - self.barFrame:SetClampedToScreen(true) - - -- get references to sub-frames - self.labelString = getglobal(name.."ControlsLabelString") - self.upArrow = getglobal(name.."PageUp") - self.downArrow = getglobal(name.."PageDown") - self.pageNum = getglobal(name.."PageNumber") - - -- set the text label on the control widget - self.labelString:SetText(id) - - -- initial stateheader state - self.barFrame.StateChanged = function() self:StateChanged() end - self.barFrame:SetAttribute("state",config.pages and config.pages.currentPage or 1) -- initial state - - -- initialize the bar layout - self:ApplySize() - self:ApplyAnchor() - self:AcquireButtons() - self:LayoutButtons() - self:ApplyVisibility() - - if self.config.pages then - self:SetPages(self.config.pages.n) - self:ApplyAutoStanceSwitch() - self:ApplyAutoStealthSwitch() - self:RefreshPageControls() - end - - -- add bar to anchorTargets list - table.insert(ReBar.anchorTargets, self) -end - -function ReBar.prototype:Destroy() - local f = self.barFrame - - self:HideControls() - f:Hide() - f:ClearAllPoints() - f:SetParent(nil) - f:SetPoint("BOTTOMRIGHT", UIParent, "TOPLEFT", 0, 0) - - while #self.buttons > 0 do - self.buttonClass:Release(table.remove(self.buttons)) - end - - -- remove from anchorTargets table - for idx, b in ipairs(ReBar.anchorTargets) do - if b == self then - table.remove(ReBar.anchorTargets, idx) - break - end - end - - -- remove from globals - local n = f:GetName() - setglobal(n, nil) - setglobal(n.."Control", nil) - setglobal(n.."Controls", nil) - setglobal(n.."ControlsLabelString", nil) - setglobal(n.."PageUp", nil) - setglobal(n.."PageDown", nil) - setglobal(n.."Page", nil) - setglobal(n.."PageNumber", nil) - setglobal(n.."PageNumberLabel", nil) - setglobal(n.."PageNumberLabelText", nil) -end - - - - --- ReAnchor.IAnchorable interface implementation -function ReBar.prototype:GetFrame() - return self.barFrame -end - -function ReBar.prototype:GetAnchorage() - return ReAnchor.anchorOutside -end - - - - --- show/hide the control frame -function ReBar.prototype:ShowControls() - self.locked = false - self.controlFrame:Show() - for _, b in ipairs(self.buttons) do - b:BarUnlocked() - b:DisplayVisibility() - end - self:ApplyVisibility() -end - -function ReBar.prototype:HideControls() - self.locked = true - local b = self.barFrame - if b.isMoving or b.resizing then - b:StopMovingOrSizing() - b:SetScript("OnUpdate",nil) - end - for _, b in ipairs(self.buttons) do - b:BarLocked() - b:DisplayVisibility() - end - self.controlFrame:Hide() - self:ApplyVisibility() -end - -function ReBar.prototype:GetControlFrame() - return self.controlFrame -end - - --- accessors -function ReBar.prototype:GetVisibility() - return self.config.visible -end - -function ReBar.prototype:ToggleVisibility() - self:SetVisibility( not self:GetVisibility() ) -end - -function ReBar.prototype:SetVisibility(v) - self.config.visible = v and true or false -- force data integrity - self:ApplyVisibility() -end - -function ReBar.prototype:GetButtonList() - return self.buttons -end - -function ReBar.prototype:GetGrowLeft() - return self.config.growLeft -end - -function ReBar.prototype:SetGrowLeft(g) - self.config.growLeft = g and true or false - self:LayoutButtons() -end - -function ReBar.prototype:GetGrowUp() - return self.config.growUp -end - -function ReBar.prototype:SetGrowUp(g) - self.config.growUp = g and true or false - self:LayoutButtons() -end - -function ReBar.prototype:GetColumnMajor() - return self.config.columnMajor -end - -function ReBar.prototype:SetColumnMajor(m) - self.config.columnMajor = m and true or false - self:LayoutButtons() -end - - --- paging methods -function ReBar.prototype:IsPagingDisabled() - return not (self.config.pages and self.config.pages.n > 1) -end - -function ReBar.prototype:GetPages() - return self.config.pages and self.config.pages.n or 1 -end - -function ReBar.prototype:SetPages(n) - n = tonumber(n) - if n and n >= 1 then - self.config.pages = self.config.pages or { } - self.config.pages.n = n - for _, btn in pairs(self.buttons) do - btn:SetPages(n) - end - if n > 1 then - local statebutton = "0:page1;" - -- map states 1-n to 'page1'-'pagen' - -- page 0 is the same as page 1. - for i = 1, n do - statebutton = statebutton..i..":page"..i..";" - end - self.barFrame:SetAttribute("statebutton",statebutton) - else - self.barFrame:SetAttribute("statebutton",ATTRIBUTE_NOOP) - end - self.barFrame:SetAttribute("statemap-anchor-next","1-"..n) - self.barFrame:SetAttribute("statemap-anchor-prev",tostring(n).."-1") - self:RefreshPageControls() - end -end - -function ReBar.prototype:GetAutoStanceSwitch() - return self.config.pages and self.config.pages.autoStanceSwitch -end - -function ReBar.prototype:SetAutoStanceSwitch( s ) - if not self.config.pages then - self.config.pages = { n = 1 } - end - self.config.pages.autoStanceSwitch = s and true or false - self:ApplyAutoStanceSwitch() -end - -function ReBar.prototype:ToggleAutoStanceSwitch() - self:SetAutoStanceSwitch( not self:GetAutoStanceSwitch() ) -end - -function ReBar.prototype:ApplyAutoStanceSwitch() - local switch = self:GetAutoStanceSwitch() - if switch then - -- check that the number of pages available is sufficient - local totalPages = nStancePages[playerClass] + (self:GetAutoStealthSwitch() and 1 or 0) - if self:GetPages() < totalPages then - self:SetPages(totalPages) - end - for form, spec in pairs(stanceMaps[playerClass]) do - self.barFrame:SetAttribute("statemap-stance-"..form,spec) - end - -- set initial value - self.barFrame:SetAttribute("state-stance",GetShapeshiftForm(true)) - else - for form, _ in pairs(stanceMaps[playerClass]) do - self.barFrame:SetAttribute("statemap-stance-"..form, ATTRIBUTE_NOOP) - end - end -end - -function ReBar.prototype:GetAutoStealthSwitch() - return self.config.pages and self.config.pages.autoStealthSwitch -end - -function ReBar.prototype:SetAutoStealthSwitch( s ) - if not self.config.pages then - self.config.pages = { n = 1 } - end - self.config.pages.autoStealthSwitch = s and true or false - self:ApplyAutoStealthSwitch() -end - -function ReBar.prototype:ToggleAutoStealthSwitch() - self:SetAutoStealthSwitch( not self:GetAutoStealthSwitch() ) -end - -function ReBar.prototype:ApplyAutoStealthSwitch() - local switch = self:GetAutoStealthSwitch() - if switch then - -- check that the number of pages available is sufficient - local totalPages = (self:GetAutoStanceSwitch() and nStancePages[playerClass] > 0 and nStancePages[playerClass] or 1) + 1 - if self:GetPages() < totalPages then - self:SetPages(totalPages) - end - local s, s2 - if playerClass == "DRUID" and not self:GetAutoStanceSwitch() then - -- change mapping for cat->prowl and prowl->cat to 1:2 and 2:1 since no stance mapping - s = "1:2" - s2 = "2:1" - end - self.barFrame:SetAttribute("statemap-stealth-1",s or stealthMaps[playerClass]) - self.barFrame:SetAttribute("statemap-stealth-0",s2 or unstealthMaps[playerClass]) - -- set initial value - self.barFrame:SetAttribute("state-stealth",IsStealthed() or 0) - else - self.barFrame:SetAttribute("statemap-stealth-1",ATTRIBUTE_NOOP) - self.barFrame:SetAttribute("statemap-stealth-0",ATTRIBUTE_NOOP) - end -end - -function ReBar.prototype:ArePageControlsHidden() - return not ( self.config.pages and self.config.pages.showControls ) -end - -function ReBar.prototype:TogglePageControlsHidden() - if self.config.pages then - self.config.pages.showControls = not self.config.pages.showControls - self:RefreshPageControls() - end -end - -function ReBar.prototype:GetPageControlsLoc() - return self.config.pages and self.config.pages.controlsLoc -end - -function ReBar.prototype:SetPageControlsLoc(loc) - if self.config.pages then - self.config.pages.controlsLoc = loc - self:RefreshPageControls() - end -end - -function ReBar.prototype:RefreshPageControls() - local b = self.barFrame; - local upArrow = self.upArrow - local downArrow = self.downArrow - local pageNum = self.pageNum - - if self:GetPages() > 1 and self.config.pages.showControls then - local loc = self.config.pages.controlsLoc - - upArrow:SetAttribute("hidestates",nil) - downArrow:SetAttribute("hidestates",nil) - - pageNum:ClearAllPoints() - upArrow:ClearAllPoints() - downArrow:ClearAllPoints() - - local vertical = { 0,0,0,1,1,0,1,1 } - local horizontal = { 0,1,1,1,0,0,1,0 } - local textures = { - upArrow:GetNormalTexture(), - upArrow:GetPushedTexture(), - upArrow:GetDisabledTexture(), - upArrow:GetHighlightTexture(), - downArrow:GetNormalTexture(), - downArrow:GetPushedTexture(), - downArrow:GetDisabledTexture(), - downArrow:GetHighlightTexture(), - } - - local offset = 10 - local mult = (loc == "RIGHT" or loc == "TOP") and 1 or -1 - local pageNumOffset = mult * (self.config.spacing/2 - offset) - local arrowOffset = mult * offset - - if loc == "Blizzard" or loc == nil then - pageNum:SetPoint("LEFT", b, "RIGHT", 28, 0) - upArrow:SetPoint("LEFT", b, "RIGHT", -2, 9) - downArrow:SetPoint("LEFT", b, "RIGHT", -2, -10) - for _, tex in ipairs(textures) do - tex:SetTexCoord(unpack(vertical)) - end - elseif loc == "RIGHT" or loc == "LEFT" then - local relPoint = loc == "RIGHT" and "LEFT" or "RIGHT" - pageNum:SetPoint(relPoint, b, loc, pageNumOffset, 0) - upArrow:SetPoint("BOTTOM",pageNum,"TOP",arrowOffset, -12) - downArrow:SetPoint("TOP",pageNum,"BOTTOM",arrowOffset, 12) - for _, tex in ipairs(textures) do - tex:SetTexCoord(unpack(vertical)) - end - else - pageNum:SetPoint(loc == "BOTTOM" and "TOP" or "BOTTOM", b, loc, 0, pageNumOffset) - upArrow:SetPoint("LEFT",pageNum,"RIGHT",-12,arrowOffset) - downArrow:SetPoint("RIGHT",pageNum,"LEFT",12,arrowOffset) - for _, tex in ipairs(textures) do - tex:SetTexCoord(unpack(horizontal)) - end - end - self:StateChanged() - upArrow:Show() - downArrow:Show() - pageNum:Show() - else - upArrow:SetAttribute("hidestates","1-"..self:GetPages()) - downArrow:SetAttribute("hidestates","1-"..self:GetPages()) - - upArrow:Hide() - downArrow:Hide() - pageNum:Hide() - end -end - -function ReBar.prototype:StateChanged() - local page = self.barFrame:GetAttribute("state") or 1 - getglobal(self.barFrame:GetName().."PageNumberLabelText"):SetText(page) - if self.config.pages then self.config.pages.currentPage = page end -end - - - --- layout methods -function ReBar.prototype:ApplySize() - local buttonSz = self.config.size or 36 - local spacing = self.config.spacing or 4 - local rows = self.config.rows or 1 - local columns = self.config.columns or 12 - local w = buttonSz * columns + spacing * columns - local h = buttonSz * rows + spacing * rows - local f = self.barFrame - - -- + 0.1: avoid issues with UI scaling - f:SetMinResize(buttonSz + spacing + 0.1, buttonSz + spacing + 0.1) - f:SetWidth(w + 0.1) - f:SetHeight(h + 0.1) -end - -function ReBar.prototype:ApplyAnchor() - local a = self.config.anchor - local f = self.barFrame - if a then - f:ClearAllPoints() - f:SetPoint(a.point,getglobal(a.frame),a.relPoint,a.x,a.y) - local color = anchoredLabelColor - if a.frame == "UIParent" or a.frame == "WorldFrame" then - color = nonAnchoredLabelColor - end - self.labelString:SetTextColor(color.r, color.g, color.b) - end -end - -function ReBar.prototype:ApplyVisibility() - local v = self.config.visible or not self.locked - - if v then - self.barFrame:Show() - else - self.barFrame:Hide() - end -end - -function ReBar.prototype:LayoutButtons() - local r = self.config.rows - local c = self.config.columns - local sp = self.config.spacing - local sz = self.config.size - local gSize = sp + sz - local point = (self.config.growUp and "BOTTOM" or "TOP")..(self.config.growLeft and "RIGHT" or "LEFT") - local major = self.config.columnMajor and r or c - - for i, b in ipairs(self.buttons) do - local x = sp/2 + gSize * math.fmod(i-1,major) - local y = sp/2 + gSize * math.floor((i-1)/major) - if self.config.columnMajor then x,y = y,x end - if self.config.growLeft then x = -x end - if not self.config.growUp then y = -y end - b:PlaceButton(self.barFrame, point, x, y, sz) - end -end - -function ReBar.prototype:FlipRowsColumns() - self.config.rows, self.config.columns = self.config.columns, self.config.rows - self.config.columnMajor = not self.config.columnMajor - self:ApplySize() - self:LayoutButtons() -end - -function ReBar.prototype:AcquireButtons() - local n = self.config.rows * self.config.columns - - for i = 1, n do - if self.buttons[i] == nil then - local b = self.buttonClass:Acquire(self.config.btnConfig, i, self.config.pages and self.config.pages.n, n) - if b then - if not AceOO.inherits(b, ReBar.IButton) then - error("ReBar: specified Button class object did not meet required interface") - end - if self.locked == false then - b:BarUnlocked() -- buttons assume they are created in a barlocked state - end - self.buttons[i] = b - self.barFrame:SetAttribute("addchild",b:GetActionFrame()) - end - end - end - - local maxn = table.maxn(self.buttons) - for i = n+1, table.maxn(self.buttons) do - local b = self.buttons[i] - self.buttons[i] = nil - if b then - self.buttonClass:Release(b) - end - end - -end - - -function ReBar.prototype:StoreAnchor(f, p, rp, x, y) - local name = f:GetName() - -- no point if we can't store the name or the offsets are incomplete - if name and x and y then - self.config.anchor = { - frame = name, - point = p, - relPoint = rp or p, - x = x, - y = y - } - end -end - - - -function ReBar.prototype:StickyIndicatorUpdate() - if IsShiftKeyDown() then - local snapRange = self.config.size + self.config.spacing - self:DisplaySnapIndicator(ReBar.anchorTargets, snapRange, 0, 0) - else - self:HideSnapIndicator() - end -end - - --- mouse event handlers (clicking/dragging/resizing the bar) -function ReBar.prototype:BeginDrag() - local f = self.barFrame - f:StartMoving() - f.isMoving = true - self.updateTime = DRAG_UPDATE_RATE - f:SetScript("OnUpdate", function(frame, elapsed) self:StickyIndicatorUpdate(elapsed) end) -end - -function ReBar.prototype:FinishDrag() - local o, p, rp, x, y - local bf = self.barFrame - local snapRange = self.config.size + self.config.spacing - - bf:StopMovingOrSizing() - bf.isMoving = false - - bf:SetScript("OnUpdate",nil) - if IsShiftKeyDown() then - o, p, rp, x, y = self:GetClosestPointSnapped(ReBar.anchorTargets, snapRange, 0, 0) - end - - if o == nil then - o, p, rp, x, y = self:GetClosestVisiblePoint(ReBar.UIParentAnchorTarget, snapRange, 0, 0) - end - - self:HideSnapIndicator() - self:StoreAnchor(o:GetFrame(), p, rp, x, y) - self:ApplyAnchor() -end - -function ReBar.prototype:BeginBarResize( sizingPoint ) - local f = self.barFrame - f:StartSizing(sizingPoint) - f.resizing = true - self.updateTime = DRAG_UPDATE_RATE - f:SetScript("OnUpdate",function(frame, elapsed) self:ReflowButtons(elapsed) end) -end - -function ReBar.prototype:BeginButtonResize( sizingPoint, mouseBtn ) - local f = self.barFrame - f:StartSizing(sizingPoint) - f.resizing = true - local r = self.config.rows - local c = self.config.columns - local s = self.config.spacing - local sz = self.config.size - self.updateTime = DRAG_UPDATE_RATE - if mouseBtn == "LeftButton" then - f:SetMinResize(c*(12 + s) +0.1, r*(12 + s) +0.1) - f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeButtons(elapsed) end) - elseif mouseBtn == "RightButton" then - f:SetMinResize(c*sz+0.1, r*sz+0.1) - f:SetScript("OnUpdate",function(frame, elapsed) self:DragSizeSpacing(elapsed) end) - end -end - -function ReBar.prototype:FinishResize() - local f = self.barFrame - f:StopMovingOrSizing() - f.resizing = false - f:SetScript("OnUpdate",nil) - self:ApplySize() -end - - - - - - - --- utility function to get the height, width, and button size attributes -function ReBar.prototype:GetLayout() - local c = self.config - local f = self.barFrame - return f:GetWidth(), f:GetHeight(), c.size, c.rows, c.columns, c.spacing -end - - --- add and remove buttons dynamically as the bar is resized -function ReBar.prototype:ReflowButtons( elapsed ) - self.updateTime = self.updateTime - elapsed - if self.updateTime <= 0 then - self.updateTime = DRAG_UPDATE_RATE - - local w, h, sz, r, c, sp = self:GetLayout() - - self.config.rows = math.floor( (h+1) / (sz + sp) ) - self.config.columns = math.floor( (w+1) / (sz + sp) ) - - if self.config.rows ~= r or self.config.columns ~= c then - self:AcquireButtons() - self:LayoutButtons() - end - end -end - - --- change the size of buttons as the bar is resized -function ReBar.prototype:DragSizeButtons( elapsed ) - self.updateTime = self.updateTime - elapsed - if self.updateTime <= 0 then - self.updateTime = DRAG_UPDATE_RATE - - local w, h, sz, r, c, sp = self:GetLayout() - - local newSzW = math.floor((w - c*sp)/c) - local newSzH = math.floor((h - r*sp)/r) - - self.config.size = math.max(12, math.min(newSzW, newSzH)) - - if self.config.size ~= sz then - self:LayoutButtons() - self:UpdateResizeTooltip() - end - end -end - - --- change the spacing of buttons as the bar is resized -function ReBar.prototype:DragSizeSpacing( elapsed ) - self.updateTime = self.updateTime - elapsed - if self.updateTime <= 0 then - self.updateTime = DRAG_UPDATE_RATE - - local w, h, sz, r, c, sp = self:GetLayout() - - local newSpW = math.floor((w - c*sz)/c) - local newSpH = math.floor((h - r*sz)/r) - - self.config.spacing = math.max(0, math.min(newSpW, newSpH)) - - if self.config.spacing ~= sp then - self:LayoutButtons() - self:UpdateResizeTooltip() - end - end -end - - --- update the drag tooltip to indicate current sizes -function ReBar.prototype:UpdateResizeTooltip() - GameTooltipTextRight4:SetText(self.config.size) - GameTooltipTextRight5:SetText(self.config.spacing) - GameTooltip:Show() -end - -function ReBar.prototype:ShowTooltip() - GameTooltip:SetOwner(self.barFrame, "ANCHOR_TOPRIGHT") - GameTooltip:AddLine(self.config.btnConfig.subtype.." Bar "..self.barID..(self.config.visible and "" or " (Hidden)")) - GameTooltip:AddLine("Drag to move") - GameTooltip:AddLine("Shift-drag for sticky mode") - GameTooltip:AddLine("Right-click for options") - GameTooltip:Show() -end - -function ReBar.prototype:ShowButtonResizeTooltip(point) - GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) - GameTooltip:AddLine("Drag to resize buttons") - GameTooltip:AddLine("Right-click-drag") - GameTooltip:AddLine("to change spacing") - GameTooltip:AddDoubleLine("Size: ", "0") - GameTooltip:AddDoubleLine("Spacing: ", "0") - self:UpdateResizeTooltip() -end - -function ReBar.prototype:ShowBarResizeTooltip(point) - GameTooltip:SetOwner(self.barFrame, "ANCHOR_"..point) - GameTooltip:AddLine("Drag to add/remove buttons") - GameTooltip:Show() -end -
--- a/classes/ReBar.xml Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,349 +0,0 @@ -<Ui xmlns="http://www.blizzard.com/wow/ui/" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.blizzard.com/wow/ui/..\FrameXML\UI.xsd"> - - - <Frame name="ReBarControlEdgeTemplate" virtual="true"> - <Size> - <AbsDimension x="8" y="8"/> - </Size> - <Layers> - <Layer level="HIGHLIGHT" alphaMode="ADD"> - <Texture> - <Color r="1.0" g="0.82" b="0" a="0.7"/> - </Texture> - </Layer> - </Layers> - <Scripts> - <OnLoad> - this:RegisterForDrag("LeftButton") - </OnLoad> - <OnMouseDown> - this:GetParent().reBar:BeginBarResize(this.sizingPoint) - </OnMouseDown> - <OnMouseUp> - this:GetParent().reBar:FinishResize() - </OnMouseUp> - <OnEnter> - this:GetParent().reBar:ShowBarResizeTooltip(this.sizingPoint) - </OnEnter> - <OnLeave> - GameTooltip:Hide() - </OnLeave> - </Scripts> - </Frame> - - - <Frame name="ReBarControlCornerTemplate" virtual="true"> - <Size> - <AbsDimension x="12" y="12"/> - </Size> - <Layers> - <Layer level="HIGHLIGHT" alphaMode="ADD"> - <Texture> - <Color r="1.0" g="0.82" b="0" a="0.7"/> - </Texture> - </Layer> - </Layers> - <Scripts> - <OnLoad> - this:RegisterForDrag("LeftButton","RightButton") - </OnLoad> - <OnMouseDown> - this:GetParent():GetParent().reBar:BeginButtonResize(this.sizingPoint, arg1) - </OnMouseDown> - <OnMouseUp> - this:GetParent():GetParent().reBar:FinishResize() - </OnMouseUp> - <OnEnter> - this:GetParent():GetParent().reBar:ShowButtonResizeTooltip(this.sizingPoint) - </OnEnter> - <OnLeave> - GameTooltip:Hide() - </OnLeave> - </Scripts> - </Frame> - - - <Button name="ReBarPageArrowTemplate" inherits="SecureAnchorButtonTemplate" virtual="true"> - <Size> - <AbsDimension x="32" y="32"/> - </Size> - <Layers> - <Layer level="BACKGROUND"> - <Color r="1" g="1" b="0" setAllPoints="true"/> - </Layer> - </Layers> - <HitRectInsets> - <AbsInset left="6" right="6" top="7" bottom="7"/> - </HitRectInsets> - </Button> - - - <!-- A ReBar is a container for buttons. The bar container itself is invisible and non-responsive to - mouse input, but when unlocked a normally invisible child control frame becomes visible and - consumes mouse events to move, resize, and set bar options. --> - <Frame name="ReBarTemplate" inherits="SecureStateDriverTemplate" frameStrata="MEDIUM" virtual="true" movable="true" resizable="true"> - <Frames> - <Frame name="$parentControl" setAllPoints="true"> - <!-- this nesting is to ensure the control frame is on top of the buttons, which will - live at this level --> - <Frames> - <!-- name: e.g. $parentControls (with an s) - yes I know, goofy naming structure --> - <Button name="$parents" hidden="true" enableMouse="true" toplevel="true" setAllPoints="true"> - <Anchors> - <Anchor point="TOPLEFT"> - <Offset> - <AbsDimension x="-4" y="4"/> - </Offset> - </Anchor> - <Anchor point="BOTTOMRIGHT"> - <Offset> - <AbsDimension x="4" y="-4"/> - </Offset> - </Anchor> - </Anchors> - <Backdrop edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true"> - <EdgeSize> - <AbsValue val="16"/> - </EdgeSize> - <TileSize> - <AbsValue val="16"/> - </TileSize> - <BackgroundInsets> - <AbsInset left="0" right="0" top="0" bottom="0"/> - </BackgroundInsets> - </Backdrop> - <Layers> - <Layer level="BACKGROUND"> - <Texture> - <!-- offsets so that the highlight layer plays nice with the edge border --> - <Anchors> - <Anchor point="TOPLEFT"> - <Offset> - <AbsDimension x="4" y="-4"/> - </Offset> - </Anchor> - <Anchor point="BOTTOMRIGHT"> - <Offset> - <AbsDimension x="-4" y="4"/> - </Offset> - </Anchor> - </Anchors> - <Color r="0.7" g="0.7" b="1.0" a="0.2"/> - </Texture> - </Layer> - <Layer level="HIGHLIGHT"> - <Texture alphaMode="ADD"> - <Anchors> - <Anchor point="TOPLEFT"> - <Offset> - <AbsDimension x="4" y="-4"/> - </Offset> - </Anchor> - <Anchor point="BOTTOMRIGHT"> - <Offset> - <AbsDimension x="-4" y="4"/> - </Offset> - </Anchor> - </Anchors> - <Color r="0.7" g="0.7" b="1.0" a="0.2"/> - </Texture> - </Layer> - <Layer level="OVERLAY"> - <FontString name="$parentLabelString" inherits="GameFontNormalLarge" justifyH="CENTER" text="(barID)" setAllPoints="true" outline="THICK"> - <Anchors> - <Anchor point="CENTER"/> - </Anchors> - <Shadow> - <Offset> - <AbsDimension x="2" y="-2"/> - </Offset> - <Color r="0" g="0" b="0" a="1"/> - </Shadow> - <Color r="1" g="1" b="1" a="1"/> - </FontString> - </Layer> - </Layers> - <Frames> - <!-- edge drag handles --> - <Frame inherits="ReBarControlEdgeTemplate"> - <Anchors> - <Anchor point="TOPLEFT"/> - <Anchor point="TOPRIGHT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "TOP" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlEdgeTemplate"> - <Anchors> - <Anchor point="TOPLEFT"/> - <Anchor point="BOTTOMLEFT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "LEFT" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlEdgeTemplate"> - <Anchors> - <Anchor point="TOPRIGHT"/> - <Anchor point="BOTTOMRIGHT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "RIGHT" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlEdgeTemplate"> - <Anchors> - <Anchor point="BOTTOMLEFT"/> - <Anchor point="BOTTOMRIGHT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "BOTTOM" </OnLoad> - </Scripts> - </Frame> - - <!-- corner drag handles --> - <Frame setAllPoints="true"> - <!-- nesting to ensure they're on top --> - <Frames> - <Frame inherits="ReBarControlCornerTemplate"> - <Anchors> - <Anchor point="TOPLEFT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "TOPLEFT" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlCornerTemplate"> - <Anchors> - <Anchor point="TOPRIGHT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "TOPRIGHT" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlCornerTemplate"> - <Anchors> - <Anchor point="BOTTOMLEFT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "BOTTOMLEFT" </OnLoad> - </Scripts> - </Frame> - - <Frame inherits="ReBarControlCornerTemplate"> - <Anchors> - <Anchor point="BOTTOMRIGHT"/> - </Anchors> - <Scripts> - <OnLoad> this.sizingPoint = "BOTTOMRIGHT" </OnLoad> - </Scripts> - </Frame> - </Frames> - </Frame> - - </Frames> - <Scripts> - <OnLoad> - this:RegisterForDrag("LeftButton") - this:RegisterForClicks("AnyUp") - </OnLoad> - <OnDragStart> - this.reBar:BeginDrag() - </OnDragStart> - <OnDragStop> - this.reBar:FinishDrag() - </OnDragStop> - <OnEnter> - this.reBar:ShowTooltip() - </OnEnter> - <OnLeave> - GameTooltip:Hide() - </OnLeave> - </Scripts> - </Button> - </Frames> - </Frame> - - <Button name="$parentPageUp" inherits="ReBarPageArrowTemplate" hidden="true"> - <Scripts> - <OnLoad> - this:SetAttribute("anchorchild",this:GetParent()) - this:SetAttribute("childstate","^next") - </OnLoad> - </Scripts> - <NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Up"/> - <PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Down"/> - <DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollUpButton-Disabled"/> - <HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Highlight"/> - </Button> - - <Button name="$parentPageDown" inherits="ReBarPageArrowTemplate" hidden="true"> - <Scripts> - <OnLoad> - this:SetAttribute("anchorchild",this:GetParent()) - this:SetAttribute("childstate","^prev") - </OnLoad> - </Scripts> - <NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Up"/> - <PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Down"/> - <DisabledTexture file="Interface\Buttons\UI-ScrollBar-ScrollDownButton-Disabled"/> - <HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Highlight"/> - </Button> - - <Frame name="$parentPage"> - <Frames> <!-- nesting so it appears on top of arrows --> - <Frame name="$parentNumber"> - <Size> - <AbsDimension x="12" y="12"/> - </Size> - <Layers> - <Layer level="BACKGROUND"> - <Texture> - <Color r="0.2" g="0.2" b="0.2" a="1.0"/> - </Texture> - </Layer> - </Layers> - <Frames> - <Frame name="$parentLabel"> - <Size> - <AbsDimension x="18" y="18"/> - </Size> - <Anchors> - <Anchor point="CENTER"/> - </Anchors> - <Backdrop edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true"> - <EdgeSize> - <AbsValue val="12"/> - </EdgeSize> - <TileSize> - <AbsValue val="12"/> - </TileSize> - </Backdrop> - <Layers> - <Layer level="ARTWORK"> - <FontString name="$parentText" inherits="GameFontNormalSmall" text="0"> - <Anchors> - <Anchor point="CENTER"/> - </Anchors> - <Color r="1.0" g="0.82" b="0"/> - </FontString> - </Layer> - </Layers> - </Frame> - </Frames> - </Frame> - </Frames> - </Frame> - </Frames> - </Frame> - - -</Ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceAddon-2.0/AceAddon-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,1394 @@ +--[[ +Name: AceAddon-2.0 +Revision: $Rev: 46764 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/wiki/AceAddon-2.0 +SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceAddon-2.0 +Description: Base for all Ace addons to inherit from. +Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceAddon-2.0" +local MINOR_VERSION = "$Revision: 46764 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end +end +-- Localization +local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, LICENSE, PRINT_ADDON_INFO, DONATE, DONATE_DESC, HOWTO_DONATE_WINDOWS, HOWTO_DONATE_MAC +if GetLocale() == "deDE" then + STANDBY = "|cffff5050(Standby)|r" -- capitalized + + TITLE = "Titel" + NOTES = "Anmerkung" + VERSION = "Version" + AUTHOR = "Autor" + DATE = "Datum" + CATEGORY = "Kategorie" + EMAIL = "E-Mail" + WEBSITE = "Webseite" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "Über" + PRINT_ADDON_INFO = "Gibt Addondaten aus" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Aktionsleisten", + ["Auction"] = "Auktion", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", + ["Buffs"] = "Stärkungszauber", + ["Chat/Communication"] = "Chat/Kommunikation", + ["Druid"] = "Druide", + ["Hunter"] = "Jäger", + ["Mage"] = "Magier", + ["Paladin"] = "Paladin", + ["Priest"] = "Priester", + ["Rogue"] = "Schurke", + ["Shaman"] = "Schamane", + ["Warlock"] = "Hexenmeister", + ["Warrior"] = "Krieger", + ["Healer"] = "Heiler", + ["Tank"] = "Tank", + ["Caster"] = "Zauberer", + ["Combat"] = "Kampf", + ["Compilations"] = "Zusammenstellungen", + ["Data Export"] = "Datenexport", + ["Development Tools"] = "Entwicklungs Tools", + ["Guild"] = "Gilde", + ["Frame Modification"] = "Frame Veränderungen", + ["Interface Enhancements"] = "Interface Verbesserungen", + ["Inventory"] = "Inventar", + ["Library"] = "Bibliotheken", + ["Map"] = "Karte", + ["Mail"] = "Post", + ["Miscellaneous"] = "Diverses", + ["Quest"] = "Quest", + ["Raid"] = "Schlachtzug", + ["Tradeskill"] = "Beruf", + ["UnitFrame"] = "Einheiten-Fenster", + } +elseif GetLocale() == "frFR" then + STANDBY = "|cffff5050(attente)|r" + + TITLE = "Titre" + NOTES = "Notes" + VERSION = "Version" + AUTHOR = "Auteur" + DATE = "Date" + CATEGORY = "Catégorie" + EMAIL = "E-mail" + WEBSITE = "Site web" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "A propos" + PRINT_ADDON_INFO = "Afficher les informations sur l'addon" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Barres d'action", + ["Auction"] = "Hôtel des ventes", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Communication", + ["Druid"] = "Druide", + ["Hunter"] = "Chasseur", + ["Mage"] = "Mage", + ["Paladin"] = "Paladin", + ["Priest"] = "Prêtre", + ["Rogue"] = "Voleur", + ["Shaman"] = "Chaman", + ["Warlock"] = "Démoniste", + ["Warrior"] = "Guerrier", + ["Healer"] = "Soigneur", + ["Tank"] = "Tank", + ["Caster"] = "Casteur", + ["Combat"] = "Combat", + ["Compilations"] = "Compilations", + ["Data Export"] = "Exportation de données", + ["Development Tools"] = "Outils de développement", + ["Guild"] = "Guilde", + ["Frame Modification"] = "Modification des fenêtres", + ["Interface Enhancements"] = "Améliorations de l'interface", + ["Inventory"] = "Inventaire", + ["Library"] = "Bibliothèques", + ["Map"] = "Carte", + ["Mail"] = "Courrier", + ["Miscellaneous"] = "Divers", + ["Quest"] = "Quêtes", + ["Raid"] = "Raid", + ["Tradeskill"] = "Métiers", + ["UnitFrame"] = "Fenêtres d'unité", + } +elseif GetLocale() == "koKR" then + STANDBY = "|cffff5050(사용가능)|r" + + TITLE = "제목" + NOTES = "노트" + VERSION = "버전" + AUTHOR = "저작자" + DATE = "날짜" + CATEGORY = "분류" + EMAIL = "전자 우편" + WEBSITE = "웹 사이트" + CREDITS = "공로자" + LICENSE = "라이센스" + + ABOUT = "정보" + PRINT_ADDON_INFO = "애드온에 대한 정보를 출력합니다." + DONATE = "기부" + DONATE_DESC = "이 애드온의 저작자에게 기부를 합니다." + HOWTO_DONATE_WINDOWS = "Ctrl-A를 눌려 링크를 선택후, Ctrl-C로 복사합니다. Alt-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." + HOWTO_DONATE_MAC = "Cmd-A를 눌려 링크를 선택후, Cmd-C로 복사합니다. Cmd-Tab 눌려 게임으로 부터 나간후 웹 브라우저를 엽니다. 복사된 링크를 주소 창에 붙여넣기 합니다." + + CATEGORIES = { + ["Action Bars"] = "액션바", + ["Auction"] = "경매", + ["Audio"] = "음향", + ["Battlegrounds/PvP"] = "전장/PvP", + ["Buffs"] = "버프", + ["Chat/Communication"] = "대화/의사소통", + ["Druid"] = "드루이드", + ["Hunter"] = "사냥꾼", + ["Mage"] = "마법사", + ["Paladin"] = "성기사", + ["Priest"] = "사제", + ["Rogue"] = "도적", + ["Shaman"] = "주술사", + ["Warlock"] = "흑마법사", + ["Warrior"] = "전사", + ["Healer"] = "힐러", + ["Tank"] = "탱커", + ["Caster"] = "캐스터", + ["Combat"] = "전투", + ["Compilations"] = "복합", + ["Data Export"] = "자료 출력", + ["Development Tools"] = "개발 도구", + ["Guild"] = "길드", + ["Frame Modification"] = "구조 변경", + ["Interface Enhancements"] = "인터페이스 강화", + ["Inventory"] = "인벤토리", + ["Library"] = "라이브러리", + ["Map"] = "지도", + ["Mail"] = "우편", + ["Miscellaneous"] = "기타", + ["Quest"] = "퀘스트", + ["Raid"] = "공격대", + ["Tradeskill"] = "전문기술", + ["UnitFrame"] = "유닛 프레임", + } +elseif GetLocale() == "zhTW" then + STANDBY = "|cffff5050(待命)|r" + + TITLE = "標題" + NOTES = "註記" + VERSION = "版本" + AUTHOR = "作者" + DATE = "日期" + CATEGORY = "類別" + EMAIL = "電子郵件" + WEBSITE = "網站" + CREDITS = "特別感謝" + LICENSE = "版權" + + ABOUT = "關於" + PRINT_ADDON_INFO = "顯示插件資訊。" + DONATE = "捐贈" + DONATE_DESC = "捐贈金錢給插件作者。" + HOWTO_DONATE_WINDOWS = "請按Ctrl-A選擇網站連結,Ctrl-C複製網址,Alt-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" + HOWTO_DONATE_MAC = "請按Cmd-A選擇網站連結,Cmd-C複製網址,Cmd-Tab切換到電腦桌面,打開瀏覽器,在網址列貼上網址。" + + CATEGORIES = { + ["Action Bars"] = "動作條", + ["Auction"] = "拍賣", + ["Audio"] = "音效", + ["Battlegrounds/PvP"] = "戰場/PvP", + ["Buffs"] = "增益", + ["Chat/Communication"] = "聊天/通訊", + ["Druid"] = "德魯伊", + ["Hunter"] = "獵人", + ["Mage"] = "法師", + ["Paladin"] = "聖騎士", + ["Priest"] = "牧師", + ["Rogue"] = "盜賊", + ["Shaman"] = "薩滿", + ["Warlock"] = "術士", + ["Warrior"] = "戰士", + ["Healer"] = "治療者", + ["Tank"] = "坦克", + ["Caster"] = "施法者", + ["Combat"] = "戰鬥", + ["Compilations"] = "整合", + ["Data Export"] = "資料匯出", + ["Development Tools"] = "開發工具", + ["Guild"] = "公會", + ["Frame Modification"] = "框架修改", + ["Interface Enhancements"] = "介面增強", + ["Inventory"] = "庫存", + ["Library"] = "程式庫", + ["Map"] = "地圖", + ["Mail"] = "郵件", + ["Miscellaneous"] = "雜項", + ["Quest"] = "任務", + ["Raid"] = "團隊", + ["Tradeskill"] = "交易技能", + ["UnitFrame"] = "單位框架", + } +elseif GetLocale() == "zhCN" then + STANDBY = "|cffff5050(暂挂)|r" + + TITLE = "标题" + NOTES = "附注" + VERSION = "版本" + AUTHOR = "作者" + DATE = "日期" + CATEGORY = "分类" + EMAIL = "电子邮件" + WEBSITE = "网站" + CREDITS = "Credits" -- fix + LICENSE = "License" -- fix + + ABOUT = "关于" + PRINT_ADDON_INFO = "印列出插件信息" + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "动作条", + ["Auction"] = "拍卖", + ["Audio"] = "音频", + ["Battlegrounds/PvP"] = "战场/PvP", + ["Buffs"] = "增益魔法", + ["Chat/Communication"] = "聊天/交流", + ["Druid"] = "德鲁伊", + ["Hunter"] = "猎人", + ["Mage"] = "法师", + ["Paladin"] = "圣骑士", + ["Priest"] = "牧师", + ["Rogue"] = "盗贼", + ["Shaman"] = "萨满祭司", + ["Warlock"] = "术士", + ["Warrior"] = "战士", +-- ["Healer"] = "治疗保障", +-- ["Tank"] = "近战控制", +-- ["Caster"] = "远程输出", + ["Combat"] = "战斗", + ["Compilations"] = "编译", + ["Data Export"] = "数据导出", + ["Development Tools"] = "开发工具", + ["Guild"] = "公会", + ["Frame Modification"] = "框架修改", + ["Interface Enhancements"] = "界面增强", + ["Inventory"] = "背包", + ["Library"] = "库", + ["Map"] = "地图", + ["Mail"] = "邮件", + ["Miscellaneous"] = "杂项", + ["Quest"] = "任务", + ["Raid"] = "团队", + ["Tradeskill"] = "商业技能", + ["UnitFrame"] = "头像框架", + } +elseif GetLocale() == "esES" then + STANDBY = "|cffff5050(espera)|r" + + TITLE = "Título" + NOTES = "Notas" + VERSION = "Versión" + AUTHOR = "Autor" + DATE = "Fecha" + CATEGORY = "Categoría" + EMAIL = "E-mail" + WEBSITE = "Web" + CREDITS = "Créditos" + LICENSE = "License" -- fix + + ABOUT = "Acerca de" + PRINT_ADDON_INFO = "Muestra información acerca del accesorio." + DONATE = "Donate" -- fix + DONATE_DESC = "Give a much-needed donation to the author of this addon." -- fix + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." -- fix + + CATEGORIES = { + ["Action Bars"] = "Barras de Acción", + ["Auction"] = "Subasta", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Campos de Batalla/JcJ", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Comunicación", + ["Druid"] = "Druida", + ["Hunter"] = "Cazador", + ["Mage"] = "Mago", + ["Paladin"] = "Paladín", + ["Priest"] = "Sacerdote", + ["Rogue"] = "Pícaro", + ["Shaman"] = "Chamán", + ["Warlock"] = "Brujo", + ["Warrior"] = "Guerrero", + ["Healer"] = "Sanador", + ["Tank"] = "Tanque", + ["Caster"] = "Conjurador", + ["Combat"] = "Combate", + ["Compilations"] = "Compilaciones", + ["Data Export"] = "Exportar Datos", + ["Development Tools"] = "Herramientas de Desarrollo", + ["Guild"] = "Hermandad", + ["Frame Modification"] = "Modificación de Marcos", + ["Interface Enhancements"] = "Mejoras de la Interfaz", + ["Inventory"] = "Inventario", + ["Library"] = "Biblioteca", + ["Map"] = "Mapa", + ["Mail"] = "Correo", + ["Miscellaneous"] = "Misceláneo", + ["Quest"] = "Misión", + ["Raid"] = "Banda", + ["Tradeskill"] = "Habilidad de Comercio", + ["UnitFrame"] = "Marco de Unidades", + } +else -- enUS + STANDBY = "|cffff5050(standby)|r" + + TITLE = "Title" + NOTES = "Notes" + VERSION = "Version" + AUTHOR = "Author" + DATE = "Date" + CATEGORY = "Category" + EMAIL = "E-mail" + WEBSITE = "Website" + CREDITS = "Credits" + LICENSE = "License" + + ABOUT = "About" + PRINT_ADDON_INFO = "Show information about the addon." + DONATE = "Donate" + DONATE_DESC = "Give a much-needed donation to the author of this addon." + HOWTO_DONATE_WINDOWS = "Press Ctrl-A to select the link, then Ctrl-C to copy, then Alt-Tab out of the game, open your favorite web browser, and paste the link into the address bar." + HOWTO_DONATE_MAC = "Press Cmd-A to select the link, then Cmd-C to copy, then Cmd-Tab out of the game, open your favorite web browser, and paste the link into the address bar." + + CATEGORIES = { + ["Action Bars"] = "Action Bars", + ["Auction"] = "Auction", + ["Audio"] = "Audio", + ["Battlegrounds/PvP"] = "Battlegrounds/PvP", + ["Buffs"] = "Buffs", + ["Chat/Communication"] = "Chat/Communication", + ["Druid"] = "Druid", + ["Hunter"] = "Hunter", + ["Mage"] = "Mage", + ["Paladin"] = "Paladin", + ["Priest"] = "Priest", + ["Rogue"] = "Rogue", + ["Shaman"] = "Shaman", + ["Warlock"] = "Warlock", + ["Warrior"] = "Warrior", + ["Healer"] = "Healer", + ["Tank"] = "Tank", + ["Caster"] = "Caster", + ["Combat"] = "Combat", + ["Compilations"] = "Compilations", + ["Data Export"] = "Data Export", + ["Development Tools"] = "Development Tools", + ["Guild"] = "Guild", + ["Frame Modification"] = "Frame Modification", + ["Interface Enhancements"] = "Interface Enhancements", + ["Inventory"] = "Inventory", + ["Library"] = "Library", + ["Map"] = "Map", + ["Mail"] = "Mail", + ["Miscellaneous"] = "Miscellaneous", + ["Quest"] = "Quest", + ["Raid"] = "Raid", + ["Tradeskill"] = "Tradeskill", + ["UnitFrame"] = "UnitFrame", + } +end + +setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive + local lowerKey = key:lower() + for k,v in pairs(CATEGORIES) do + if k:lower() == lowerKey then + return v + end + end +end }) + +-- Create the library object + +local AceOO = AceLibrary("AceOO-2.0") +local AceAddon = AceOO.Class() +local AceEvent +local AceConsole +local AceModuleCore + +function AceAddon:GetLocalizedCategory(name) + self:argCheck(name, 2, "string") + return CATEGORIES[name] or UNKNOWN +end + +function AceAddon:ToString() + return "AceAddon" +end + +local function print(text) + DEFAULT_CHAT_FRAME:AddMessage(text) +end + +function AceAddon:ADDON_LOADED(name) + local unregister = true + local initAddon = {} + while #self.nextAddon > 0 do + local addon = table.remove(self.nextAddon, 1) + if addon.possibleNames[name] then + table.insert(initAddon, addon) + else + unregister = nil + table.insert(self.skipAddon, addon) + end + end + self.nextAddon, self.skipAddon = self.skipAddon, self.nextAddon + if unregister then + AceAddon:UnregisterEvent("ADDON_LOADED") + end + while #initAddon > 0 do + local addon = table.remove(initAddon, 1) + table.insert(self.addons, addon) + if not self.addons[name] then + self.addons[name] = addon + end + addon.possibleNames = nil + self:InitializeAddon(addon, name) + end +end + +local function RegisterOnEnable(self) + if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK + AceAddon.playerLoginFired = true + end + if AceAddon.playerLoginFired then + AceAddon.addonsStarted[self] = true + if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then + AceAddon:ManualEnable(self) + end + else + if not AceAddon.addonsToOnEnable then + AceAddon.addonsToOnEnable = {} + end + table.insert(AceAddon.addonsToOnEnable, self) + end +end + +function AceAddon:InitializeAddon(addon, name) + if addon.name == nil then + addon.name = name + end + if GetAddOnMetadata then + -- TOC checks + if addon.title == nil then + addon.title = GetAddOnMetadata(name, "Title") + end + if type(addon.title) == "string" then + local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$") + if num then + addon.title = addon.title:sub(1, num - 1) + end + addon.title = addon.title:trim() + end + if addon.notes == nil then + addon.notes = GetAddOnMetadata(name, "Notes") + end + if type(addon.notes) == "string" then + addon.notes = addon.notes:trim() + end + if addon.version == nil then + addon.version = GetAddOnMetadata(name, "Version") + end + if type(addon.version) == "string" then + if addon.version:find("%$Revision: (%d+) %$") then + addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1") + elseif addon.version:find("%$Rev: (%d+) %$") then + addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1") + elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then + addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1") + end + addon.version = addon.version:trim() + end + if addon.author == nil then + addon.author = GetAddOnMetadata(name, "Author") + end + if type(addon.author) == "string" then + addon.author = addon.author:trim() + end + if addon.credits == nil then + addon.credits = GetAddOnMetadata(name, "X-Credits") + end + if type(addon.credits) == "string" then + addon.credits = addon.credits:trim() + end + if addon.donate == nil then + addon.donate = GetAddOnMetadata(name, "X-Donate") + end + if type(addon.donate) == "string" then + addon.donate = addon.donate:trim() + end + if addon.date == nil then + addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate") + end + if type(addon.date) == "string" then + if addon.date:find("%$Date: (.-) %$") then + addon.date = addon.date:gsub("%$Date: (.-) %$", "%1") + elseif addon.date:find("%$LastChangedDate: (.-) %$") then + addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1") + end + addon.date = addon.date:trim() + end + + if addon.category == nil then + addon.category = GetAddOnMetadata(name, "X-Category") + end + if type(addon.category) == "string" then + addon.category = addon.category:trim() + end + if addon.email == nil then + addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") + end + if type(addon.email) == "string" then + addon.email = addon.email:trim() + end + if addon.license == nil then + addon.license = GetAddOnMetadata(name, "X-License") + end + if type(addon.license) == "string" then + addon.license = addon.license:trim() + end + if addon.website == nil then + addon.website = GetAddOnMetadata(name, "X-Website") + end + if type(addon.website) == "string" then + addon.website = addon.website:trim() + end + end + local current = addon.class + while true do + if current == AceOO.Class or not current then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedInitialize) == "function" then + mixin:OnEmbedInitialize(addon, name) + end + end + end + current = current.super + end + local n = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 + + if type(addon.OnInitialize) == "function" then + safecall(addon.OnInitialize, addon, name) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonInitialized", addon) + end + RegisterOnEnable(addon) + local n2 = AceAddon.addonsToOnEnable and #AceAddon.addonsToOnEnable or 0 + if n2 - n > 1 then + local mine = table.remove(AceAddon.addonsToOnEnable) + table.insert(AceAddon.addonsToOnEnable, n+1, mine) + end +end + +local aboutFrame +local function createAboutFrame() + aboutFrame = CreateFrame("Frame", "AceAddon20AboutFrame", UIParent, "DialogBoxFrame") + aboutFrame:SetWidth(500) + aboutFrame:SetHeight(400) + aboutFrame:SetPoint("CENTER") + aboutFrame:SetBackdrop({ + bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], + edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 5, right = 5, top = 5, bottom = 5 } + }) + aboutFrame:SetBackdropColor(0,0,0,1) + + local donateButton = CreateFrame("Button", "AceAddon20AboutFrameDonateButton", aboutFrame, "UIPanelButtonTemplate2") + aboutFrame.donateButton = donateButton + donateButton:SetPoint("BOTTOMRIGHT", -20, 20) + _G.AceAddon20AboutFrameDonateButtonText:SetText(DONATE) + donateButton:SetWidth(_G.AceAddon20AboutFrameDonateButtonText:GetWidth()+20) + donateButton:SetScript("OnClick", function() + aboutFrame.currentAddon:OpenDonationFrame() + end) + + local text = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + aboutFrame.title = text + text:SetPoint("TOP", 0, -5) + + aboutFrame:Hide() + + aboutFrame.lefts = {} + aboutFrame.rights = {} + aboutFrame.textLefts = {} + aboutFrame.textRights = {} + function aboutFrame:Clear() + self.title:SetText("") + for i = 1, #self.lefts do + self.lefts[i] = nil + self.rights[i] = nil + end + end + + function aboutFrame:AddLine(left, right) + aboutFrame.lefts[#aboutFrame.lefts+1] = left + aboutFrame.rights[#aboutFrame.rights+1] = right + end + + local aboutFrame_Show = aboutFrame.Show + function aboutFrame:Show(...) + local maxLeftWidth = 0 + local maxRightWidth = 0 + local textHeight = 0 + for i = 1, #self.lefts do + if not self.textLefts[i] then + local left = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontNormal") + self.textLefts[i] = left + local right = aboutFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + self.textRights[i] = right + if i == 1 then + left:SetPoint("TOPRIGHT", aboutFrame, "TOPLEFT", 75, -35) + else + left:SetPoint("TOPRIGHT", self.textLefts[i-1], "BOTTOMRIGHT", 0, -5) + end + right:SetPoint("LEFT", left, "RIGHT", 5, 0) + end + self.textLefts[i]:SetText(self.lefts[i] .. ":") + self.textRights[i]:SetText(self.rights[i]) + local leftWidth = self.textLefts[i]:GetWidth() + local rightWidth = self.textRights[i]:GetWidth() + textHeight = self.textLefts[i]:GetHeight() + if maxLeftWidth < leftWidth then + maxLeftWidth = leftWidth + end + if maxRightWidth < rightWidth then + maxRightWidth = rightWidth + end + end + for i = #self.lefts+1, #self.textLefts do + self.textLefts[i]:SetText('') + self.textRights[i]:SetText('') + end + aboutFrame:SetWidth(75 + maxRightWidth + 20) + aboutFrame:SetHeight(#self.lefts * (textHeight + 5) + 100) + + aboutFrame_Show(self, ...) + end + aboutFrame:Hide() + + createAboutFrame = nil +end +local donateFrame + +local function unobfuscateEmail(email) + return email:gsub(" AT ", "@"):gsub(" DOT ", ".") +end + +local function isGoodVariable(var) + return type(var) == "string" or type(var) == "number" +end +function AceAddon.prototype:PrintAddonInfo() + if createAboutFrame then + createAboutFrame() + end + aboutFrame:Clear() + local x + if isGoodVariable(self.title) then + x = tostring(self.title) + elseif isGoodVariable(self.name) then + x = tostring(self.name) + else + x = "<" .. tostring(self.class) .. " instance>" + end + if type(self.IsActive) == "function" then + if not self:IsActive() then + x = x .. " " .. STANDBY + end + end + aboutFrame.title:SetText(x) + + if isGoodVariable(self.version) then + aboutFrame:AddLine(VERSION, tostring(self.version)) + end + if isGoodVariable(self.notes) then + aboutFrame:AddLine(NOTES, tostring(self.notes)) + end + if isGoodVariable(self.author) then + aboutFrame:AddLine(AUTHOR, tostring(self.author)) + end + if isGoodVariable(self.credits) then + aboutFrame:AddLine(CREDITS, tostring(self.credits)) + end + if isGoodVariable(self.date) then + aboutFrame:AddLine(DATE, tostring(self.date)) + end + if self.category then + local category = CATEGORIES[self.category] + if category then + aboutFrame:AddLine(CATEGORY, tostring(self.category)) + end + end + if isGoodVariable(self.email) then + aboutFrame:AddLine(EMAIL, unobfuscateEmail(tostring(self.email))) + end + if isGoodVariable(self.website) then + aboutFrame:AddLine(WEBSITE, tostring(self.website)) + end + if isGoodVariable(self.license) then + aboutFrame:AddLine(LICENSE, tostring(self.license)) + end + + if donateFrame and donateFrame:IsShown() then + donateFrame:Hide() + end + + aboutFrame.currentAddon = self + + aboutFrame:Show() + + if self.donate then + aboutFrame.donateButton:Show() + else + aboutFrame.donateButton:Hide() + end +end + +local function createDonateFrame() + donateFrame = CreateFrame("Frame", "AceAddon20Frame", UIParent, "DialogBoxFrame") + + donateFrame:SetWidth(500) + donateFrame:SetHeight(200) + donateFrame:SetPoint("CENTER") + donateFrame:SetBackdrop({ + bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], + edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], + tile = true, tileSize = 16, edgeSize = 16, + insets = { left = 5, right = 5, top = 5, bottom = 5 } + }) + donateFrame:SetBackdropColor(0,0,0,1) + + local text = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge") + text:SetPoint("TOP", 0, -5) + text:SetText(DONATE) + + local howto = donateFrame:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + howto:SetPoint("TOP", text, "BOTTOM", 0, -5) + howto:SetPoint("LEFT", 16, 0) + howto:SetPoint("RIGHT", -16, 0) + if not IsMacClient() then + -- Windows or Linux + howto:SetText(HOWTO_DONATE_WINDOWS) + else + howto:SetText(HOWTO_DONATE_MAC) + end + + local scrollFrame = CreateFrame("ScrollFrame", "AceAddon20FrameScrollFrame", donateFrame, "UIPanelScrollFrameTemplate") + scrollFrame:SetToplevel(true) + scrollFrame:SetPoint("TOP", -10, -76) + scrollFrame:SetWidth(455) + scrollFrame:SetHeight(70) + howto:SetPoint("BOTTOM", scrollFrame, "TOP") + + local editBox = CreateFrame("EditBox", nil, scrollFrame) + donateFrame.editBox = editBox + scrollFrame:SetScrollChild(editBox) + editBox:SetFontObject(ChatFontNormal) + editBox:SetMultiLine(true) + editBox:SetMaxLetters(99999) + editBox:SetWidth(450) + editBox:SetHeight(54) + editBox:SetPoint("BOTTOM", 5, 0) + editBox:SetJustifyH("LEFT") + editBox:SetJustifyV("TOP") + editBox:SetAutoFocus(false) + editBox:SetScript("OnTextChanged", function(this) + if this:GetText() ~= this.text then + this:SetText(this.text) + end + end) + editBox:SetScript("OnEscapePressed", function(this) + this:ClearFocus() + end) + createDonateFrame = nil +end + +local function fix(char) + return ("%%%02x"):format(char:byte()) +end + +local function urlencode(text) + return text:gsub("[^0-9A-Za-z]", fix) +end + +function AceAddon.prototype:OpenDonationFrame() + if createDonateFrame then + createDonateFrame() + end + local donate = self.donate + if type(donate) ~= "string" then + donate = "Wowace" + end + local style, data = (":"):split(donate, 2) + style = style:lower() + if style ~= "website" and style ~= "paypal" then + style = "wowace" + end + if style == "wowace" then + donateFrame.editBox.text = "http://www.wowace.com/wiki/Donations" + elseif style == "website" then + donateFrame.editBox.text = data + else -- PayPal + local text = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=" .. urlencode(unobfuscateEmail(data)) + local name + if type(self.title) == "string" then + name = self.title + elseif type(self.name) == "string" then + name = self.name + end + if name then + name = name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", "") + text = text .. "&item_name=" .. urlencode(name) + end + donateFrame.editBox.text = text + end + donateFrame.editBox:SetText(donateFrame.editBox.text) + + if aboutFrame and aboutFrame:IsShown() then + aboutFrame:Hide() + end + + donateFrame:Show() + + donateFrame.editBox:SetFocus() +end + +local options +function AceAddon:GetAceOptionsDataTable(target) + return { + about = { + name = ABOUT, + desc = PRINT_ADDON_INFO, + type = "execute", + func = "PrintAddonInfo", + order = -1, + }, + donate = { + name = DONATE, + desc = DONATE_DESC, + type = "execute", + func = "OpenDonationFrame", + order = -1, + hidden = function() + return not target.donate + end + } + } +end + +function AceAddon:PLAYER_LOGIN() + self.playerLoginFired = true + if self.addonsToOnEnable then + while #self.addonsToOnEnable > 0 do + local addon = table.remove(self.addonsToOnEnable, 1) + self.addonsStarted[addon] = true + if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then + AceAddon:ManualEnable(addon) + end + end + self.addonsToOnEnable = nil + end +end + +function AceAddon.prototype:Inject(t) + AceAddon:argCheck(t, 2, "table") + for k,v in pairs(t) do + self[k] = v + end +end + +function AceAddon.prototype:init() + if not AceEvent then + error(MAJOR_VERSION .. " requires AceEvent-2.0", 4) + end + AceAddon.super.prototype.init(self) + + self.super = self.class.prototype + + AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED") + local names = {} + for i = 1, GetNumAddOns() do + if IsAddOnLoaded(i) then names[GetAddOnInfo(i)] = true end + end + self.possibleNames = names + table.insert(AceAddon.nextAddon, self) +end + +function AceAddon.prototype:ToString() + local x + if type(self.title) == "string" then + x = self.title + elseif type(self.name) == "string" then + x = self.name + else + x = "<" .. tostring(self.class) .. " instance>" + end + if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then + x = x .. " " .. STANDBY + end + return x +end + +AceAddon.new = function(self, ...) + local class = AceAddon:pcall(AceOO.Classpool, self, ...) + return class:new() +end + +function AceAddon:ManualEnable(addon) + AceAddon:argCheck(addon, 2, "table") + local first = nil + if AceOO.inherits(addon, "AceAddon-2.0") then + if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[addon] then + first = true + AceAddon.addonsEnabled[addon] = true + end + end + local current = addon.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, addon, first) + end + end + end + current = current.super + end + if type(addon.OnEnable) == "function" then + safecall(addon.OnEnable, addon, first) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", addon, first) + end +end + +function AceAddon:ManualDisable(addon) + AceAddon:argCheck(addon, 2, "table") + local current = addon.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, addon) + end + end + end + current = current.super + end + if type(module.OnDisable) == "function" then + safecall(module.OnDisable, addon) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", addon) + end +end + +local function external(self, major, instance) + if major == "AceEvent-2.0" then + AceEvent = instance + + AceEvent:embed(self) + + self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) + elseif major == "AceConsole-2.0" then + AceConsole = instance + + local slashCommands = { "/ace2" } + local _,_,_,enabled,loadable = GetAddOnInfo("Ace") + if not enabled or not loadable then + table.insert(slashCommands, "/ace") + end + local function listAddon(addon, depth) + if not depth then + depth = 0 + end + + local s = (" "):rep(depth) .. " - " .. tostring(addon) + if rawget(addon, 'version') then + s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r" + end + if rawget(addon, 'slashCommand') then + s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r" + end + print(s) + if type(rawget(addon, 'modules')) == "table" then + local i = 0 + for k,v in pairs(addon.modules) do + i = i + 1 + if i == 6 then + print((" "):rep(depth + 1) .. " - more...") + break + else + listAddon(v, depth + 1) + end + end + end + end + local function listNormalAddon(i) + local name,_,_,enabled,loadable = GetAddOnInfo(i) + if not loadable then + enabled = false + end + if self.addons[name] then + listAddon(self.addons[name]) + else + local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name) + local version = GetAddOnMetadata(i, "Version") + if version then + if version:find("%$Revision: (%d+) %$") then + version = version:gsub("%$Revision: (%d+) %$", "%1") + elseif version:find("%$Rev: (%d+) %$") then + version = version:gsub("%$Rev: (%d+) %$", "%1") + elseif version:find("%$LastChangedRevision: (%d+) %$") then + version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1") + end + s = s .. " - |cffffff7f" .. version .. "|r" + end + if not enabled then + s = s .. " |cffff0000(disabled)|r" + end + if IsAddOnLoadOnDemand(i) then + s = s .. " |cff00ff00[LoD]|r" + end + print(s) + end + end + local function mySort(alpha, bravo) + return tostring(alpha) < tostring(bravo) + end + AceConsole.RegisterChatCommand(self, slashCommands, { + desc = "AddOn development framework", + name = "Ace2", + type = "group", + args = { + about = { + desc = "Get information about Ace2", + name = "About", + type = "execute", + func = function() + print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework") + print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team") + print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/") + end + }, + list = { + desc = "List addons", + name = "List", + type = "group", + args = { + ace2 = { + desc = "List addons using Ace2", + name = "Ace2", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + table.sort(self.addons, mySort) + for _,v in ipairs(self.addons) do + listAddon(v) + end + end + }, + all = { + desc = "List all addons", + name = "All", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + listNormalAddon(i) + end + end + }, + enabled = { + desc = "List all enabled addons", + name = "Enabled", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local _,_,_,enabled,loadable = GetAddOnInfo(i) + if enabled and loadable then + listNormalAddon(i) + end + end + end + }, + disabled = { + desc = "List all disabled addons", + name = "Disabled", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local _,_,_,enabled,loadable = GetAddOnInfo(i) + if not enabled or not loadable then + listNormalAddon(i) + end + end + end + }, + lod = { + desc = "List all LoadOnDemand addons", + name = "LoadOnDemand", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + if IsAddOnLoadOnDemand(i) then + listNormalAddon(i) + end + end + end + }, + ace1 = { + desc = "List all addons using Ace1", + name = "Ace 1.x", + type = "execute", + func = function() + print("|cffffff7fAddon list:|r") + local count = GetNumAddOns() + for i = 1, count do + local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) + if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then + listNormalAddon(i) + end + end + end + }, + libs = { + desc = "List all libraries using AceLibrary", + name = "Libraries", + type = "execute", + func = function() + if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then + print("|cffffff7fLibrary list:|r") + for name, data in pairs(AceLibrary.libs) do + local s + if data.minor then + s = " - " .. tostring(name) .. "." .. tostring(data.minor) + else + s = " - " .. tostring(name) + end + if rawget(AceLibrary(name), 'slashCommand') then + s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)" + end + print(s) + end + end + end + }, + search = { + desc = "Search by name", + name = "Search", + type = "text", + usage = "<keyword>", + input = true, + get = false, + set = function(...) + local arg = { ... } + for i,v in ipairs(arg) do + arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower() + end + local count = GetNumAddOns() + for i = 1, count do + local name = GetAddOnInfo(i) + local good = true + for _,v in ipairs(arg) do + if not name:lower():find(v) then + good = false + break + end + end + if good then + listNormalAddon(i) + end + end + end + } + }, + }, + enable = { + desc = "Enable addon(s).", + name = "Enable", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, enabled, _, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif not enabled then + EnableAddOn(addon) + print(("|cffffff7fAce2:|r %s is now enabled."):format(addon or name)) + else + print(("|cffffff7fAce2:|r %s is already enabled."):format(addon or name)) + end + end + end, + }, + disable = { + desc = "Disable addon(s).", + name = "Disable", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, enabled, _, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif enabled then + DisableAddOn(addon) + print(("|cffffff7fAce2:|r %s is now disabled."):format(addon or name)) + else + print(("|cffffff7fAce2:|r %s is already disabled."):format(addon or name)) + end + end + end, + }, + load = { + desc = "Load addon(s).", + name = "Load", + type = "text", + usage = "<addon 1> <addon 2> ...", + get = false, + input = true, + set = function(...) + for i = 1, select("#", ...) do + local addon = select(i, ...) + local name, title, _, _, loadable, reason = GetAddOnInfo(addon) + if reason == "MISSING" then + print(("|cffffff7fAce2:|r AddOn %q does not exist."):format(addon)) + elseif not loadable then + print(("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s."):format(addon, reason)) + else + LoadAddOn(addon) + print(("|cffffff7fAce2:|r %s is now loaded."):format(addon or name)) + end + end + end + }, + info = { + desc = "Display information", + name = "Information", + type = "execute", + func = function() + local mem, threshold = gcinfo() + print((" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r"):format(mem / 1024)) + if threshold then + print((" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r"):format(threshold / 1024)) + end + print((" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r"):format(GetFramerate())) + local bandwidthIn, bandwidthOut, latency = GetNetStats() + bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024) + print((" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r"):format(latency)) + print((" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r"):format(bandwidthIn)) + print((" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r"):format(bandwidthOut)) + print((" - |cffffff7fTotal addons [|r%d|cffffff7f]|r"):format(GetNumAddOns())) + print((" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r"):format(#self.addons)) + local ace = 0 + local enabled = 0 + local disabled = 0 + local lod = 0 + for i = 1, GetNumAddOns() do + local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) + if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then + ace = ace + 1 + end + if IsAddOnLoadOnDemand(i) then + lod = lod + 1 + end + local isActive, loadable = select(4, GetAddOnInfo(i)) + if not isActive or not loadable then + disabled = disabled + 1 + else + enabled = enabled + 1 + end + end + print((" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r"):format(ace)) + print((" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r"):format(lod)) + print((" - |cffffff7fenabled addons [|r%d|cffffff7f]|r"):format(enabled)) + print((" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r"):format(disabled)) + local libs = 0 + if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then + for _ in pairs(AceLibrary.libs) do + libs = libs + 1 + end + end + print((" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r"):format(libs)) + end + } + } + }) + elseif major == "AceModuleCore-2.0" then + AceModuleCore = instance + end +end + +local function activate(self, oldLib, oldDeactivate) + AceAddon = self + + self.playerLoginFired = oldLib and oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage + self.addonsToOnEnable = oldLib and oldLib.addonsToOnEnable + self.addons = oldLib and oldLib.addons or {} + self.nextAddon = oldLib and oldLib.nextAddon or {} + self.skipAddon = oldLib and oldLib.skipAddon or {} + self.addonsStarted = oldLib and oldLib.addonsStarted or {} + self.addonsEnabled = oldLib and oldLib.addonsEnabled or {} + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceConsole-2.0/AceConsole-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,2675 @@ +--[[ +Name: AceConsole-2.0 +Revision: $Rev: 48940 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceConsole-2.0 +SVN: http://svn.wowace.com/wowace/trunk/Ace2/AceConsole-2.0 +Description: Mixin to allow for input/output capabilities. This uses the + AceOptions data table format to determine input. + http://www.wowace.com/index.php/AceOptions_data_table +Dependencies: AceLibrary, AceOO-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceConsole-2.0" +local MINOR_VERSION = "$Revision: 48940 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end + +-- #AUTODOC_NAMESPACE AceConsole + +local MAP_ONOFF, USAGE, IS_CURRENTLY_SET_TO, IS_NOW_SET_TO, IS_NOT_A_VALID_OPTION_FOR, IS_NOT_A_VALID_VALUE_FOR, NO_OPTIONS_AVAILABLE, OPTION_HANDLER_NOT_FOUND, OPTION_HANDLER_NOT_VALID, OPTION_IS_DISABLED, KEYBINDING_USAGE, DEFAULT_CONFIRM_MESSAGE +if GetLocale() == "deDE" then + MAP_ONOFF = { [false] = "|cffff0000Aus|r", [true] = "|cff00ff00An|r" } + USAGE = "Benutzung" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r steht momentan auf |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r ist nun auf |cffffff7f[|r%s|cffffff7f]|r gesetzt" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] ist keine g\195\188ltige Option f\195\188r |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] ist kein g\195\188ltiger Wert f\195\188r |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "Keine Optionen verfügbar" + OPTION_HANDLER_NOT_FOUND = "Optionen handler |cffffff7f%q|r nicht gefunden." + OPTION_HANDLER_NOT_VALID = "Optionen handler nicht g\195\188ltig." + OPTION_IS_DISABLED = "Option |cffffff7f%s|r deaktiviert." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix + DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix +elseif GetLocale() == "frFR" then + MAP_ONOFF = { [false] = "|cffff0000Inactif|r", [true] = "|cff00ff00Actif|r" } + USAGE = "Utilisation" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est actuellement positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r est maintenant positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] n'est pas une option valide pour |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] n'est pas une valeur valide pour |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "Pas d'options disponibles" + OPTION_HANDLER_NOT_FOUND = "Le gestionnaire d'option |cffffff7f%q|r n'a pas \195\169t\195\169 trouv\195\169." + OPTION_HANDLER_NOT_VALID = "Le gestionnaire d'option n'est pas valide." + OPTION_IS_DISABLED = "L'option |cffffff7f%s|r est d\195\169sactiv\195\169e." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix + DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix +elseif GetLocale() == "koKR" then + MAP_ONOFF = { [false] = "|cffff0000끔|r", [true] = "|cff00ff00켬|r" } + USAGE = "사용법" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r|1은;는; 현재 상태는 |cffffff7f[|r%s|cffffff7f]|r|1으로;로; 설정되어 있습니다." + IS_NOW_SET_TO = "|cffffff7f%s|r|1을;를; |cffffff7f[|r%s|cffffff7f]|r 상태로 변경합니다." + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정입니다." + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용 불가능한 설정 값입니다." + NO_OPTIONS_AVAILABLE = "가능한 설정이 없습니다." + OPTION_HANDLER_NOT_FOUND = "설정 조정 값인 |cffffff7f%q|r|1을;를; 찾지 못했습니다." + OPTION_HANDLER_NOT_VALID = "설정 조정 값이 올바르지 않습니다." + OPTION_IS_DISABLED = "|cffffff7f%s|r 설정은 사용할 수 없습니다." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" + DEFAULT_CONFIRM_MESSAGE = "정말 당신은 `%s'|1을;를; 하시겠습니까?" +elseif GetLocale() == "zhCN" then + MAP_ONOFF = { [false] = "|cffff0000\229\133\179\233\151\173|r", [true] = "|cff00ff00\229\188\128\229\144\175|r" } + USAGE = "\231\148\168\230\179\149" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r \229\189\147\229\137\141\232\162\171\232\174\190\231\189\174 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r \231\142\176\229\156\168\232\162\171\232\174\190\231\189\174\228\184\186 |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\231\154\132\233\128\137\233\161\185 \228\184\186 |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\229\128\188 \228\184\186 |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "\230\178\161\230\156\137\233\128\137\233\161\185\229\143\175\231\148\168" + OPTION_HANDLER_NOT_FOUND = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 |cffffff7f%q|r \230\178\161\230\159\165\230\137\190." + OPTION_HANDLER_NOT_VALID = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 \230\151\160\230\149\136." + OPTION_IS_DISABLED = "\233\128\137\233\161\185 |cffffff7f%s|r \228\184\141\229\174\140\230\149\180." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix + DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix +elseif GetLocale() == "zhTW" then + MAP_ONOFF = { [false] = "|cffff0000關閉|r", [true] = "|cff00ff00開啟|r" } + USAGE = "用法" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r目前的設定為|cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r現在被設定為|cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的選項" + IS_NOT_A_VALID_VALUE_FOR = "對於|cffffff7f%2$s|r,[|cffffff7f%1$s|r]是一個不符合規定的數值" + NO_OPTIONS_AVAILABLE = "沒有可用的選項" + OPTION_HANDLER_NOT_FOUND = "找不到|cffffff7f%q|r選項處理器。" + OPTION_HANDLER_NOT_VALID = "選項處理器不符合規定。" + OPTION_IS_DISABLED = "|cffffff7f%s|r已被停用。" + KEYBINDING_USAGE = "<Alt-Ctrl-Shift-鍵>" + DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" +elseif GetLocale() == "esES" then + MAP_ONOFF = { [false] = "|cffff0000Desactivado|r", [true] = "|cff00ff00Activado|r" } + USAGE = "Uso" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est\195\161 establecido actualmente a |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r se ha establecido a |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] no es una opci\195\179n valida para |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] no es un valor v\195\161lido para |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "No hay opciones disponibles" + OPTION_HANDLER_NOT_FOUND = "Gestor de opciones |cffffff7f%q|r no encontrado." + OPTION_HANDLER_NOT_VALID = "Gestor de opciones no v\195\161lido." + OPTION_IS_DISABLED = "La opci\195\179n |cffffff7f%s|r est\195\161 desactivada." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" + DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" -- fix +else -- enUS + MAP_ONOFF = { [false] = "|cffff0000Off|r", [true] = "|cff00ff00On|r" } + USAGE = "Usage" + IS_CURRENTLY_SET_TO = "|cffffff7f%s|r is currently set to |cffffff7f[|r%s|cffffff7f]|r" + IS_NOW_SET_TO = "|cffffff7f%s|r is now set to |cffffff7f[|r%s|cffffff7f]|r" + IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] is not a valid option for |cffffff7f%s|r" + IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] is not a valid value for |cffffff7f%s|r" + NO_OPTIONS_AVAILABLE = "No options available" + OPTION_HANDLER_NOT_FOUND = "Option handler |cffffff7f%q|r not found." + OPTION_HANDLER_NOT_VALID = "Option handler not valid." + OPTION_IS_DISABLED = "Option |cffffff7f%s|r is disabled." + KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" + DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" +end + +local NONE = NONE or "None" + +local AceOO = AceLibrary("AceOO-2.0") +local AceEvent + +local AceConsole = AceOO.Mixin { "Print", "PrintComma", "PrintLiteral", "CustomPrint", "RegisterChatCommand" } +local Dewdrop + +local _G = getfenv(0) + +local function print(text, name, r, g, b, frame, delay) + if not text or text:len() == 0 then + text = " " + end + if not name or name == AceConsole then + else + text = "|cffffff78" .. tostring(name) .. ":|r " .. text + end + local last_color + for t in text:gmatch("[^\n]+") do + (frame or DEFAULT_CHAT_FRAME):AddMessage(last_color and "|cff" .. last_color .. t or t, r, g, b, nil, delay or 5) + if not last_color or t:find("|r") or t:find("|c") then + last_color = t:match(".*|c[fF][fF](%x%x%x%x%x%x)[^|]-$") + end + end + return text +end + +local real_tostring = tostring + +local function tostring(t) + if type(t) == "table" then + if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then + return ("<%s:%s>"):format(t:GetObjectType(), t:GetName() or "(anon)") + end + end + return real_tostring(t) +end + +local getkeystring + +local function isList(t) + local n = #t + for k,v in pairs(t) do + if type(k) ~= "number" then + return false + elseif k < 1 or k > n then + return false + end + end + return true +end + +local findGlobal = setmetatable({}, {__index=function(self, t) + for k,v in pairs(_G) do + if v == t then + k = tostring(k) + self[v] = k + return k + end + end + self[t] = false + return false +end}) + +local recurse = {} +local timeToEnd +local GetTime = GetTime +local type = type + +local new, del +do + local cache = setmetatable({},{__mode='k'}) + function new() + local t = next(cache) + if t then + cache[t] = nil + return t + else + return {} + end + end + + function del(t) + for k in pairs(t) do + t[k] = nil + end + cache[t] = true + return nil + end +end + +local function ignoreCaseSort(alpha, bravo) + if not alpha or not bravo then + return false + end + return tostring(alpha):lower() < tostring(bravo):lower() +end + +local function specialSort(alpha, bravo) + if alpha == nil or bravo == nil then + return false + end + local type_alpha, type_bravo = type(alpha), type(bravo) + if type_alpha ~= type_bravo then + return type_alpha < type_bravo + end + if type_alpha == "string" then + return alpha:lower() < bravo:lower() + elseif type_alpha == "number" then + return alpha < bravo + elseif type_alpha == "table" then + return #alpha < #bravo + elseif type_alpha == "boolean" then + return not alpha + else + return false + end +end + +local function escapeChar(c) + return ("\\%03d"):format(c:byte()) +end + +local function literal_tostring_prime(t, depth) + if type(t) == "string" then + return ("|cff00ff00%q|r"):format((t:gsub("|", "||"))):gsub("[\001-\012\014-\031\128-\255]", escapeChar) + elseif type(t) == "table" then + if t == _G then + return "|cffffea00_G|r" + end + if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then + return ("|cffffea00<%s:%s>|r"):format(t:GetObjectType(), t:GetName() or "(anon)") + end + if next(t) == nil then + local mt = getmetatable(t) + if type(mt) == "table" and type(mt.__raw) == "table" then + t = mt.__raw + end + end + if recurse[t] then + local g = findGlobal[t] + if g then + return ("|cff9f9f9f<Recursion _G[%q]>|r"):format(g) + else + return ("|cff9f9f9f<Recursion %s>|r"):format(real_tostring(t):gsub("|", "||")) + end + elseif GetTime() > timeToEnd then + local g = findGlobal[t] + if g then + return ("|cff9f9f9f<Timeout _G[%q]>|r"):format(g) + else + return ("|cff9f9f9f<Timeout %s>|r"):format(real_tostring(t):gsub("|", "||")) + end + elseif depth >= 2 then + local g = findGlobal[t] + if g then + return ("|cff9f9f9f<_G[%q]>|r"):format(g) + else + return ("|cff9f9f9f<%s>|r"):format(real_tostring(t):gsub("|", "||")) + end + end + recurse[t] = true + if next(t) == nil then + return "{}" + elseif next(t, (next(t))) == nil then + local k, v = next(t) + if k == 1 then + return "{ " .. literal_tostring_prime(v, depth+1) .. " }" + else + return "{ " .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. " }" + end + end + local s + local g = findGlobal[t] + if g then + s = ("{ |cff9f9f9f-- _G[%q]|r\n"):format(g) + else + s = "{ |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||") .. "|r\n" + end + if isList(t) then + for i = 1, #t do + s = s .. (" "):rep(depth+1) .. literal_tostring_prime(t[i], depth+1) .. (i == #t and "\n" or ",\n") + end + else + local tmp = new() + for k in pairs(t) do + tmp[#tmp+1] = k + end + table.sort(tmp, specialSort) + for i,k in ipairs(tmp) do + tmp[i] = nil + local v = t[k] + s = s .. (" "):rep(depth+1) .. getkeystring(k, depth+1) .. " = " .. literal_tostring_prime(v, depth+1) .. (tmp[i+1] == nil and "\n" or ",\n") + end + tmp = del(tmp) + end + if g then + s = s .. (" "):rep(depth) .. string.format("} |cff9f9f9f-- _G[%q]|r", g) + else + s = s .. (" "):rep(depth) .. "} |cff9f9f9f-- " .. real_tostring(t):gsub("|", "||") + end + return s + end + if type(t) == "number" then + return "|cffff7fff" .. real_tostring(t) .. "|r" + elseif type(t) == "boolean" then + return "|cffff9100" .. real_tostring(t) .. "|r" + elseif t == nil then + return "|cffff7f7f" .. real_tostring(t) .. "|r" + else + return "|cffffea00" .. real_tostring(t) .. "|r" + end +end + +function getkeystring(t, depth) + if type(t) == "string" then + if t:find("^[%a_][%a%d_]*$") then + return "|cff7fd5ff" .. t .. "|r" + end + end + return "[" .. literal_tostring_prime(t, depth) .. "]" +end + +local get_stringed_args +do + local function g(value, ...) + if select('#', ...) == 0 then + return literal_tostring_prime(value, 1) + end + return literal_tostring_prime(value, 1) .. ", " .. g(...) + end + + local function f(success, ...) + if not success then + return + end + return g(...) + end + + function get_stringed_args(func, ...) + return f(pcall(func, ...)) + end +end + +local function literal_tostring_frame(t) + local s = ("|cffffea00<%s:%s|r\n"):format(t:GetObjectType(), t:GetName() or "(anon)") + local __index = getmetatable(t).__index + local tmp, tmp2, tmp3 = new(), new(), new() + for k in pairs(t) do + if k ~= 0 then + tmp3[k] = true + tmp2[k] = true + end + end + for k in pairs(__index) do + tmp2[k] = true + end + for k in pairs(tmp2) do + tmp[#tmp+1] = k + tmp2[k] = nil + end + table.sort(tmp, ignoreCaseSort) + local first = true + for i,k in ipairs(tmp) do + local v = t[k] + local good = true + if k == "GetPoint" then + for i = 1, t:GetNumPoints() do + if not first then + s = s .. ",\n" + else + first = false + end + s = s .. " " .. getkeystring(k, 1) .. "(" .. literal_tostring_prime(i, 1) .. ") => " .. get_stringed_args(v, t, i) + end + elseif type(v) == "function" and type(k) == "string" and (k:find("^Is") or k:find("^Get") or k:find("^Can")) then + local q = get_stringed_args(v, t) + if q then + if not first then + s = s .. ",\n" + else + first = false + end + s = s .. " " .. getkeystring(k, 1) .. "() => " .. q + end + elseif type(v) ~= "function" or (type(v) == "function" and type(k) == "string" and tmp3[k]) then + if not first then + s = s .. ",\n" + else + first = false + end + s = s .. " " .. getkeystring(k, 1) .. " = " .. literal_tostring_prime(v, 1) + else + good = false + end + end + tmp, tmp2, tmp3 = del(tmp), del(tmp2), del(tmp3) + s = s .. "\n|cffffea00>|r" + return s +end + +local function literal_tostring(t, only) + timeToEnd = GetTime() + 0.2 + local s + if only and type(t) == "table" and type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then + s = literal_tostring_frame(t) + else + s = literal_tostring_prime(t, 0) + end + for k,v in pairs(recurse) do + recurse[k] = nil + end + for k,v in pairs(findGlobal) do + findGlobal[k] = nil + end + return s +end + +local function tostring_args(a1, ...) + if select('#', ...) < 1 then + return tostring(a1) + end + return tostring(a1), tostring_args(...) +end + +local function literal_tostring_args(a1, ...) + if select('#', ...) < 1 then + return literal_tostring(a1) + end + return literal_tostring(a1), literal_tostring_args(...) +end + +function AceConsole:CustomPrint(r, g, b, frame, delay, connector, a1, ...) + if connector == true then + local s + if select('#', ...) == 0 then + s = literal_tostring(a1, true) + else + s = (", "):join(literal_tostring_args(a1, ...)) + end + return print(s, self, r, g, b, frame or self.printFrame, delay) + elseif tostring(a1):find("%%") and select('#', ...) >= 1 then + local success, text = pcall(string.format, tostring_args(a1, ...)) + if success then + return print(text, self, r, g, b, frame or self.printFrame, delay) + end + end + return print((connector or " "):join(tostring_args(a1, ...)), self, r, g, b, frame or self.printFrame, delay) +end + +function AceConsole:Print(...) + return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, " ", ...) +end + +function AceConsole:PrintComma(...) + return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, ", ", ...) +end + +function AceConsole:PrintLiteral(...) + return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, true, ...) +end + +local work +local argwork + +local function findTableLevel(self, options, chat, text, index, passTable) + if not index then + index = 1 + if work then + for k,v in pairs(work) do + work[k] = nil + end + for k,v in pairs(argwork) do + argwork[k] = nil + end + else + work = {} + argwork = {} + end + local len = text:len() + local count + repeat + text, count = text:gsub("(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[[^%]]-) (.-%]|h|r)", "%1\001%2") + until count == 0 + text = text:gsub("(%]|h|r)(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[)", "%1 %2") + for token in text:gmatch("([^%s]+)") do + local token = token + local num = tonumber(token) + if num then + token = num + else + token = token:gsub("\001", " ") + end + table.insert(work, token) + end + end + + local path = chat + for i = 1, index - 1 do + path = path .. " " .. tostring(work[i]) + end + + local passValue = options.passValue or (passTable and work[index-1]) + passTable = passTable or options + + if type(options.args) == "table" then + local disabled, hidden = options.disabled, options.cmdHidden or options.hidden + if hidden then + if type(hidden) == "function" then + hidden = hidden(passValue) + elseif type(hidden) == "string" then + local handler = options.handler or self + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + hidden = handler[f](handler, passValue) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled(passValue) + elseif type(disabled) == "string" then + local handler = options.handler or self + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + disabled = handler[f](handler, passValue) + if neg then + disabled = not disabled + end + end + end + if not disabled then + local next = work[index] and tostring(work[index]):lower() + local next_num = tonumber(next) + if next then + for k,v in pairs(options.args) do + local good = false + if tostring(k):gsub("%s", "-"):lower() == next then + good = true + elseif k == next_num then + good = true + elseif type(v.aliases) == "table" then + for _,alias in ipairs(v.aliases) do + if alias:gsub("%s", "-"):lower() == next then + good = true + break + end + end + elseif type(v.aliases) == "string" and v.aliases:gsub("%s", "-"):lower() == next then + good = true + end + if good then + work[index] = k -- revert it back to its original form as supplied in args + if options.pass then + passTable = passTable or options + if options.get and options.set then + passTable = options + end + else + passTable = nil + end + return findTableLevel(options.handler or self, v, chat, text, index + 1, passTable) + end + end + end + end + end + for i = index, #work do + table.insert(argwork, work[i]) + end + return options, path, argwork, options.handler or self, passTable, passValue +end + +local function validateOptionsMethods(self, options, position) + if type(options) ~= "table" then + return "Options must be a table.", position + end + self = options.handler or self + if options.type == "execute" then + if options.func and type(options.func) ~= "string" and type(options.func) ~= "function" then + return "func must be a string or function", position + end + if options.func and type(options.func) == "string" and type(self[options.func]) ~= "function" then + return ("%q is not a proper function"):format(tostring(options.func)), position + end + else + if options.get then + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return "get must be a string or function", position + end + if type(options.get) == "string" then + local f = options.get + if options.type == "toggle" then + f = f:match("^~(.-)$") or f + end + if type(self[f]) ~= "function" then + return ("%q is not a proper function"):format(tostring(f)), position + end + end + end + if options.set then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return "set must be a string or function", position + end + if type(options.set) == "string" and type(self[options.set]) ~= "function" then + return ("%q is not a proper function"):format(tostring(options.set)), position + end + end + if options.validate and type(options.validate) ~= "table" and options.validate ~= "keybinding" then + if type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return "validate must be a string or function", position + end + if type(options.validate) == "string" and type(self[options.validate]) ~= "function" then + return ("%q is not a proper function"):format(tostring(options.validate)), position + end + end + end + if options.disabled and type(options.disabled) == "string" then + local f = options.disabled + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return ("%q is not a proper function"):format(tostring(f)), position + end + end + if options.cmdHidden and type(options.cmdHidden) == "string" then + local f = options.cmdHidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return ("%q is not a proper function"):format(tostring(f)), position + end + end + if options.guiHidden and type(options.guiHidden) == "string" then + local f = options.guiHidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return ("%q is not a proper function"):format(tostring(f)), position + end + end + if options.hidden and type(options.hidden) == "string" then + local f = options.hidden + f = f:match("^~(.-)$") or f + if type(self[f]) ~= "function" then + return ("%q is not a proper function"):format(tostring(f)), position + end + end + if options.type == "group" and type(options.args) == "table" then + for k,v in pairs(options.args) do + if type(v) == "table" then + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptionsMethods(self, v, newposition) + if err then + return err, pos + end + end + end + end +end + +local function validateOptions(options, position, baseOptions, fromPass) + if not baseOptions then + baseOptions = options + end + if type(options) ~= "table" then + return "Options must be a table.", position + end + local kind = options.type + if type(kind) ~= "string" then + return '"type" must be a string.', position + elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then + return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position + end + if options.aliases then + if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then + return '"alias" must be a table or string', position + end + end + if not fromPass then + if kind == "execute" then + if type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + elseif kind == "range" or kind == "text" or kind == "toggle" then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if kind == "text" and options.get == false then + elseif type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif kind == "group" and options.pass then + if options.pass ~= true then + return '"pass" must be either nil, true, or false', position + end + if not options.func then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + end + end + if options ~= baseOptions then + if kind == "header" then + elseif type(options.desc) ~= "string" then + return '"desc" must be a string', position + elseif options.desc:len() == 0 then + return '"desc" cannot be a 0-length string', position + end + end + + if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then + if options.type == "header" and not options.cmdName and not options.name then + elseif options.cmdName then + if type(options.cmdName) ~= "string" then + return '"cmdName" must be a string or nil', position + elseif options.cmdName:len() == 0 then + return '"cmdName" cannot be a 0-length string', position + end + if type(options.guiName) ~= "string" then + if not options.guiNameIsMap then + return '"guiName" must be a string or nil', position + end + elseif options.guiName:len() == 0 then + return '"guiName" cannot be a 0-length string', position + end + else + if type(options.name) ~= "string" then + return '"name" must be a string', position + elseif options.name:len() == 0 then + return '"name" cannot be a 0-length string', position + end + end + end + if options.guiNameIsMap then + if type(options.guiNameIsMap) ~= "boolean" then + return '"guiNameIsMap" must be a boolean or nil', position + elseif options.type ~= "toggle" then + return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position + elseif type(options.map) ~= "table" then + return '"map" must be a table', position + end + end + if options.message and type(options.message) ~= "string" then + return '"message" must be a string or nil', position + end + if options.error and type(options.error) ~= "string" then + return '"error" must be a string or nil', position + end + if options.current and type(options.current) ~= "string" then + return '"current" must be a string or nil', position + end + if options.order then + if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then + return '"order" must be a non-zero number or nil', position + end + end + if options.disabled then + if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then + return '"disabled" must be a function, string, or boolean', position + end + end + if options.cmdHidden then + if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then + return '"cmdHidden" must be a function, string, or boolean', position + end + end + if options.guiHidden then + if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then + return '"guiHidden" must be a function, string, or boolean', position + end + end + if options.hidden then + if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then + return '"hidden" must be a function, string, or boolean', position + end + end + if kind == "text" then + if type(options.validate) == "table" then + local t = options.validate + local iTable = nil + for k,v in pairs(t) do + if type(k) == "number" then + if iTable == nil then + iTable = true + elseif not iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + elseif k < 1 or k > #t then + return '"validate" numeric keys must be indexed properly. >= 1 and <= #validate', position + end + else + if iTable == nil then + iTable = false + elseif iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + end + end + if type(v) ~= "string" then + return '"validate" values must all be strings', position + end + end + if options.multiToggle and options.multiToggle ~= true then + return '"multiToggle" must be a boolean or nil if "validate" is a table', position + end + elseif options.validate == "keybinding" then + + else + if type(options.usage) ~= "string" then + return '"usage" must be a string', position + elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return '"validate" must be a string, function, or table', position + end + end + if options.multiToggle and type(options.validate) ~= "table" then + return '"validate" must be a table if "multiToggle" is true', position + end + elseif kind == "range" then + if options.min or options.max then + if type(options.min) ~= "number" then + return '"min" must be a number', position + elseif type(options.max) ~= "number" then + return '"max" must be a number', position + elseif options.min >= options.max then + return '"min" must be less than "max"', position + end + end + if options.step then + if type(options.step) ~= "number" then + return '"step" must be a number', position + elseif options.step < 0 then + return '"step" must be nonnegative', position + end + end + if options.isPercent and options.isPercent ~= true then + return '"isPercent" must either be nil, true, or false', position + end + elseif kind == "toggle" then + if options.map then + if type(options.map) ~= "table" then + return '"map" must be a table', position + elseif type(options.map[true]) ~= "string" then + return '"map[true]" must be a string', position + elseif type(options.map[false]) ~= "string" then + return '"map[false]" must be a string', position + end + end + elseif kind == "color" then + if options.hasAlpha and options.hasAlpha ~= true then + return '"hasAlpha" must be nil, true, or false', position + end + elseif kind == "group" then + if options.pass and options.pass ~= true then + return '"pass" must be nil, true, or false', position + end + if type(options.args) ~= "table" then + return '"args" must be a table', position + end + for k,v in pairs(options.args) do + if type(k) ~= "number" then + if type(k) ~= "string" then + return '"args" keys must be strings or numbers', position + elseif k:len() == 0 then + return '"args" keys must not be 0-length strings.', position + end + end + if type(v) ~= "table" then + if type(k) == "number" then + return '"args" values must be tables', position and position .. "[" .. k .. "]" or "[" .. k .. "]" + else + return '"args" values must be tables', position and position .. "." .. k or k + end + end + local newposition + if type(k) == "number" then + newposition = position and position .. ".args[" .. k .. "]" or "args[" .. k .. "]" + else + newposition = position and position .. ".args." .. k or "args." .. k + end + local err, pos = validateOptions(v, newposition, baseOptions, options.pass) + if err then + return err, pos + end + end + elseif kind == "execute" then + if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then + return '"confirm" must be a string, boolean, or nil', position + end + end +end + +local colorTable +local colorFunc +local colorCancelFunc + +local function keybindingValidateFunc(text) + if text == nil or text == "NONE" then + return nil + end + text = text:upper() + local shift, ctrl, alt + local modifier + while true do + if text == "-" then + break + end + modifier, text = strsplit('-', text, 2) + if text then + if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then + return false + end + if modifier == "SHIFT" then + if shift then + return false + end + shift = true + end + if modifier == "CTRL" then + if ctrl then + return false + end + ctrl = true + end + if modifier == "ALT" then + if alt then + return false + end + alt = true + end + else + text = modifier + break + end + end + if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then + return false + end + local s = text + if shift then + s = "SHIFT-" .. s + end + if ctrl then + s = "CTRL-" .. s + end + if alt then + s = "ALT-" .. s + end + return s +end +AceConsole.keybindingValidateFunc = keybindingValidateFunc + +local order + +local mysort_args +local mysort + +local function icaseSort(alpha, bravo) + if type(alpha) == "number" and type(bravo) == "number" then + return alpha < bravo + end + return tostring(alpha):lower() < tostring(bravo):lower() +end + +local tmp = {} +local function printUsage(self, handler, realOptions, options, path, args, passValue, quiet, filter) + if filter then + filter = "^" .. filter:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + end + local hidden, disabled = options.cmdHidden or options.hidden, options.disabled + if hidden then + if type(hidden) == "function" then + hidden = hidden(options.passValue) + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + hidden = handler[f](handler, options.passValue) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled(options.passValue) + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + disabled = handler[f](handler, options.passValue) + if neg then + disabled = not disabled + end + end + end + local kind = (options.type or "group"):lower() + if disabled then + print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self) + elseif kind == "text" then + local var + local multiToggle + for k in pairs(tmp) do + tmp[k] = nil + end + if passTable then + multiToggle = passTable.multiToggle + if not passTable.get then + elseif type(passTable.get) == "function" then + if not multiToggle then + var = passTable.get(passValue) + else + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + var[val] = passTable.get(val) or nil + else + var[val] = passTable.get(passValue, val) or nil + end + end + end + else + local handler = passTable.handler or handler + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get))) + end + var = handler[passTable.get](handler, passValue) + if not multiToggle then + var = handler[passTable.get](handler, passValue) + else + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + var[val] = handler[passTable.get](handler, val) or nil + else + var[val] = handler[passTable.get](handler, passValue, val) or nil + end + end + end + end + else + multiToggle = options.multiToggle + if not options.get then + elseif type(options.get) == "function" then + if not multiToggle then + var = options.get(passValue) + else + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + var[val] = options.get(val) or nil + else + var[val] = options.get(passValue, val) or nil + end + end + end + else + local handler = options.handler or handler + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get))) + end + if not multiToggle then + var = handler[options.get](handler, passValue) + else + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + var[val] = handler[options.get](handler, val) or nil + else + var[val] = handler[options.get](handler, passValue, val) or nil + end + end + end + end + end + + local usage + if type(options.validate) == "table" then + if filter then + if not order then + order = {} + end + for k,v in pairs(options.validate) do + if v:find(filter) then + table.insert(order, v) + end + end + table.sort(order, icaseSort) + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + else + if not order then + order = {} + end + for k,v in pairs(options.validate) do + table.insert(order, v) + end + table.sort(order, icaseSort) + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + end + if multiToggle then + if not next(var) then + var = NONE + else + if not order then + order = {} + end + for k in pairs(var) do + if options.validate[k] then + order[#order+1] = options.validate[k] + else + for _,v in pairs(options.validate) do + if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then + order[#order+1] = v + break + end + end + end + end + table.sort(order, icaseSort) + var = table.concat(order, ", ") + for k in pairs(order) do + order[k] = nil + end + end + else + var = options.validate[var] or var + end + elseif options.validate == "keybinding" then + usage = KEYBINDING_USAGE + else + usage = options.usage or "<value>" + end + if not quiet then + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self) + end + if (passTable and passTable.get) or options.get then + print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE))) + end + elseif kind == "range" then + local var + if passTable then + if type(passTable.get) == "function" then + var = passTable.get(passValue) + else + local handler = passTable.handler or handler + if type(handler[passTable.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(passTable.get))) + end + var = handler[passTable.get](handler, passValue) + end + else + if type(options.get) == "function" then + var = options.get(passValue) + else + local handler = options.handler or handler + if type(handler[options.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.get))) + end + var = handler[options.get](handler, passValue) + end + end + + local usage + local min = options.min or 0 + local max = options.max or 1 + if options.isPercent then + min, max = min * 100, max * 100 + var = tostring(var * 100) .. "%" + end + local bit = "-" + if min < 0 or max < 0 then + bit = " - " + end + usage = ("(%s%s%s)"):format(min, bit, max) + if not quiet then + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage), realOptions.cmdName or realOptions.name or self) + end + print((options.current or IS_CURRENTLY_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE))) + elseif kind == "group" then + local usage + if next(options.args) then + if not order then + order = {} + end + for k,v in pairs(options.args) do + if v.type ~= "header" then + local hidden = v.cmdHidden or v.hidden + if hidden then + if type(hidden) == "function" then + hidden = hidden() + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + hidden = handler[f](handler) + if neg then + hidden = not hidden + end + end + end + if not hidden then + if filter then + if k:find(filter) then + table.insert(order, k) + elseif type(v.aliases) == "table" then + for _,bit in ipairs(v.aliases) do + if bit:find(filter) then + table.insert(order, k) + break + end + end + elseif type(v.aliases) == "string" then + if v.aliases:find(filter) then + table.insert(order, k) + end + end + else + table.insert(order, k) + end + end + end + end + if not mysort then + mysort = function(a, b) + local alpha, bravo = mysort_args[a], mysort_args[b] + local alpha_order = alpha and alpha.order or 100 + local bravo_order = bravo and bravo.order or 100 + if alpha_order == bravo_order then + return tostring(a):lower() < tostring(b):lower() + else + if alpha_order < 0 then + if bravo_order > 0 then + return false + end + else + if bravo_order < 0 then + return true + end + end + if alpha_order > 0 and bravo_order > 0 then + return tostring(a):lower() < tostring(b):lower() + end + return alpha_order < bravo_order + end + end + end + mysort_args = options.args + table.sort(order, mysort) + mysort_args = nil + if not quiet then + if options == realOptions then + if options.desc then + print(tostring(options.desc), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}")) + elseif self.description or self.notes then + print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}")) + else + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + end + else + if options.desc then + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + print(tostring(options.desc)) + else + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) + end + end + end + local passTable = options.pass and options or nil + for _,k in ipairs(order) do + local passValue = passTable and k or nil + local real_k = k + local v = options.args[k] + if v then + local v_p = passTable or v + if v.get and v.set then + v_p = v + passValue = nil + end + if v.passValue then + passValue = v.passValue + end + local k = tostring(k):gsub("%s", "-") + local disabled = v.disabled + if disabled then + if type(disabled) == "function" then + disabled = disabled(passValue) + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + disabled = handler[f](handler, passValue) + if neg then + disabled = not disabled + end + end + end + if type(v.aliases) == "table" then + for _,s in ipairs(v.aliases) do + k = k .. " || " .. s:gsub("%s", "-") + end + elseif type(v.aliases) == "string" then + k = k .. " || " .. v.aliases:gsub("%s", "-") + end + if v_p.get then + local a1,a2,a3,a4 + local multiToggle = v_p.type == "text" and v_p.multiToggle + for k in pairs(tmp) do + tmp[k] = nil + end + if type(v_p.get) == "function" then + if multiToggle then + a1 = tmp + for k,v in pairs(v.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + a1[val] = v_p.get(val) or nil + else + a1[val] = v_p.get(passValue, val) or nil + end + end + else + a1,a2,a3,a4 = v_p.get(passValue) + end + else + local handler = v_p.handler or handler + local f = v_p.get + local neg + if v.type == "toggle" then + neg = f:match("^~(.-)$") + if neg then + f = neg + end + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + if multiToggle then + a1 = tmp + for k,v in pairs(v.validate) do + local val = type(k) ~= "number" and k or v + if passValue == nil then + a1[val] = handler[f](handler, val) or nil + else + a1[val] = handler[f](handler, passValue, val) or nil + end + end + else + a1,a2,a3,a4 = handler[f](handler, passValue) + end + if neg then + a1 = not a1 + end + end + local s + if v.type == "color" then + if v.hasAlpha then + if not a1 or not a2 or not a3 or not a4 then + s = NONE + else + s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a4*255, a1*255, a2*255, a3*255, a4*255, a1*255, a2*255, a3*255) + end + else + if not a1 or not a2 or not a3 then + s = NONE + else + s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(a1*255, a2*255, a3*255, a1*255, a2*255, a3*255) + end + end + elseif v.type == "toggle" then + if v.map then + s = tostring(v.map[a1 and true or false] or NONE) + else + s = tostring(MAP_ONOFF[a1 and true or false] or NONE) + end + elseif v.type == "range" then + if v.isPercent then + s = tostring(a1 * 100) .. "%" + else + s = tostring(a1) + end + elseif v.type == "text" and type(v.validate) == "table" then + if multiToggle then + if not next(a1) then + s = NONE + else + s = '' + for k in pairs(a1) do + if v.validate[k] then + if s == '' then + s = v.validate[k] + else + s = s .. ', ' .. v.validate[k] + end + else + for _,u in pairs(v.validate) do + if u == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then + if s == '' then + s = u + else + s = s .. ', ' .. u + end + break + end + end + end + end + end + else + s = tostring(v.validate[a1] or a1 or NONE) + end + else + s = tostring(a1 or NONE) + end + if disabled then + local s = s:gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + print(("|cffcfcfcf - %s: [%s] %s|r"):format(k, s, desc)) + else + print((" - |cffffff7f%s: [|r%s|cffffff7f]|r %s"):format(k, s, v.desc or NONE)) + end + else + if disabled then + local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") + print(("|cffcfcfcf - %s: %s"):format(k, desc)) + else + print((" - |cffffff7f%s:|r %s"):format(k, v.desc or NONE)) + end + end + end + end + for k in pairs(order) do + order[k] = nil + end + else + if options.desc then + print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self) + print(tostring(options.desc)) + elseif options == realOptions and (self.description or self.notes) then + print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s"):format(USAGE, path)) + else + print(("|cffffff7f%s:|r %s"):format(USAGE, path), realOptions.cmdName or realOptions.name or self) + end + print(NO_OPTIONS_AVAILABLE) + end + end +end + +local function confirmPopup(message, func, ...) + if not StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] then + StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] = {} + end + local t = StaticPopupDialogs["ACECONSOLE20_CONFIRM_DIALOG"] + for k in pairs(t) do + t[k] = nil + end + t.text = message + t.button1 = ACCEPT or "Accept" + t.button2 = CANCEL or "Cancel" + t.OnAccept = function() + func(unpack(t)) + end + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + t.timeout = 0 + t.whileDead = 1 + t.hideOnEscape = 1 + + StaticPopup_Show("ACECONSOLE20_CONFIRM_DIALOG") +end + +local function handlerFunc(self, chat, msg, options) + if not msg then + msg = "" + else + msg = msg:gsub("^%s*(.-)%s*$", "%1") + msg = msg:gsub("%s+", " ") + end + + local realOptions = options + local options, path, args, handler, passTable, passValue = findTableLevel(self, options, chat, msg) + if options.type == "execute" then + if options.func then + passTable = nil + end + else + if options.get and options.set then + passTable = nil + end + end + passValue = options.passValue or passTable and passValue + + local hidden, disabled = options.cmdHidden or options.hidden, options.disabled + if hidden then + if type(hidden) == "function" then + hidden = hidden(passValue) + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + hidden = handler[f](handler, passValue) + if neg then + hidden = not hidden + end + end + end + if hidden then + disabled = true + elseif disabled then + if type(disabled) == "function" then + disabled = disabled(passValue) + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + disabled = handler[f](handler, passValue) + if neg then + disabled = not disabled + end + end + end + local _G_this = this + local kind = (options.type or "group"):lower() + local options_p = passTable or options + if disabled then + print(OPTION_IS_DISABLED:format(path), realOptions.cmdName or realOptions.name or self) + elseif kind == "text" then + if #args > 0 then + if (type(options.validate) == "table" and #args > 1) or (type(options.validate) ~= "table" and not options.input) then + local arg = table.concat(args, " ") + for k,v in pairs(args) do + args[k] = nil + end + args[1] = arg + end + if options.validate then + local good + if type(options.validate) == "function" then + good = options.validate(unpack(args)) + elseif type(options.validate) == "table" then + local arg = args[1] + arg = tostring(arg):lower() + for k,v in pairs(options.validate) do + if v:lower() == arg then + args[1] = type(k) == "string" and k or v + good = true + break + end + end + if not good and type((next(options.validate))) == "string" then + for k,v in pairs(options.validate) do + if type(k) == "string" and k:lower() == arg then + args[1] = k + good = true + break + end + end + end + elseif options.validate == "keybinding" then + good = keybindingValidateFunc(unpack(args)) + if good ~= false then + args[1] = good + end + else + if type(handler[options.validate]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options.validate))) + end + good = handler[options.validate](handler, unpack(args)) + end + if not good then + local usage + if type(options.validate) == "table" then + if not order then + order = {} + end + for k,v in pairs(options.validate) do + table.insert(order, v) + end + usage = "{" .. table.concat(order, " || ") .. "}" + for k in pairs(order) do + order[k] = nil + end + elseif options.validate == "keybinding" then + usage = KEYBINDING_USAGE + else + usage = options.usage or "<value>" + end + print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(tostring(table.concat(args, " ")), path), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage)) + return + end + end + + local var + local multiToggle + for k in pairs(tmp) do + tmp[k] = nil + end + multiToggle = options_p.multiToggle + if not options_p.get then + elseif type(options_p.get) == "function" then + if multiToggle then + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue then + var[val] = options_p.get(passValue, val) or nil + else + var[val] = options_p.get(val) or nil + end + end + else + var = options_p.get(passValue) + end + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + if multiToggle then + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue then + var[val] = handler[options_p.get](handler, passValue, val) or nil + else + var[val] = handler[options_p.get](handler, val) or nil + end + end + else + var = handler[options_p.get](handler, passValue) + end + end + + if multiToggle or var ~= args[1] then + if multiToggle then + local current = var[args[1]] + if current == nil and type(args[1]) == "string" then + for k in pairs(var) do + if type(k) == "string" and k:lower() == args[1]:lower() then + current = true + break + end + end + end + args[2] = not current + end + if type(options_p.set) == "function" then + if passValue then + options_p.set(passValue, unpack(args)) + else + options_p.set(unpack(args)) + end + else + if type(handler[options_p.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) + end + if passValue then + handler[options_p.set](handler, passValue, unpack(args)) + else + handler[options_p.set](handler, unpack(args)) + end + end + end + end + + if #args > 0 then + local var + local multiToggle + for k in pairs(tmp) do + tmp[k] = nil + end + multiToggle = options_p.multiToggle + if not options_p.get then + elseif type(options_p.get) == "function" then + if multiToggle then + var = tmp + for k,v in pairs(options_p.validate) do + local val = type(k) ~= "number" and k or v + if passValue then + var[val] = options_p.get(passValue, val) or nil + else + var[val] = options_p.get(val) or nil + end + end + else + var = options_p.get(passValue) + end + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + if multiToggle then + var = tmp + for k,v in pairs(options.validate) do + local val = type(k) ~= "number" and k or v + if passValue then + var[val] = handler[options_p.get](handler, passValue, val) or nil + else + var[val] = handler[options_p.get](handler, val) or nil + end + end + else + var = handler[options_p.get](handler, passValue) + end + end + if multiToggle then + if not next(var) then + var = NONE + else + if not order then + order = {} + end + for k in pairs(var) do + if options.validate[k] then + order[#order+1] = options.validate[k] + else + for _,v in pairs(options.validate) do + if v == k or (type(v) == "string" and type(k) == "string" and v:lower() == k:lower()) then + order[#order+1] = v + break + end + end + end + end + table.sort(order, icaseSort) + var = table.concat(order, ", ") + for k in pairs(order) do + order[k] = nil + end + end + elseif type(options.validate) == "table" then + var = options.validate[var] or var + end + if options_p.get then + print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) + end + if var == args[1] then + return + end + else + printUsage(self, handler, realOptions, options, path, args, passValue) + return + end + elseif kind == "execute" then + local confirm = options.confirm + if confirm == true then + confirm = DEFAULT_CONFIRM_MESSAGE:format(options.desc or options.name or UNKNOWN or "Unknown") + end + if type(options_p.func) == "function" then + if confirm then + confirmPopup(confirm, options_p.func, passValue) + else + options_p.func(passValue) + end + else + if type(handler[options_p.func]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.func))) + end + if confirm then + confirmPopup(confirm, handler[options_p.func], handler, passValue) + else + handler[options_p.func](handler, passValue) + end + end + elseif kind == "toggle" then + local var + if type(options_p.get) == "function" then + var = options_p.get(passValue) + else + local f = options_p.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + var = handler[f](handler, passValue) + if neg then + var = not var + end + end + if type(options_p.set) == "function" then + if passValue then + options_p.set(passValue, not var) + else + options_p.set(not var) + end + else + if type(handler[options_p.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) + end + if passValue then + handler[options_p.set](handler, passValue, not var) + else + handler[options_p.set](handler, not var) + end + end + if type(options_p.get) == "function" then + var = options_p.get(passValue) + else + local f = options_p.get + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + var = handler[f](handler, passValue) + if neg then + var = not var + end + end + + print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), (options.map or MAP_ONOFF)[var and true or false] or NONE), realOptions.cmdName or realOptions.name or self) + elseif kind == "range" then + local arg + if #args <= 1 then + arg = args[1] + else + arg = table.concat(args, " ") + end + + if arg then + local min = options.min or 0 + local max = options.max or 1 + local good = false + if type(arg) == "number" then + if options.isPercent then + arg = arg / 100 + end + + if arg >= min and arg <= max then + good = true + end + + if good and type(options.step) == "number" and options.step > 0 then + local step = options.step + arg = math.floor((arg - min) / step + 0.5) * step + min + if arg > max then + arg = max + elseif arg < min then + arg = min + end + end + end + if not good then + local usage + local min = options.min or 0 + local max = options.max or 1 + if options.isPercent then + min, max = min * 100, max * 100 + end + local bit = "-" + if min < 0 or max < 0 then + bit = " - " + end + usage = ("(%s%s%s)"):format(min, bit, max) + print((options.error or IS_NOT_A_VALID_VALUE_FOR):format(tostring(arg), path), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s %s"):format(USAGE, path, usage)) + return + end + + local var + if type(options_p.get) == "function" then + var = options_p.get(passValue) + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + var = handler[options_p.get](handler, passValue) + end + + if var ~= arg then + if type(options_p.set) == "function" then + if passValue then + options_p.set(passValue, arg) + else + options_p.set(arg) + end + else + if type(handler[options_p.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) + end + if passValue then + handler[options_p.set](handler, passValue, arg) + else + handler[options_p.set](handler, arg) + end + end + end + end + + if arg then + local var + if type(options_p.get) == "function" then + var = options_p.get(passValue) + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + var = handler[options_p.get](handler, passValue) + end + + if var and options.isPercent then + var = tostring(var * 100) .. "%" + end + print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) + if var == arg then + return + end + else + printUsage(self, handler, realOptions, options, path, args, passValue) + return + end + elseif kind == "color" then + if #args > 0 then + local r,g,b,a + if #args == 1 then + local arg = tostring(args[1]) + if options.hasAlpha then + if arg:len() == 8 and arg:find("^%x*$") then + r,g,b,a = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255, tonumber(arg:sub(7, 8), 16) / 255 + end + else + if arg:len() == 6 and arg:find("^%x*$") then + r,g,b = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255 + end + end + elseif #args == 4 and options.hasAlpha then + local a1,a2,a3,a4 = args[1], args[2], args[3], args[4] + if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and type(a4) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 and a4 <= 1 then + r,g,b,a = a1,a2,a3,a4 + elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") and (type(a4) == "number" or a4:len() == 2) and a4:find("^%x*$") then + r,g,b,a = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255, tonumber(a4, 16) / 255 + end + elseif #args == 3 and not options.hasAlpha then + local a1,a2,a3 = args[1], args[2], args[3] + if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 then + r,g,b = a1,a2,a3 + elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") then + r,g,b = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255 + end + end + if not r then + print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(table.concat(args, ' '), path), realOptions.cmdName or realOptions.name or self) + print(("|cffffff7f%s:|r %s {0-1} {0-1} {0-1}%s"):format(USAGE, path, options.hasAlpha and " {0-1}" or "")) + return + end + + if type(options_p.set) == "function" then + if passValue then + options_p.set(passValue, r,g,b,a) + else + options_p.set(r,g,b,a) + end + else + if type(handler[options_p.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.set))) + end + if passValue then + handler[options_p.set](handler, passValue, r,g,b,a) + else + handler[options_p.set](handler, r,g,b,a) + end + end + + local r,g,b,a + if type(options_p.get) == "function" then + r,g,b,a = options_p.get(passValue) + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + r,g,b,a = handler[options_p.get](handler, passValue) + end + + local s + if type(r) == "number" and type(g) == "number" and type(b) == "number" then + if options.hasAlpha and type(a) == "number" then + s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) + else + s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255) + end + else + s = NONE + end + print((options.message or IS_NOW_SET_TO):format(tostring(options.cmdName or options.name), s), realOptions.cmdName or realOptions.name or self) + else + local r,g,b,a + if type(options_p.get) == "function" then + r,g,b,a = options_p.get(passValue) + else + if type(handler[options_p.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(options_p.get))) + end + r,g,b,a = handler[options_p.get](handler, passValue) + end + + if not colorTable then + colorTable = {} + local t = colorTable + + if ColorPickerOkayButton then + local ColorPickerOkayButton_OnClick = ColorPickerOkayButton:GetScript("OnClick") + ColorPickerOkayButton:SetScript("OnClick", function() + if ColorPickerOkayButton_OnClick then + ColorPickerOkayButton_OnClick() + end + if t.active then + ColorPickerFrame.cancelFunc = nil + ColorPickerFrame.func = nil + ColorPickerFrame.opacityFunc = nil + local r,g,b,a + if t.passValue then + if type(t.get) == "function" then + r,g,b,a = t.get(t.passValue) + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) + end + r,g,b,a = t.handler[t.get](t.handler, t.passValue) + end + else + if type(t.get) == "function" then + r,g,b,a = t.get() + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) + end + r,g,b,a = t.handler[t.get](t.handler) + end + end + if r ~= t.r or g ~= t.g or b ~= t.b or (t.hasAlpha and a ~= t.a) then + local s + if type(r) == "number" and type(g) == "number" and type(b) == "number" then + if t.hasAlpha and type(a) == "number" then + s = ("|c%02x%02x%02x%02x%02x%02x%02x%02x|r"):format(a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) + else + s = ("|cff%02x%02x%02x%02x%02x%02x|r"):format(r*255, g*255, b*255, r*255, g*255, b*255) + end + else + s = NONE + end + print(t.message:format(tostring(t.name), s), t.realOptions.cmdName or t.realOptions.name or self) + end + for k,v in pairs(t) do + t[k] = nil + end + end + end) + end + else + for k,v in pairs(colorTable) do + colorTable[k] = nil + end + end + + if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then + r,g,b = 1, 1, 1 + end + if type(a) ~= "number" then + a = 1 + end + local t = colorTable + t.r = r + t.g = g + t.b = b + if hasAlpha then + t.a = a + end + t.realOptions = realOptions + t.hasAlpha = options.hasAlpha + t.handler = handler + t.set = options_p.set + t.get = options_p.get + t.name = options.cmdName or options.name + t.message = options.message or IS_NOW_SET_TO + t.passValue = passValue + t.active = true + + if not colorFunc then + colorFunc = function() + local r,g,b = ColorPickerFrame:GetColorRGB() + if t.hasAlpha then + local a = 1 - OpacitySliderFrame:GetValue() + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, r,g,b,a) + else + t.set(r,g,b,a) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, r,g,b,a) + else + t.handler[t.set](t.handler, r,g,b,a) + end + end + else + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, r,g,b) + else + t.set(r,g,b) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, r,g,b) + else + t.handler[t.set](t.handler, r,g,b) + end + end + end + end + end + + ColorPickerFrame.func = colorFunc + ColorPickerFrame.hasOpacity = options.hasAlpha + if options.hasAlpha then + ColorPickerFrame.opacityFunc = ColorPickerFrame.func + ColorPickerFrame.opacity = 1 - a + end + ColorPickerFrame:SetColorRGB(r,g,b) + + if not colorCancelFunc then + colorCancelFunc = function() + if t.hasAlpha then + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, t.r,t.g,t.b,t.a) + else + t.set(t.r,t.g,t.b,t.a) + end + else + if type(t.handler[t.get]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.get))) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b,t.a) + else + t.handler[t.set](t.handler, t.r,t.g,t.b,t.a) + end + end + else + if type(t.set) == "function" then + if t.passValue then + t.set(t.passValue, t.r,t.g,t.b) + else + t.set(t.r,t.g,t.b) + end + else + if type(t.handler[t.set]) ~= "function" then + AceConsole:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(t.set))) + end + if t.passValue then + t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b) + else + t.handler[t.set](t.handler, t.r,t.g,t.b) + end + end + end + for k,v in pairs(t) do + t[k] = nil + end + ColorPickerFrame.cancelFunc = nil + ColorPickerFrame.func = nil + ColorPickerFrame.opacityFunc = nil + end + end + + ColorPickerFrame.cancelFunc = colorCancelFunc + + ShowUIPanel(ColorPickerFrame) + end + return + elseif kind == "group" then + if #args == 0 then + printUsage(self, handler, realOptions, options, path, args, passValue) + else + -- invalid argument + print((options.error or IS_NOT_A_VALID_OPTION_FOR):format(args[1], path), realOptions.cmdName or realOptions.name or self) + end + return + end + this = _G_this + if Dewdrop then + Dewdrop:Refresh() + end +end + +local external +local tmp +function AceConsole:RegisterChatCommand(...) -- slashCommands, options, name + local slashCommands, options, name + if type((...)) == "string" then + if not tmp then + tmp = {} + else + for i in ipairs(tmp) do + tmp[i] = nil + end + end + for i = 1, select('#', ...)+1 do + local v = select(i, ...) + if type(v) == "string" then + tmp[#tmp+1] = v + else + slashCommands = tmp + options = v + name = select(i+1, ...) + break + end + end + else + slashCommands, options, name = ... + end + if type(slashCommands) ~= "table" and slashCommands ~= false then + AceConsole:error("Bad argument #2 to `RegisterChatCommand' (expected table, got %s)", type(slashCommands)) + end + if not slashCommands and type(name) ~= "string" then + AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string, got %s)", type(name)) + end + if type(options) ~= "table" and type(options) ~= "function" and options ~= nil then + AceConsole:error("Bad argument #3 to `RegisterChatCommand' (expected table, function, or nil, got %s)", type(options)) + end + if name then + if type(name) ~= "string" then + AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string or nil, got %s)", type(name)) + elseif not name:find("^%w+$") or name:upper() ~= name or name:len() == 0 then + AceConsole:error("Argument #4 must be an uppercase, letters-only string with at least 1 character") + end + end + if slashCommands then + if #slashCommands == 0 then + AceConsole:error("Argument #2 to `RegisterChatCommand' must include at least one string") + end + + for k,v in pairs(slashCommands) do + if type(k) ~= "number" then + AceConsole:error("All keys in argument #2 to `RegisterChatCommand' must be numbers") + end + if type(v) ~= "string" then + AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be strings") + elseif not v:find("^/[A-Za-z][A-Za-z0-9_]*$") then + AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be in the form of \"/word\"") + end + end + end + + if not options then + options = { + type = 'group', + args = {}, + handler = self + } + end + + if type(options) == "table" then + local err, position = validateOptions(options) + if err then + if position then + AceConsole:error(position .. ": " .. err) + else + AceConsole:error(err) + end + end + + if not options.handler then + options.handler = self + end + + if options.handler == self and options.type:lower() == "group" and self.class then + AceConsole:InjectAceOptionsTable(self, options) + end + end + + local chat + if slashCommands then + chat = slashCommands[1] + else + chat = _G["SLASH_"..name..1] + end + + local handler + if type(options) == "function" then + handler = options + for k,v in pairs(_G) do + if handler == v then + local k = k + handler = function(msg) + return _G[k](msg) + end + end + end + else + function handler(msg) + handlerFunc(self, chat, msg, options) + end + end + + if not _G.SlashCmdList then + _G.SlashCmdList = {} + end + + if not name and type(slashCommands) == "table" and type(slashCommands[1]) == "string" then + name = slashCommands[1]:gsub("%A", ""):upper() + end + + if not name then + local A = ('A'):byte() + repeat + name = string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) + until not _G.SlashCmdList[name] + end + + if slashCommands then + if _G.SlashCmdList[name] then + local i = 0 + while true do + i = i + 1 + if _G["SLASH_"..name..i] then + _G["SLASH_"..name..i] = nil + else + break + end + end + end + + local i = 0 + for _,command in ipairs(slashCommands) do + i = i + 1 + _G["SLASH_"..name..i] = command + if command:lower() ~= command then + i = i + 1 + _G["SLASH_"..name..i] = command:lower() + end + end + end + _G.SlashCmdList[name] = handler + if self ~= AceConsole and self.slashCommand == nil then + self.slashCommand = chat + end + + if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then + external(AceConsole, "AceEvent-2.0", AceLibrary("AceEvent-2.0")) + end + if AceEvent then + if not AceConsole.nextAddon then + AceConsole.nextAddon = {} + end + if type(options) == "table" then + AceConsole.nextAddon[self] = options + if not self.playerLogin then + AceConsole:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) + end + end + end + + AceConsole.registry[name] = options + + if slashCommands == tmp then + for i in ipairs(tmp) do + tmp[i] = nil + end + end +end + +function AceConsole:InjectAceOptionsTable(handler, options) + self:argCheck(handler, 2, "table") + self:argCheck(options, 3, "table") + if options.type:lower() ~= "group" then + self:error('Cannot inject into options table argument #3 if its type is not "group"') + end + if options.handler ~= nil and options.handler ~= handler then + self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") + end + options.handler = handler + local class = handler.class + if not AceLibrary:HasInstance("AceOO-2.0") or not class then + if Rock then + -- possible Rock object + for mixin in Rock:IterateObjectMixins(handler) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + else + -- Ace2 object + while class and class ~= AceLibrary("AceOO-2.0").Class do + if type(class.GetAceOptionsDataTable) == "function" then + local t = class:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + local mixins = class.mixins + if mixins then + for mixin in pairs(mixins) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + class = class.super + end + end + + return options +end + +function AceConsole:PLAYER_LOGIN() + self.playerLogin = true + for addon, options in pairs(self.nextAddon) do + local err, position = validateOptionsMethods(addon, options) + if err then + if position then + geterrorhandler()(tostring(addon) .. ": AceConsole: " .. position .. ": " .. err) + else + geterrorhandler()(tostring(addon) .. ": AceConsole: " .. err) + end + end + self.nextAddon[addon] = nil + end +end + +function AceConsole:TabCompleteInfo(cmdpath) + local cmd = cmdpath:match("(/%S+)") + if not cmd then + return + end + local path = cmdpath:sub(cmd:len() + 2) + for name in pairs(SlashCmdList) do --global + if AceConsole.registry[name] then + local i = 0 + while true do + i = i + 1 + local scmd = _G["SLASH_"..name..i] + if not scmd then break end + if cmd == scmd then + return name, cmd, path + end + end + end + end +end + +function external(self, major, instance) + if major == "AceEvent-2.0" then + if not AceEvent then + AceEvent = instance + + AceEvent:embed(self) + end + elseif major == "AceTab-2.0" then + instance:RegisterTabCompletion("AceConsole", "%/.*", function(t, cmdpath, pos) + local name, cmd, path = self:TabCompleteInfo(cmdpath:sub(1, pos)) + + if not self.registry[name] then + return false + else + local validArgs, _, _, handler = findTableLevel(self, self.registry[name], cmd, path or "") + if validArgs.args then + for arg, v in pairs(validArgs.args) do + local hidden = v.hidden + local handler = v.handler or handler + if hidden then + if type(hidden) == "function" then + hidden = hidden(v.passValue) + elseif type(hidden) == "string" then + local f = hidden + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + hidden = handler[f](handler, v.passValue) + if neg then + hidden = not hidden + end + end + end + local disabled = hidden or v.disabled + if disabled then + if type(disabled) == "function" then + disabled = disabled(v.passValue) + elseif type(disabled) == "string" then + local f = disabled + local neg = f:match("^~(.-)$") + if neg then + f = neg + end + if type(handler[f]) ~= "function" then + self:error("%s: %s", handler, OPTION_HANDLER_NOT_FOUND:format(tostring(f))) + end + disabled = handler[f](handler, v.passValue) + if neg then + disabled = not disabled + end + end + end + if not hidden and not disabled and v.type ~= "header" then + table.insert(t, (tostring(arg):gsub("%s", "-"))) + end + end + end + end + end, function(u, matches, gcs, cmdpath) + local name, cmd, path = self:TabCompleteInfo(cmdpath) + if self.registry[name] then + local validArgs, path2, argwork, handler = findTableLevel(self, self.registry[name], cmd, path) + printUsage(self, validArgs.handler or handler, self.registry[name], validArgs, path2, argwork, argwork[#argwork], not gcs or gcs ~= "", gcs) + end + end) + elseif major == "Dewdrop-2.0" then + Dewdrop = instance + end +end + +local function activate(self, oldLib, oldDeactivate) + AceConsole = self + + if oldLib then + self.registry = oldLib.registry + self.nextAddon = oldLib.nextAddon + end + + if not self.registry then + self.registry = {} + else + for name,options in pairs(self.registry) do + self:RegisterChatCommand(false, options, name) + end + end + + self:RegisterChatCommand("/reload", "/rl", "/reloadui", ReloadUI, "RELOAD") + self:RegisterChatCommand("/gm", ToggleHelpFrame, "GM") + local t = { "/print", "/echo" } + local _,_,_,enabled,loadable = GetAddOnInfo("DevTools") + if not enabled and not loadable then + table.insert(t, "/dump") + end + self:RegisterChatCommand(t, function(text) + text = text:trim():match("^(.-);*$") + local f, err = loadstring("AceLibrary('AceConsole-2.0'):PrintLiteral(" .. text .. ")") + if not f then + self:Print("|cffff0000Error:|r", err) + else + f() + end + end, "PRINT") + + self:activate(oldLib, oldDeactivate) + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceConsole, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceDB-2.0/AceDB-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,2187 @@ +--[[ +Name: AceDB-2.0 +Revision: $Rev: 46764 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceDB-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0 +Description: Mixin to allow for fast, clean, and featureful saved variable + access. +Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceDB-2.0" +local MINOR_VERSION = "$Revision: 46764 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err) end +end + +local ACTIVE, ENABLED, STATE, TOGGLE_ACTIVE, MAP_ACTIVESUSPENDED, SET_PROFILE, SET_PROFILE_USAGE, PROFILE, PLAYER_OF_REALM, CHOOSE_PROFILE_DESC, CHOOSE_PROFILE_GUI, COPY_PROFILE_DESC, COPY_PROFILE_GUI, OTHER_PROFILE_DESC, OTHER_PROFILE_GUI, OTHER_PROFILE_USAGE, RESET_PROFILE, RESET_PROFILE_DESC, CHARACTER_COLON, REALM_COLON, CLASS_COLON, DEFAULT, ALTERNATIVE + +-- Move these into "enUS" when they've been translated in all other locales +local DELETE_PROFILE = "Delete" +local DELETE_PROFILE_DESC = "Deletes a profile. Note that no check is made whether this profile is in use by other characters or not." +local DELETE_PROFILE_USAGE = "<profile name>" + +if GetLocale() == "deDE" then + ACTIVE = "Aktiv" + ENABLED = "Aktiviert" + STATE = "Status" + TOGGLE_ACTIVE = "Stoppt/Aktiviert dieses Addon." + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Aktiv|r", [false] = "|cffff0000Gestoppt|r" } + SET_PROFILE = "Setzt das Profil f\195\188r dieses Addon." + SET_PROFILE_USAGE = "{Charakter || Klasse || Realm || <Profilname>}" + PROFILE = "Profil" + PLAYER_OF_REALM = "%s von %s" + CHOOSE_PROFILE_DESC = "W\195\164hle ein Profil." + CHOOSE_PROFILE_GUI = "W\195\164hle" + COPY_PROFILE_DESC = "Kopiert Einstellungen von einem anderem Profil." + COPY_PROFILE_GUI = "Kopiere von" + OTHER_PROFILE_DESC = "W\195\164hle ein anderes Profil." + OTHER_PROFILE_GUI = "Anderes" + OTHER_PROFILE_USAGE = "<Profilname>" + RESET_PROFILE = "Reset profile" -- fix + RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix + + CHARACTER_COLON = "Charakter: " + REALM_COLON = "Realm: " + CLASS_COLON = "Klasse: " + + DEFAULT = "Default" -- fix + ALTERNATIVE = "Alternative" -- fix +elseif GetLocale() == "frFR" then + ACTIVE = "Actif" + ENABLED = "Activ\195\169" + STATE = "Etat" + TOGGLE_ACTIVE = "Suspend/active cet addon." + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Actif|r", [false] = "|cffff0000Suspendu|r" } + SET_PROFILE = "S\195\169lectionne le profil pour cet addon." + SET_PROFILE_USAGE = "{perso || classe || royaume || <nom de profil>}" + PROFILE = "Profil" + PLAYER_OF_REALM = "%s de %s" + CHOOSE_PROFILE_DESC = "Choisissez un profil." + CHOOSE_PROFILE_GUI = "Choix" + COPY_PROFILE_DESC = "Copier les param\195\168tres d'un autre profil." + COPY_PROFILE_GUI = "Copier \195\160 partir de" + OTHER_PROFILE_DESC = "Choisissez un autre profil." + OTHER_PROFILE_GUI = "Autre" + OTHER_PROFILE_USAGE = "<nom de profil>" + RESET_PROFILE = "Reset profile" -- fix + RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix + + CHARACTER_COLON = "Personnage: " + REALM_COLON = "Royaume: " + CLASS_COLON = "Classe: " + + DEFAULT = "Default" -- fix + ALTERNATIVE = "Alternative" -- fix +elseif GetLocale() == "koKR" then + DELETE_PROFILE = "삭제" + DELETE_PROFILE_DESC = "프로필을 삭제합니다." + DELETE_PROFILE_USAGE = "<프로필명>" + + ACTIVE = "사용" + ENABLED = "사용" + STATE = "상태" + TOGGLE_ACTIVE = "이 애드온 중지/다시 시작" + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00사용|r", [false] = "|cffff0000중지|r" } + SET_PROFILE = "이 애드온에 프로필 설정" + SET_PROFILE_USAGE = "{캐릭터명 || 직업 || 서버명 || <프로필명>}" + PROFILE = "프로필" + PLAYER_OF_REALM = "%s (%s 서버)" + CHOOSE_PROFILE_DESC = "프로필을 선택합니다." + CHOOSE_PROFILE_GUI = "선택" + COPY_PROFILE_DESC = "다른 프로필 설정을 복사합니다." + COPY_PROFILE_GUI = "복사" + OTHER_PROFILE_DESC = "다른 프로필을 선택합니다." + OTHER_PROFILE_GUI = "기타" + OTHER_PROFILE_USAGE = "<프로필명>" + RESET_PROFILE = "프로필 초기화" + RESET_PROFILE_DESC = "모든 세팅에서 현재 프로필을 초기화 합니다." + + CHARACTER_COLON = "캐릭터: " + REALM_COLON = "서버: " + CLASS_COLON = "직업: " + + DEFAULT = "기본값" + ALTERNATIVE = "대체" +elseif GetLocale() == "zhTW" then + DELETE_PROFILE = "刪除" + DELETE_PROFILE_DESC = "刪除記錄檔。注意,有可能別的角色也使用這個記錄檔。" + DELETE_PROFILE_USAGE = "<記錄檔名稱>" + + ACTIVE = "啟動" + ENABLED = "啟用" + STATE = "狀態" + TOGGLE_ACTIVE = "暫停/繼續使用這個插件。" + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00啟動|r", [false] = "|cffff0000已暫停|r" } + SET_PROFILE = "設定這插件的記錄檔。" + SET_PROFILE_USAGE = "{角色 || 職業 || 伺服器 || <記錄檔名稱>}" + PROFILE = "記錄檔" + PLAYER_OF_REALM = "%s - %s" + CHOOSE_PROFILE_DESC = "選擇一個記錄檔。" + CHOOSE_PROFILE_GUI = "選擇" + COPY_PROFILE_DESC = "由其他記錄檔複製設定。" + COPY_PROFILE_GUI = "複製自" + OTHER_PROFILE_DESC = "選擇其他記錄檔。" + OTHER_PROFILE_GUI = "其他" + OTHER_PROFILE_USAGE = "<記錄檔名稱>" + RESET_PROFILE = "重設記錄檔" + RESET_PROFILE_DESC = "清除目前的記錄檔上的所有設定。" + + CHARACTER_COLON = "角色: " + REALM_COLON = "伺服器: " + CLASS_COLON = "職業: " + + DEFAULT = "預設" + ALTERNATIVE = "替代" +elseif GetLocale() == "zhCN" then + ACTIVE = "\230\156\137\230\149\136" + ENABLED = "\229\144\175\231\148\168" + STATE = "\231\138\182\230\128\129" + TOGGLE_ACTIVE = "\230\154\130\229\129\156/\230\129\162\229\164\141 \230\173\164\230\143\146\228\187\182." + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00\230\156\137\230\149\136|r", [false] = "|cffff0000\230\154\130\229\129\156|r" } + SET_PROFILE = "\232\174\190\231\189\174\233\133\141\231\189\174\230\150\135\228\187\182\228\184\186\232\191\153\230\143\146\228\187\182." + SET_PROFILE_USAGE = "{\229\173\151\231\172\166 || \233\128\137\228\187\182\231\177\187 || \229\159\159 || <\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>}" + PROFILE = "\233\133\141\231\189\174\230\150\135\228\187\182" + PLAYER_OF_REALM = "%s \231\154\132 %s" + CHOOSE_PROFILE_DESC = "\233\128\137\230\139\169\233\133\141\231\189\174\230\150\135\228\187\182." + CHOOSE_PROFILE_GUI = "\233\128\137\230\139\169" + COPY_PROFILE_DESC = "\229\164\141\229\136\182\232\174\190\231\189\174\228\187\142\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." + COPY_PROFILE_GUI = "\229\164\141\229\136\182\228\187\142" + OTHER_PROFILE_DESC = "\233\128\137\230\139\169\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." + OTHER_PROFILE_GUI = "\229\133\182\228\187\150" + OTHER_PROFILE_USAGE = "<\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>" + RESET_PROFILE = "Reset profile" -- fix + RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix + + CHARACTER_COLON = "\229\173\151\231\172\166: " + REALM_COLON = "\229\159\159: " + CLASS_COLON = "\233\128\137\228\187\182\231\177\187: " + + DEFAULT = "Default" -- fix + ALTERNATIVE = "Alternative" -- fix +elseif GetLocale() == "esES" then + ACTIVE = "Activo" + ENABLED = "Activado" + STATE = "Estado" + TOGGLE_ACTIVE = "Parar/Continuar este accesorio" + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Activo|r", [false] = "|cffff0000Parado|r" } + SET_PROFILE = "Selecciona el perfil para este accesorio." + SET_PROFILE_USAGE = "{perso || clase || reino || <nombre del perfil>}" + PROFILE = "Perfil" + PLAYER_OF_REALM = "%s de %s" + CHOOSE_PROFILE_DESC = "Elige un perfil." + CHOOSE_PROFILE_GUI = "Elige" + COPY_PROFILE_DESC = "Copiar de un perfil a otro" + COPY_PROFILE_GUI = "Copiar desde" + OTHER_PROFILE_DESC = "Elige otro perfil." + OTHER_PROFILE_GUI = "Otro" + OTHER_PROFILE_USAGE = "<nombre del perfil>" + RESET_PROFILE = "Reset profile" -- fix + RESET_PROFILE_DESC = "Clear all settings of the current profile." -- fix + + CHARACTER_COLON = "Personaje: " + REALM_COLON = "Reino: " + CLASS_COLON = "Clase: " + + DEFAULT = "Por defecto" + ALTERNATIVE = "Alternativo" +else -- enUS + ACTIVE = "Active" + ENABLED = "Enabled" + STATE = "State" + TOGGLE_ACTIVE = "Suspend/resume this addon." + MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" } + SET_PROFILE = "Set profile for this addon." + SET_PROFILE_USAGE = "{char || class || realm || <profile name>}" + PROFILE = "Profile" + PLAYER_OF_REALM = "%s of %s" + CHOOSE_PROFILE_DESC = "Choose a profile." + CHOOSE_PROFILE_GUI = "Choose" + COPY_PROFILE_DESC = "Copy settings from another profile." + COPY_PROFILE_GUI = "Copy from" + OTHER_PROFILE_DESC = "Choose another profile." + OTHER_PROFILE_GUI = "Other" + OTHER_PROFILE_USAGE = "<profile name>" + RESET_PROFILE = "Reset profile" + RESET_PROFILE_DESC = "Clear all settings of the current profile." + + CHARACTER_COLON = "Character: " + REALM_COLON = "Realm: " + CLASS_COLON = "Class: " + + DEFAULT = "Default" + ALTERNATIVE = "Alternative" +end +local convertFromOldCharID +do + local matchStr = "^" .. PLAYER_OF_REALM:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1"):gsub("%%s", "(.+)") .. "$" + function convertFromOldCharID(str) + local player, realm = str:match(matchStr) + if not player then + return str + end + return player .. " - " .. realm + end +end + +local AceOO = AceLibrary("AceOO-2.0") +local AceEvent +local Mixin = AceOO.Mixin +local AceDB = Mixin { + "RegisterDB", + "RegisterDefaults", + "ResetDB", + "SetProfile", + "GetProfile", + "CopyProfileFrom", + "DeleteProfile", + "ToggleActive", + "IsActive", + "AcquireDBNamespace", + } +local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0") + +local _G = getfenv(0) + +local function inheritDefaults(t, defaults) + if not defaults then + return t + end + for k,v in pairs(defaults) do + if k == "*" or k == "**" then + local v = v + if type(v) == "table" then + setmetatable(t, { + __index = function(self, key) + if key == nil then + return nil + end + self[key] = {} + inheritDefaults(self[key], v) + return self[key] + end + } ) + else + setmetatable(t, { + __index = function(self, key) + if key == nil then + return nil + end + self[key] = v + return self[key] + end + } ) + end + for key in pairs(t) do + if (defaults[key] == nil or key == k) and type(t[key]) == "table" then + inheritDefaults(t[key], v) + end + end + else + if type(v) == "table" then + if type(rawget(t, k)) ~= "table" then + t[k] = {} + end + inheritDefaults(t[k], v) + if defaults["**"] then + inheritDefaults(t[k], defaults["**"]) + end + elseif rawget(t, k) == nil then + t[k] = v + end + end + end + return t +end + +local _,race = UnitRace("player") +local faction +if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" or race == "BloodElf" then + faction = FACTION_HORDE +else + faction = FACTION_ALLIANCE +end +local server = GetRealmName():trim() +local charID = UnitName("player") .. " - " .. server +local realmID = server .. " - " .. faction +local classID = UnitClass("player") + +AceDB.CHAR_ID = charID +AceDB.REALM_ID = realmID +AceDB.CLASS_ID = classID + +AceDB.FACTION = faction +AceDB.REALM = server +AceDB.NAME = UnitName("player") + +local new, del +do + local list = setmetatable({}, {__mode="k"}) + function new() + local t = next(list) + if t then + list[t] = nil + return t + else + return {} + end + end + + function del(t) + setmetatable(t, nil) + for k in pairs(t) do + t[k] = nil + end + list[t] = true + end +end + +local caseInsensitive_mt = { + __index = function(self, key) + if type(key) ~= "string" then + return nil + end + local lowerKey = key:lower() + for k,v in pairs(self) do + if k:lower() == lowerKey then + return self[k] + end + end + end, + __newindex = function(self, key, value) + if type(key) ~= "string" then + return error("table index is nil", 2) + end + local lowerKey = key:lower() + for k in pairs(self) do + if k:lower() == lowerKey then + rawset(self, k, nil) + rawset(self, key, value) + return + end + end + rawset(self, key, value) + end +} + +local db_mt = { __index = function(db, key) + if key == "char" then + if db.charName then + if type(_G[db.charName]) ~= "table" then + _G[db.charName] = {} + end + if type(_G[db.charName].global) ~= "table" then + _G[db.charName].global = {} + end + rawset(db, 'char', _G[db.charName].global) + else + if type(db.raw.chars) ~= "table" then + db.raw.chars = {} + end + local id = charID + if type(db.raw.chars[id]) ~= "table" then + db.raw.chars[id] = {} + end + rawset(db, 'char', db.raw.chars[id]) + end + if db.defaults and db.defaults.char then + inheritDefaults(db.char, db.defaults.char) + end + return db.char + elseif key == "realm" then + if type(db.raw.realms) ~= "table" then + db.raw.realms = {} + end + local id = realmID + if type(db.raw.realms[id]) ~= "table" then + db.raw.realms[id] = {} + end + rawset(db, 'realm', db.raw.realms[id]) + if db.defaults and db.defaults.realm then + inheritDefaults(db.realm, db.defaults.realm) + end + return db.realm + elseif key == "server" then + if type(db.raw.servers) ~= "table" then + db.raw.servers = {} + end + local id = server + if type(db.raw.servers[id]) ~= "table" then + db.raw.servers[id] = {} + end + rawset(db, 'server', db.raw.servers[id]) + if db.defaults and db.defaults.server then + inheritDefaults(db.server, db.defaults.server) + end + return db.server + elseif key == "account" then + if type(db.raw.account) ~= "table" then + db.raw.account = {} + end + rawset(db, 'account', db.raw.account) + if db.defaults and db.defaults.account then + inheritDefaults(db.account, db.defaults.account) + end + return db.account + elseif key == "faction" then + if type(db.raw.factions) ~= "table" then + db.raw.factions = {} + end + local id = faction + if type(db.raw.factions[id]) ~= "table" then + db.raw.factions[id] = {} + end + rawset(db, 'faction', db.raw.factions[id]) + if db.defaults and db.defaults.faction then + inheritDefaults(db.faction, db.defaults.faction) + end + return db.faction + elseif key == "class" then + if type(db.raw.classes) ~= "table" then + db.raw.classes = {} + end + local id = classID + if type(db.raw.classes[id]) ~= "table" then + db.raw.classes[id] = {} + end + rawset(db, 'class', db.raw.classes[id]) + if db.defaults and db.defaults.class then + inheritDefaults(db.class, db.defaults.class) + end + return db.class + elseif key == "profile" then + if type(db.raw.profiles) ~= "table" then + db.raw.profiles = setmetatable({}, caseInsensitive_mt) + else + setmetatable(db.raw.profiles, caseInsensitive_mt) + end + local id = db.raw.currentProfile[charID] + if id == "char" then + id = "char/" .. charID + elseif id == "class" then + id = "class/" .. classID + elseif id == "realm" then + id = "realm/" .. realmID + end + if type(db.raw.profiles[id]) ~= "table" then + db.raw.profiles[id] = {} + end + rawset(db, 'profile', db.raw.profiles[id]) + if db.defaults and db.defaults.profile then + inheritDefaults(db.profile, db.defaults.profile) + end + return db.profile + elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then + return nil + end + error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) +end, __newindex = function(db, key, value) + error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) +end } + +local function RecalculateAceDBCopyFromList(target) + local db = target.db + local t = target['acedb-profile-copylist'] + for k,v in pairs(t) do + t[k] = nil + end + local _,currentProfile = AceDB.GetProfile(target) + if db and db.raw then + if db.raw.profiles then + for k in pairs(db.raw.profiles) do + if currentProfile ~= k then + if k:find("^char/") then + local name = k:sub(6) + local player, realm = name:match("^(.*) %- (.*)$") + if player then + name = PLAYER_OF_REALM:format(player, realm) + end + t[k] = CHARACTER_COLON .. name + elseif k:find("^realm/") then + local name = k:sub(7) + t[k] = REALM_COLON .. name + elseif k:find("^class/") then + local name = k:sub(7) + t[k] = CLASS_COLON .. name + else + t[k] = k + end + end + end + end + if db.raw.namespaces then + for _,n in pairs(db.raw.namespaces) do + if n.profiles then + for k in pairs(n.profiles) do + if currentProfile ~= k then + if k:find('^char/') then + local name = k:sub(6) + local player, realm = name:match("^(.*) %- (.*)$") + if player then + name = PLAYER_OF_REALM:format(player, realm) + end + t[k] = CHARACTER_COLON .. name + elseif k:find('^realm/') then + local name = k:sub(7) + t[k] = REALM_COLON .. name + elseif k:find('^class/') then + local name = k:sub(7) + t[k] = CLASS_COLON .. name + else + t[k] = k + end + end + end + end + end + end + end + if t.Default then + t.Default = DEFAULT + end + if t.Alternative then + t.Alternative = ALTERNATIVE + end +end + +local function RecalculateAceDBProfileList(target) + local t = target['acedb-profile-list'] + for k,v in pairs(t) do + t[k] = nil + end + t.char = CHARACTER_COLON .. PLAYER_OF_REALM:format(UnitName("player"), server) + t.realm = REALM_COLON .. realmID + t.class = CLASS_COLON .. classID + t.Default = DEFAULT + local db = target.db + if db and db.raw then + if db.raw.profiles then + for k in pairs(db.raw.profiles) do + if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then + t[k] = k + end + end + end + if db.raw.namespaces then + for _,n in pairs(db.raw.namespaces) do + if n.profiles then + for k in pairs(n.profiles) do + if not k:find("^char/") and not k:find("^realm/") and not k:find("^class/") then + t[k] = k + end + end + end + end + end + local curr = db.raw.currentProfile and db.raw.currentProfile[charID] + if curr and not t[curr] then + t[curr] = curr + end + end + if t.Alternative then + t.Alternative = ALTERNATIVE + end +end + +local CrawlForSerialization +local CrawlForDeserialization + +local function SerializeObject(o) + local t = { o:Serialize() } + CrawlForSerialization(t) + t[0] = o.class:GetLibraryVersion() + return t +end + +local function DeserializeObject(t) + CrawlForDeserialization(t) + local className = t[0] + t[0] = nil + return AceLibrary(className):Deserialize(unpack(t)) +end + +local function IsSerializable(t) + return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function" +end + +function CrawlForSerialization(t) + local tmp = new() + for k,v in pairs(t) do + tmp[k] = v + end + for k,v in pairs(tmp) do + if type(v) == "table" and type(rawget(v, 0)) ~= "userdata" then + if IsSerializable(v) then + v = SerializeObject(v) + t[k] = v + else + CrawlForSerialization(v) + end + end + if type(k) == "table" and type(rawget(k, 0)) ~= "userdata" then + if IsSerializable(k) then + t[k] = nil + t[SerializeObject(k)] = v + else + CrawlForSerialization(k) + end + end + tmp[k] = nil + k = nil + end + tmp = del(tmp) +end + +local function IsDeserializable(t) + return type(rawget(t, 0)) == "string" and AceLibrary:HasInstance(rawget(t, 0)) +end + +function CrawlForDeserialization(t) + local tmp = new() + for k,v in pairs(t) do + tmp[k] = v + end + for k,v in pairs(tmp) do + if type(v) == "table" then + if IsDeserializable(v) then + t[k] = DeserializeObject(v) + del(v) + v = t[k] + elseif type(rawget(v, 0)) ~= "userdata" then + CrawlForDeserialization(v) + end + end + if type(k) == "table" then + if IsDeserializable(k) then + t[k] = nil + t[DeserializeObject(k)] = v + del(k) + elseif type(rawget(k, 0)) ~= "userdata" then + CrawlForDeserialization(k) + end + end + tmp[k] = nil + k = nil + end + tmp = del(tmp) +end + +local namespace_mt = { __index = function(namespace, key) + local db = namespace.db + local name = namespace.name + if key == "char" then + if db.charName then + if type(_G[db.charName]) ~= "table" then + _G[db.charName] = {} + end + if type(_G[db.charName].namespaces) ~= "table" then + _G[db.charName].namespaces = {} + end + if type(_G[db.charName].namespaces[name]) ~= "table" then + _G[db.charName].namespaces[name] = {} + end + rawset(namespace, 'char', _G[db.charName].namespaces[name]) + else + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].chars) ~= "table" then + db.raw.namespaces[name].chars = {} + end + local id = charID + if type(db.raw.namespaces[name].chars[id]) ~= "table" then + db.raw.namespaces[name].chars[id] = {} + end + rawset(namespace, 'char', db.raw.namespaces[name].chars[id]) + end + if namespace.defaults and namespace.defaults.char then + inheritDefaults(namespace.char, namespace.defaults.char) + end + return namespace.char + elseif key == "realm" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].realms) ~= "table" then + db.raw.namespaces[name].realms = {} + end + local id = realmID + if type(db.raw.namespaces[name].realms[id]) ~= "table" then + db.raw.namespaces[name].realms[id] = {} + end + rawset(namespace, 'realm', db.raw.namespaces[name].realms[id]) + if namespace.defaults and namespace.defaults.realm then + inheritDefaults(namespace.realm, namespace.defaults.realm) + end + return namespace.realm + elseif key == "server" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].servers) ~= "table" then + db.raw.namespaces[name].servers = {} + end + local id = server + if type(db.raw.namespaces[name].servers[id]) ~= "table" then + db.raw.namespaces[name].servers[id] = {} + end + rawset(namespace, 'server', db.raw.namespaces[name].servers[id]) + if namespace.defaults and namespace.defaults.server then + inheritDefaults(namespace.server, namespace.defaults.server) + end + return namespace.server + elseif key == "account" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].account) ~= "table" then + db.raw.namespaces[name].account = {} + end + rawset(namespace, 'account', db.raw.namespaces[name].account) + if namespace.defaults and namespace.defaults.account then + inheritDefaults(namespace.account, namespace.defaults.account) + end + return namespace.account + elseif key == "faction" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].factions) ~= "table" then + db.raw.namespaces[name].factions = {} + end + local id = faction + if type(db.raw.namespaces[name].factions[id]) ~= "table" then + db.raw.namespaces[name].factions[id] = {} + end + rawset(namespace, 'faction', db.raw.namespaces[name].factions[id]) + if namespace.defaults and namespace.defaults.faction then + inheritDefaults(namespace.faction, namespace.defaults.faction) + end + return namespace.faction + elseif key == "class" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].classes) ~= "table" then + db.raw.namespaces[name].classes = {} + end + local id = classID + if type(db.raw.namespaces[name].classes[id]) ~= "table" then + db.raw.namespaces[name].classes[id] = {} + end + rawset(namespace, 'class', db.raw.namespaces[name].classes[id]) + if namespace.defaults and namespace.defaults.class then + inheritDefaults(namespace.class, namespace.defaults.class) + end + return namespace.class + elseif key == "profile" then + if type(db.raw.namespaces) ~= "table" then + db.raw.namespaces = {} + end + if type(db.raw.namespaces[name]) ~= "table" then + db.raw.namespaces[name] = {} + end + if type(db.raw.namespaces[name].profiles) ~= "table" then + db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt) + else + setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt) + end + local id = db.raw.currentProfile[charID] + if id == "char" then + id = "char/" .. charID + elseif id == "class" then + id = "class/" .. classID + elseif id == "realm" then + id = "realm/" .. realmID + end + if type(db.raw.namespaces[name].profiles[id]) ~= "table" then + db.raw.namespaces[name].profiles[id] = {} + end + rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id]) + if namespace.defaults and namespace.defaults.profile then + inheritDefaults(namespace.profile, namespace.defaults.profile) + end + return namespace.profile + elseif key == "defaults" or key == "name" or key == "db" then + return nil + end + error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) +end, __newindex = function(db, key, value) + error(("Cannot access key %q in db table. You may want to use db.profile[%q]"):format(tostring(key), tostring(key)), 2) +end } + +local tmp = {} +function AceDB:InitializeDB(addonName) + local db = self.db + + if not db then + if addonName then + AceDB.addonsLoaded[addonName] = true + end + return + end + + if db.raw then + -- someone manually initialized + return + end + + if type(_G[db.name]) ~= "table" then + _G[db.name] = {} + else + CrawlForDeserialization(_G[db.name]) + end + if db.charName then + if type(_G[db.charName]) ~= "table" then + _G[db.charName] = {} + else + CrawlForDeserialization(_G[db.charName]) + end + end + rawset(db, 'raw', _G[db.name]) + if not db.raw.currentProfile then + db.raw.currentProfile = {} + else + for k,v in pairs(db.raw.currentProfile) do + tmp[convertFromOldCharID(k)] = v + db.raw.currentProfile[k] = nil + end + for k,v in pairs(tmp) do + db.raw.currentProfile[k] = v + tmp[k] = nil + end + end + if not db.raw.currentProfile[charID] then + db.raw.currentProfile[charID] = AceDB.registry[self] or "Default" + end + if db.raw.profiles then + for k,v in pairs(db.raw.profiles) do + local new_k = k + if k:find("^char/") then + new_k = "char/" .. convertFromOldCharID(k:sub(6)) + end + tmp[new_k] = v + db.raw.profiles[k] = nil + end + for k,v in pairs(tmp) do + db.raw.profiles[k] = v + tmp[k] = nil + end + end + if db.raw.disabledModules then -- AceModuleCore-2.0 + for k,v in pairs(db.raw.disabledModules) do + local new_k = k + if k:find("^char/") then + new_k = "char/" .. convertFromOldCharID(k:sub(6)) + end + tmp[new_k] = v + db.raw.disabledModules[k] = nil + end + for k,v in pairs(tmp) do + db.raw.disabledModules[k] = v + tmp[k] = nil + end + end + if db.raw.chars then + for k,v in pairs(db.raw.chars) do + tmp[convertFromOldCharID(k)] = v + db.raw.chars[k] = nil + end + for k,v in pairs(tmp) do + db.raw.chars[k] = v + tmp[k] = nil + end + end + if db.raw.namespaces then + for l,u in pairs(db.raw.namespaces) do + if u.chars then + for k,v in pairs(u.chars) do + tmp[convertFromOldCharID(k)] = v + u.chars[k] = nil + end + for k,v in pairs(tmp) do + u.chars[k] = v + tmp[k] = nil + end + end + end + end + if db.raw.disabled then + setmetatable(db.raw.disabled, caseInsensitive_mt) + end + if self['acedb-profile-copylist'] then + RecalculateAceDBCopyFromList(self) + end + if self['acedb-profile-list'] then + RecalculateAceDBProfileList(self) + end + setmetatable(db, db_mt) +end + +function AceDB:OnEmbedInitialize(target, name) + if name then + self:ADDON_LOADED(name) + end + self.InitializeDB(target, name) +end + +function AceDB:RegisterDB(name, charName, defaultProfile) + AceDB:argCheck(name, 2, "string") + AceDB:argCheck(charName, 3, "string", "nil") + AceDB:argCheck(defaultProfile, 4, "string", "nil") + if self.db then + AceDB:error("Cannot call \"RegisterDB\" if self.db is set.") + end + local stack = debugstack() + local addonName = stack:gsub(".-\n.-\\AddOns\\(.-)\\.*", "%1") + self.db = { + name = name, + charName = charName + } + AceDB.registry[self] = defaultProfile or "Default" + if AceDB.addonsLoaded[addonName] then + AceDB.InitializeDB(self, addonName) + else + AceDB.addonsToBeInitialized[self] = addonName + end +end + +function AceDB:RegisterDefaults(kind, defaults, a3) + local name + if a3 then + name, kind, defaults = kind, defaults, a3 + AceDB:argCheck(name, 2, "string") + AceDB:argCheck(kind, 3, "string") + AceDB:argCheck(defaults, 4, "table") + else + AceDB:argCheck(kind, 2, "string") + AceDB:argCheck(defaults, 3, "table") + end + if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then + AceDB:error("Bad argument #%d to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", \"realm\", \"server\", or \"faction\" expected, got %q)", a3 and 3 or 2, kind) + end + if type(self.db) ~= "table" or type(self.db.name) ~= "string" then + AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.") + end + local db + if name then + local namespace = self:AcquireDBNamespace(name) + if namespace.defaults and namespace.defaults[kind] then + AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind) + end + db = namespace + else + if self.db.defaults and self.db.defaults[kind] then + AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind) + end + db = self.db + end + if not db.defaults then + rawset(db, 'defaults', {}) + end + db.defaults[kind] = defaults + if rawget(db, kind) then + inheritDefaults(db[kind], defaults) + end +end + +function AceDB:ResetDB(kind, a2) + local name + if a2 then + name, kind = kind, a2 + AceDB:argCheck(name, 2, "nil", "string") + AceDB:argCheck(kind, 3, "nil", "string") + else + AceDB:argCheck(kind, 2, "nil", "string") + if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" and kind ~= "server" then + name, kind = kind, nil + end + end + if not self.db or not self.db.raw then + AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") + end + local db = self.db + if not kind then + if not name then + if db.charName then + _G[db.charName] = nil + end + _G[db.name] = nil + rawset(db, 'raw', nil) + AceDB.InitializeDB(self) + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'account', nil) + rawset(v, 'char', nil) + rawset(v, 'class', nil) + rawset(v, 'profile', nil) + rawset(v, 'realm', nil) + rawset(v, 'server', nil) + rawset(v, 'faction', nil) + end + end + else + if db.raw.namespaces then + db.raw.namespaces[name] = nil + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'account', nil) + rawset(v, 'char', nil) + rawset(v, 'class', nil) + rawset(v, 'profile', nil) + rawset(v, 'realm', nil) + rawset(v, 'server', nil) + rawset(v, 'faction', nil) + end + end + end + elseif kind == "account" then + if name then + db.raw.account = nil + rawset(db, 'account', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + v.account = nil + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'account', nil) + end + end + else + if db.raw.namespaces and db.raw.namespaces[name] then + db.raw.namespaces[name].account = nil + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'account', nil) + end + end + end + elseif kind == "char" then + if name then + if db.charName then + _G[db.charName] = nil + else + if db.raw.chars then + db.raw.chars[charID] = nil + end + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.chars then + v.chars[charID] = nil + end + end + end + end + rawset(db, 'char', nil) + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'char', nil) + end + end + else + if db.charName then + local x = _G[db.charName] + if x.namespaces then + x.namespaces[name] = nil + end + else + if db.raw.namespaces then + local v = db.namespaces[name] + if v and v.chars then + v.chars[charID] = nil + end + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'char', nil) + end + end + end + elseif kind == "realm" then + if not name then + if db.raw.realms then + db.raw.realms[realmID] = nil + end + rawset(db, 'realm', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.realms then + v.realms[realmID] = nil + end + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'realm', nil) + end + end + else + if db.raw.namespaces then + local v = db.raw.namespaces[name] + if v and v.realms then + v.realms[realmID] = nil + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'realm', nil) + end + end + end + elseif kind == "server" then + if not name then + if db.raw.servers then + db.raw.servers[server] = nil + end + rawset(db, 'server', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.servers then + v.servers[server] = nil + end + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'server', nil) + end + end + else + if db.raw.namespaces then + local v = db.raw.namespaces[name] + if v and v.servers then + v.servers[server] = nil + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'server', nil) + end + end + end + elseif kind == "faction" then + if not name then + if db.raw.factions then + db.raw.factions[faction] = nil + end + rawset(db, 'faction', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.factions then + v.factions[faction] = nil + end + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'faction', nil) + end + end + else + if db.raw.namespaces then + local v = db.raw.namespaces[name] + if v and v.factions then + v.factions[faction] = nil + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'faction', nil) + end + end + end + elseif kind == "class" then + if not name then + if db.raw.realms then + db.raw.realms[classID] = nil + end + rawset(db, 'class', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.classes then + v.classes[classID] = nil + end + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'class', nil) + end + end + else + if db.raw.namespaces then + local v = db.raw.namespaces[name] + if v and v.classes then + v.classes[classID] = nil + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'class', nil) + end + end + end + elseif kind == "profile" then + local id = db.raw.currentProfile and db.raw.currentProfile[charID] or AceDB.registry[self] or "Default" + if id == "char" then + id = "char/" .. charID + elseif id == "class" then + id = "class/" .. classID + elseif id == "realm" then + id = "realm/" .. realmID + end + + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileDisable) == "function" then + safecall(mixin.OnEmbedProfileDisable, mixin, self, id) + end + end + end + current = current.super + end + if type(self.OnProfileDisable) == "function" then + safecall(self.OnProfileDisable, self, id) + end + local active = self:IsActive() + + if not name then + if db.raw.profiles then + db.raw.profiles[id] = nil + end + rawset(db, 'profile', nil) + if db.raw.namespaces then + for name,v in pairs(db.raw.namespaces) do + if v.profiles then + v.profiles[id] = nil + end + end + end + if db.namespaces then + for name,v in pairs(db.namespaces) do + rawset(v, 'profile', nil) + end + end + else + if db.raw.namespaces then + local v = db.raw.namespaces[name] + if v and v.profiles then + v.profiles[id] = nil + end + end + if db.namespaces then + local v = db.namespaces[name] + if v then + rawset(v, 'profile', nil) + end + end + end + + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileEnable) == "function" then + safecall(mixin.OnEmbedProfileEnable, mixin, self, id) + end + end + end + current = current.super + end + if type(self.OnProfileEnable) == "function" then + safecall(self.OnProfileEnable, self, id) + end + local newactive = self:IsActive() + if active ~= newactive then + if newactive then + local first = nil + if AceOO.inherits(self, "AceAddon-2.0") then + local AceAddon = AceLibrary("AceAddon-2.0") + if not AceAddon.addonsStarted[self] then + return + end + if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then + AceAddon.addonsEnabled[self] = true + first = true + end + end + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, self, first) + end + end + end + current = current.super + end + if type(self.OnEnable) == "function" then + safecall(self.OnEnable, self, first) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first) + end + else + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnDisable) == "function" then + safecall(self.OnDisable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", self) + end + end + end + else + return -- skip event + end + if AceEvent then + AceEvent:TriggerEvent("AceDB20_ResetDB", self, self.db.name, kind) + end +end + +local function cleanDefaults(t, defaults, blocker) + if defaults then + for k,v in pairs(t) do + if (not blocker or (blocker[k] == nil and blocker['*'] == nil and blocker['**'] == nil)) and (defaults[k] ~= nil or defaults['*'] ~= nil or defaults['**'] ~= nil) then + local u = defaults[k] + if u == nil then + u = defaults['*'] + if u == nil then + u = defaults['**'] + end + end + if v == u then + t[k] = nil + elseif type(v) == "table" and type(u) == "table" then + if cleanDefaults(v, u) then + t[k] = nil + else + local w = defaults['**'] + if w ~= u then + if cleanDefaults(v, w, u) then + t[k] = nil + end + end + end + end + end + end + end + return t and next(t) == nil +end + +function AceDB:GetProfile() + if not self.db or not self.db.raw then + return nil + end + if not self.db.raw.currentProfile then + self.db.raw.currentProfile = {} + end + if not self.db.raw.currentProfile[charID] then + self.db.raw.currentProfile[charID] = AceDB.registry[self] or "Default" + end + local profile = self.db.raw.currentProfile[charID] + if profile == "char" then + return "char", "char/" .. charID + elseif profile == "class" then + return "class", "class/" .. classID + elseif profile == "realm" then + return "realm", "realm/" .. realmID + end + return profile, profile +end + +local function copyTable(to, from) + setmetatable(to, nil) + for k,v in pairs(from) do + if type(k) == "table" then + k = copyTable({}, k) + end + if type(v) == "table" then + v = copyTable({}, v) + end + to[k] = v + end + setmetatable(to, from) + return to +end + +function AceDB:SetProfile(name) + AceDB:argCheck(name, 2, "string") + if not self.db or not self.db.raw then + AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") + end + local db = self.db + local lowerName = name:lower() + if lowerName:find("^char/") or lowerName:find("^realm/") or lowerName:find("^class/") then + if lowerName:find("^char/") then + name = "char" + else + name = lowerName:sub(1, 5) + end + lowerName = name:lower() + end + local oldName = db.raw.currentProfile[charID] + if oldName:lower() == name:lower() then + return + end + local oldProfileData = db.profile + local realName = name + if lowerName == "char" then + realName = name .. "/" .. charID + elseif lowerName == "realm" then + realName = name .. "/" .. realmID + elseif lowerName == "class" then + realName = name .. "/" .. classID + end + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileDisable) == "function" then + safecall(mixin.OnEmbedProfileDisable, mixin, self, realName) + end + end + end + current = current.super + end + if type(self.OnProfileDisable) == "function" then + safecall(self.OnProfileDisable, self, realName) + end + local active = self:IsActive() + db.raw.currentProfile[charID] = name + rawset(db, 'profile', nil) + if db.namespaces then + for k,v in pairs(db.namespaces) do + rawset(v, 'profile', nil) + end + end + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileEnable) == "function" then + safecall(mixin.OnEmbedProfileEnable, mixin, self, oldName, oldProfileData) + end + end + end + current = current.super + end + if type(self.OnProfileEnable) == "function" then + safecall(self.OnProfileEnable, self, oldName, oldProfileData) + end + if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then + db.raw.profiles[oldName] = nil + if not next(db.raw.profiles) then + db.raw.profiles = nil + end + end + local newactive = self:IsActive() + if active ~= newactive then + local first = nil + if AceOO.inherits(self, "AceAddon-2.0") then + local AceAddon = AceLibrary("AceAddon-2.0") + if not AceAddon.addonsStarted[self] then + return + end + if AceAddon.addonsEnabled and not AceAddon.addonsEnabled[self] then + first = true + end + end + if newactive then + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, self, first) + end + end + end + current = current.super + end + if type(self.OnEnable) == "function" then + safecall(self.OnEnable, self, first) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", self, first) + end + else + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnDisable) == "function" then + safecall(self.OnDisable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", self) + end + end + end + if self['acedb-profile-list'] then + RecalculateAceDBProfileList(self) + end + if self['acedb-profile-copylist'] then + RecalculateAceDBCopyFromList(self) + end + if Dewdrop then + Dewdrop:Refresh() + end +end + +function AceDB:CopyProfileFrom(copyFrom) + AceDB:argCheck(copyFrom, 2, "string") + if not self.db or not self.db.raw then + AceDB:error("Cannot call \"CopyProfileFrom\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") + end + local db = self.db + local lowerCopyFrom = copyFrom:lower() + if not db.raw.profiles or not db.raw.profiles[copyFrom] then + local good = false + if db.raw.namespaces then + for _,n in pairs(db.raw.namespaces) do + if n.profiles and n.profiles[copyFrom] then + good = true + break + end + end + end + if not good then + AceDB:error("Cannot copy from profile %q, it does not exist.", copyFrom) + end + end + local currentProfile = db.raw.currentProfile[charID] + if currentProfile:lower() == lowerCopyFrom then + AceDB:error("Cannot copy from profile %q, it is currently in use.", copyFrom) + end + local oldProfileData = db.profile + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileDisable) == "function" then + safecall(mixin.OnEmbedProfileDisable, mixin, self, currentProfile) + end + end + end + current = current.super + end + if type(self.OnProfileDisable) == "function" then + safecall(self.OnProfileDisable, self, realName) + end + local active = self:IsActive() + for k,v in pairs(db.profile) do + db.profile[k] = nil + end + if db.raw.profiles[copyFrom] then + copyTable(db.profile, db.raw.profiles[copyFrom]) + end + inheritDefaults(db.profile, db.defaults and db.defaults.profile) + if db.namespaces then + for l,u in pairs(db.namespaces) do + for k,v in pairs(u.profile) do + u.profile[k] = nil + end + if db.raw.namespaces[l].profiles[copyFrom] then + copyTable(u.profile, db.raw.namespaces[l].profiles[copyFrom]) + end + inheritDefaults(u.profile, u.defaults and u.defaults.profile) + end + end + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedProfileEnable) == "function" then + safecall(mixin.OnEmbedProfileEnable, mixin, self, copyFrom, oldProfileData, copyFrom) + end + end + end + current = current.super + end + if type(self.OnProfileEnable) == "function" then + safecall(self.OnProfileEnable, self, copyFrom, oldProfileData, copyFrom) + end + local newactive = self:IsActive() + if active ~= newactive then + if AceOO.inherits(self, "AceAddon-2.0") then + local AceAddon = AceLibrary("AceAddon-2.0") + if not AceAddon.addonsStarted[self] then + return + end + end + if newactive then + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnEnable) == "function" then + safecall(self.OnEnable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", self) + end + else + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnDisable) == "function" then + safecall(self.OnDisable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", self) + end + end + end + if self['acedb-profile-list'] then + RecalculateAceDBProfileList(self) + end + if self['acedb-profile-copylist'] then + RecalculateAceDBCopyFromList(self) + end + if Dewdrop then + Dewdrop:Refresh() + end +end + +function AceDB:DeleteProfile(profile, noconfirm) + AceDB:argCheck(profile , 2, "string") + if not self.db or not self.db.raw then + AceDB:error("Cannot call \"DeleteProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") + end + local db = self.db + + local currentProfile = db.raw.currentProfile[charID] + if currentProfile:lower() == profile:lower() then + AceDB:error("Cannot delete profile %q, it is currently in use.", profile) + end + + if not (noconfirm or IsShiftKeyDown()) then + if not StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] then + StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] = {} + end + local t = StaticPopupDialogs["ACEDB20_CONFIRM_DELETE_DIALOG"] + t.text = format("%s: %s?", DELETE_PROFILE, profile) + t.button1 = DELETE_PROFILE + t.button2 = CANCEL or "Cancel" + t.OnAccept = function() + self:DeleteProfile(profile, true) + end + t.timeout = 0 + t.whileDead = 1 + t.hideOnEscape = 1 + + StaticPopup_Show("ACEDB20_CONFIRM_DELETE_DIALOG") + return; + end + + local good = false + if db.raw.profiles and db.raw.profiles[profile] then + good = true; + db.raw.profiles[profile] = nil; + end + + if db.raw.namespaces then + for _,n in pairs(db.raw.namespaces) do + if n.profiles and n.profiles[profile] then + n.profiles[profile] = nil; + good = true + end + end + end + + if not good then + AceDB:error("Cannot delete profile %q, it does not exist.", profile) + end + + if self['acedb-profile-list'] then + RecalculateAceDBProfileList(self) + end + if self['acedb-profile-copylist'] then + RecalculateAceDBCopyFromList(self) + end + + if Dewdrop then + Dewdrop:Refresh() + end +end + +function AceDB:IsActive() + return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]] +end + +function AceDB:ToggleActive(state) + AceDB:argCheck(state, 2, "boolean", "nil") + if not self.db or not self.db.raw then + AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") + end + local db = self.db + if not db.raw.disabled then + db.raw.disabled = setmetatable({}, caseInsensitive_mt) + end + local profile = db.raw.currentProfile[charID] + local disable + if state == nil then + disable = not db.raw.disabled[profile] + else + disable = not state + if disable == db.raw.disabled[profile] then + return + end + end + db.raw.disabled[profile] = disable or nil + if AceOO.inherits(self, "AceAddon-2.0") then + local AceAddon = AceLibrary("AceAddon-2.0") + if not AceAddon.addonsStarted[self] then + return + end + end + if not disable then + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedEnable) == "function" then + safecall(mixin.OnEmbedEnable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnEnable) == "function" then + safecall(self.OnEnable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonEnabled", self) + end + else + local current = self.class + while current and current ~= AceOO.Class do + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnEmbedDisable) == "function" then + safecall(mixin.OnEmbedDisable, mixin, self) + end + end + end + current = current.super + end + if type(self.OnDisable) == "function" then + safecall(self.OnDisable, self) + end + if AceEvent then + AceEvent:TriggerEvent("Ace2_AddonDisabled", self) + end + end + return not disable +end + +function AceDB:embed(target) + self.super.embed(self, target) + if not AceEvent then + AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0") + end +end + +function AceDB:ADDON_LOADED(name) + AceDB.addonsLoaded[name] = true + for addon, addonName in pairs(AceDB.addonsToBeInitialized) do + if name == addonName then + AceDB.InitializeDB(addon, name) + AceDB.addonsToBeInitialized[addon] = nil + end + end +end + +function AceDB:PLAYER_LOGOUT() + for addon, defaultProfile in pairs(AceDB.registry) do + local db = addon.db + if db then + if type(addon.OnDatabaseCleanup) == "function" then + safecall(addon.OnDatabaseCleanup, addon) + end + setmetatable(db, nil) + CrawlForSerialization(db.raw) + if type(_G[db.charName]) == "table" then + CrawlForSerialization(_G[db.charName]) + end + if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then + if db.charName and _G[db.charName] and _G[db.charName].global == db.char then + _G[db.charName].global = nil + if not next(_G[db.charName]) then + _G[db.charName] = nil + end + else + if db.raw.chars then + db.raw.chars[charID] = nil + if not next(db.raw.chars) then + db.raw.chars = nil + end + end + end + end + if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then + if db.raw.realms then + db.raw.realms[realmID] = nil + if not next(db.raw.realms) then + db.raw.realms = nil + end + end + end + if db.server and cleanDefaults(db.server, db.defaults and db.defaults.server) then + if db.raw.servers then + db.raw.servers[server] = nil + if not next(db.raw.servers) then + db.raw.servers = nil + end + end + end + if db.faction and cleanDefaults(db.faction, db.defaults and db.defaults.faction) then + if db.raw.factions then + db.raw.factions[faction] = nil + if not next(db.raw.factions) then + db.raw.factions = nil + end + end + end + if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then + if db.raw.classes then + db.raw.classes[classID] = nil + if not next(db.raw.classes) then + db.raw.classes = nil + end + end + end + if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then + db.raw.account = nil + end + if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then + if db.raw.profiles then + db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil + if not next(db.raw.profiles) then + db.raw.profiles = nil + end + end + end + if db.namespaces and db.raw.namespaces then + for name,v in pairs(db.namespaces) do + if db.raw.namespaces[name] then + setmetatable(v, nil) + if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then + if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then + _G[db.charName].namespaces[name] = nil + if not next(_G[db.charName].namespaces) then + _G[db.charName].namespaces = nil + if not next(_G[db.charName]) then + _G[db.charName] = nil + end + end + else + if db.raw.namespaces[name].chars then + db.raw.namespaces[name].chars[charID] = nil + if not next(db.raw.namespaces[name].chars) then + db.raw.namespaces[name].chars = nil + end + end + end + end + if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then + if db.raw.namespaces[name].realms then + db.raw.namespaces[name].realms[realmID] = nil + if not next(db.raw.namespaces[name].realms) then + db.raw.namespaces[name].realms = nil + end + end + end + if v.server and cleanDefaults(v.server, v.defaults and v.defaults.server) then + if db.raw.namespaces[name].servers then + db.raw.namespaces[name].servers[server] = nil + if not next(db.raw.namespaces[name].servers) then + db.raw.namespaces[name].servers = nil + end + end + end + if v.faction and cleanDefaults(v.faction, v.defaults and v.defaults.faction) then + if db.raw.namespaces[name].factions then + db.raw.namespaces[name].factions[faction] = nil + if not next(db.raw.namespaces[name].factions) then + db.raw.namespaces[name].factions = nil + end + end + end + if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then + if db.raw.namespaces[name].classes then + db.raw.namespaces[name].classes[classID] = nil + if not next(db.raw.namespaces[name].classes) then + db.raw.namespaces[name].classes = nil + end + end + end + if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then + db.raw.namespaces[name].account = nil + end + if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then + if db.raw.namespaces[name].profiles then + db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or defaultProfile or "Default"] = nil + if not next(db.raw.namespaces[name].profiles) then + db.raw.namespaces[name].profiles = nil + end + end + end + if not next(db.raw.namespaces[name]) then + db.raw.namespaces[name] = nil + end + end + end + if not next(db.raw.namespaces) then + db.raw.namespaces = nil + end + end + if db.raw.disabled and not next(db.raw.disabled) then + db.raw.disabled = nil + end + if db.raw.currentProfile then + for k,v in pairs(db.raw.currentProfile) do + if v:lower() == (defaultProfile or "Default"):lower() then + db.raw.currentProfile[k] = nil + end + end + if not next(db.raw.currentProfile) then + db.raw.currentProfile = nil + end + end + if _G[db.name] and not next(_G[db.name]) then + _G[db.name] = nil + end + end + end +end + +function AceDB:AcquireDBNamespace(name) + AceDB:argCheck(name, 2, "string") + local db = self.db + if not db then + AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2) + end + if not db.namespaces then + rawset(db, 'namespaces', {}) + end + if not db.namespaces[name] then + local namespace = {} + db.namespaces[name] = namespace + namespace.db = db + namespace.name = name + setmetatable(namespace, namespace_mt) + end + return db.namespaces[name] +end + +function AceDB:GetAceOptionsDataTable(target) + if not target['acedb-profile-list'] then + target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt) + RecalculateAceDBProfileList(target) + end + if not target['acedb-profile-copylist'] then + target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt) + RecalculateAceDBCopyFromList(target) + end + return { + standby = { + cmdName = STATE, + guiName = ENABLED, + name = ACTIVE, + desc = TOGGLE_ACTIVE, + type = "toggle", + get = "IsActive", + set = "ToggleActive", + map = MAP_ACTIVESUSPENDED, + order = -3, + }, + profile = { + type = 'group', + name = PROFILE, + desc = SET_PROFILE, + order = -3.5, + get = "GetProfile", + args = { + choose = { + guiName = CHOOSE_PROFILE_GUI, + cmdName = PROFILE, + desc = CHOOSE_PROFILE_DESC, + type = 'text', + get = "GetProfile", + set = "SetProfile", + validate = target['acedb-profile-list'] + }, + copy = { + guiName = COPY_PROFILE_GUI, + cmdName = PROFILE, + desc = COPY_PROFILE_DESC, + type = 'text', + get = false, + set = "CopyProfileFrom", + validate = target['acedb-profile-copylist'], + disabled = function() + return not next(target['acedb-profile-copylist']) + end, + }, + other = { + guiName = OTHER_PROFILE_GUI, + cmdName = PROFILE, + desc = OTHER_PROFILE_DESC, + usage = OTHER_PROFILE_USAGE, + type = 'text', + get = "GetProfile", + set = "SetProfile", + }, + delete = { + name = DELETE_PROFILE, + desc = DELETE_PROFILE_DESC, + usage = DELETE_PROFILE_USAGE, + type = 'text', + set = "DeleteProfile", + get = false, + validate = target['acedb-profile-copylist'], + disabled = function() + return not next(target['acedb-profile-copylist']) + end, + }, + reset = { + name = RESET_PROFILE, + desc = RESET_PROFILE_DESC, + type = 'execute', + func = function() + target:ResetDB('profile') + end, + confirm = true, + } + } + }, + } +end + +local function activate(self, oldLib, oldDeactivate) + AceDB = self + AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") + + self.addonsToBeInitialized = oldLib and oldLib.addonsToBeInitialized or {} + self.addonsLoaded = oldLib and oldLib.addonsLoaded or {} + self.registry = oldLib and oldLib.registry or {} + for k, v in pairs(self.registry) do + if v == true then + self.registry[k] = "Default" + end + end + + self:activate(oldLib, oldDeactivate) + + for t in pairs(self.embedList) do + if t.db then + rawset(t.db, 'char', nil) + rawset(t.db, 'realm', nil) + rawset(t.db, 'class', nil) + rawset(t.db, 'account', nil) + rawset(t.db, 'server', nil) + rawset(t.db, 'faction', nil) + rawset(t.db, 'profile', nil) + setmetatable(t.db, db_mt) + end + end + + if oldLib then + oldDeactivate(oldLib) + end +end + +local function external(self, major, instance) + if major == "AceEvent-2.0" then + AceEvent = instance + + AceEvent:embed(self) + + self:RegisterEvent("ADDON_LOADED") + self:RegisterEvent("PLAYER_LOGOUT") + elseif major == "Dewdrop-2.0" then + Dewdrop = instance + end +end + +AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) +AceDB = AceLibrary(MAJOR_VERSION)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceEvent-2.0/AceEvent-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,1082 @@ +--[[ +Name: AceEvent-2.0 +Revision: $Rev: 49307 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceEvent-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0 +Description: Mixin to allow for event handling, scheduling, and inter-addon + communication. +Dependencies: AceLibrary, AceOO-2.0 +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceEvent-2.0" +local MINOR_VERSION = "$Revision: 49307 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end + +local AceOO = AceLibrary:GetInstance("AceOO-2.0") +local Mixin = AceOO.Mixin +local AceEvent = Mixin { + "RegisterEvent", + "RegisterAllEvents", + "UnregisterEvent", + "UnregisterAllEvents", + "TriggerEvent", + "ScheduleEvent", + "ScheduleRepeatingEvent", + "CancelScheduledEvent", + "CancelAllScheduledEvents", + "IsEventRegistered", + "IsEventScheduled", + "RegisterBucketEvent", + "UnregisterBucketEvent", + "UnregisterAllBucketEvents", + "IsBucketEventRegistered", + "ScheduleLeaveCombatAction", + "CancelAllCombatSchedules", +} + +local weakKey = {__mode="k"} + +local FAKE_NIL +local RATE + +local eventsWhichHappenOnce = { + PLAYER_LOGIN = true, + AceEvent_FullyInitialized = true, + VARIABLES_LOADED = true, + PLAYER_LOGOUT = true, +} +local next = next +local pairs = pairs +local pcall = pcall +local type = type +local GetTime = GetTime +local gcinfo = gcinfo +local unpack = unpack +local geterrorhandler = geterrorhandler + +local build = GetBuildInfo() +local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.") + +local new, del +do + local cache = setmetatable({}, {__mode='k'}) + function new(...) + local t = next(cache) + if t then + cache[t] = nil + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + return t + else + return { ... } + end + end + function del(t) + for k in pairs(t) do + t[k] = nil + end + cache[t] = true + return nil + end +end + +local registeringFromAceEvent +--[[---------------------------------------------------------------------------------- +Notes: + * Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered. +Arguments: + string - name of the event to register + [optional] string or function - name of the method or function to call. Default: same name as "event". + [optional] boolean - whether to have method called only once. Default: false +------------------------------------------------------------------------------------]] +function AceEvent:RegisterEvent(event, method, once) + AceEvent:argCheck(event, 2, "string") + if self == AceEvent and not registeringFromAceEvent then + AceEvent:argCheck(method, 3, "function") + self = method + else + AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number") + if type(method) == "boolean" or type(method) == "number" then + AceEvent:argCheck(once, 4, "nil") + once, method = method, event + end + end + AceEvent:argCheck(once, 4, "number", "boolean", "nil") + if eventsWhichHappenOnce[event] then + once = true + end + local throttleRate + if type(once) == "number" then + throttleRate, once = once + end + if not method then + method = event + end + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + else + assert(type(method) == "function" or type(method) == "string") + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[event] then + AceEvent_registry[event] = new() + AceEvent.frame:RegisterEvent(event) + end + + local remember = true + if AceEvent_registry[event][self] then + remember = false + end + AceEvent_registry[event][self] = method + + local AceEvent_onceRegistry = AceEvent.onceRegistry + if once then + if not AceEvent_onceRegistry then + AceEvent.onceRegistry = {} + AceEvent_onceRegistry = AceEvent.onceRegistry + end + if not AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event] = new() + end + AceEvent_onceRegistry[event][self] = true + else + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if throttleRate then + if not AceEvent_throttleRegistry then + AceEvent.throttleRegistry = {} + AceEvent_throttleRegistry = AceEvent.throttleRegistry + end + if not AceEvent_throttleRegistry[event] then + AceEvent_throttleRegistry[event] = new() + end + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + end + AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey) + local t = AceEvent_throttleRegistry[event][self] + t[RATE] = throttleRate + else + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then + if AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + end + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + end + + if remember then + AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event) + end +end + +local ALL_EVENTS + +--[[---------------------------------------------------------------------------------- +Notes: + * Registers all events to the given method + * To access the current event, check AceEvent.currentEvent + * To access the current event's unique identifier, check AceEvent.currentEventUID + * This is only for debugging purposes. +Arguments: + [optional] string or function - name of the method or function to call. Default: same name as "event". +------------------------------------------------------------------------------------]] +function AceEvent:RegisterAllEvents(method) + if self == AceEvent then + AceEvent:argCheck(method, 1, "function") + self = method + else + AceEvent:argCheck(method, 1, "string", "function") + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register all events to method %q, it does not exist", method) + end + end + + local AceEvent_registry = AceEvent.registry + if not AceEvent_registry[ALL_EVENTS] then + AceEvent_registry[ALL_EVENTS] = new() + AceEvent.frame:RegisterAllEvents() + end + + local remember = not AceEvent_registry[ALL_EVENTS][self] + AceEvent_registry[ALL_EVENTS][self] = method + if remember then + AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all") + end +end + +--[[---------------------------------------------------------------------------------- +Notes: + * Trigger a custom AceEvent. + * This should never be called to simulate fake Blizzard events. + * Custom events should be in the form of AddonName_SpecificEvent +Arguments: + string - name of the event + tuple - list of arguments to pass along +------------------------------------------------------------------------------------]] +function AceEvent:TriggerEvent(event, ...) + if type(event) ~= "string" then + DEFAULT_CHAT_FRAME:AddMessage(debugstack()) + end + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then + return + end + local lastEvent = AceEvent.currentEvent + AceEvent.currentEvent = event + local lastEventUID = AceEvent.currentEventUID + local uid = AceEvent.UID_NUM + 1 + AceEvent.UID_NUM = uid + AceEvent.currentEventUID = uid + + local tmp = new() + + local AceEvent_onceRegistry = AceEvent.onceRegistry + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then + for obj, method in pairs(AceEvent_onceRegistry[event]) do + tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + AceEvent.UnregisterEvent(obj, event) + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + tmp[obj] = nil + obj = next(tmp) + end + end + + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] + if AceEvent_registry[event] then + for obj, method in pairs(AceEvent_registry[event]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + local continue = false + if throttleTable and throttleTable[obj] then + local a1 = ... + if a1 == nil then + a1 = FAKE_NIL + end + if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then + throttleTable[obj][a1] = GetTime() + else + continue = true + end + end + if not continue then + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + end + tmp[obj] = nil + obj = next(tmp) + end + end + if AceEvent_registry[ALL_EVENTS] then + for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do + tmp[obj] = method + end + local obj = next(tmp) + while obj do + local method = tmp[obj] + if type(method) == "string" then + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + elseif method then -- function + local success, err = pcall(method, ...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + tmp[obj] = nil + obj = next(tmp) + end + end + tmp = del(tmp) + AceEvent.currentEvent = lastEvent + AceEvent.currentEventUID = lastEventUID +end + +local delayRegistry +local OnUpdate +do + local tmp = {} + OnUpdate = function() + local t = GetTime() + for k,v in pairs(delayRegistry) do + tmp[k] = true + end + for k in pairs(tmp) do + local v = delayRegistry[k] + if v then + local v_time = v.time + if not v_time then + delayRegistry[k] = nil + elseif v_time <= t then + local v_repeatDelay = v.repeatDelay + if v_repeatDelay then + -- use the event time, not the current time, else timing inaccuracies add up over time + v.time = v_time + v_repeatDelay + end + local event = v.event + if type(event) == "function" then + local uid = AceEvent.UID_NUM + 1 + AceEvent.UID_NUM = uid + AceEvent.currentEventUID = uid + local success, err = pcall(event, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + AceEvent.currentEventUID = nil + else + AceEvent:TriggerEvent(event, unpack(v, 1, v.n)) + end + if not v_repeatDelay then + local x = delayRegistry[k] + if x and x.time == v_time then -- check if it was manually reset + if not useTablesAsIDs or type(k) == "string" then + del(delayRegistry[k]) + end + delayRegistry[k] = nil + end + end + end + end + end + for k in pairs(tmp) do + tmp[k] = nil + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + end +end + +local function ScheduleEvent(self, repeating, event, delay, ...) + local id + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + id, event, delay = event, delay, ... + AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(delay, 4, "number") + self:CancelScheduledEvent(id) + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + if not delayRegistry then + AceEvent.delayRegistry = {} + delayRegistry = AceEvent.delayRegistry + AceEvent.frame:SetScript("OnUpdate", OnUpdate) + end + local t + if useTablesAsIDs and type(id) == "table" then + for k in pairs(id) do + id[k] = nil + end + t = id + for i = 2, select('#', ...) do + t[i-1] = select(i, ...) + end + t.n = select('#', ...) - 1 + elseif id then + t = new(select(2, ...)) + t.n = select('#', ...) - 1 + else + t = new(...) + t.n = select('#', ...) + end + t.event = event + t.time = GetTime() + delay + t.self = self + t.id = id or t + t.repeatDelay = repeating and delay + delayRegistry[t.id] = t + AceEvent.frame:Show() + if useTablesAsIDs then + return t.id + else + return + end +end + +--[[---------------------------------------------------------------------------------- +Notes: + * Schedule an event to fire. + * To fire on the next frame, specify a delay of 0. +Arguments: + string or function - name of the event to fire, or a function to call. + number - the amount of time to wait until calling. + tuple - a list of arguments to pass along. +------------------------------------------------------------------------------------]] +function AceEvent:ScheduleEvent(event, delay, ...) + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(..., 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, false, event, delay, ...) +end + +function AceEvent:ScheduleRepeatingEvent(event, delay, ...) + if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then + if useTablesAsIDs and type(event) == "table" then + if not delayRegistry or not delayRegistry[event] then + AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") + end + end + if type(delay) ~= "number" then + AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") + AceEvent:argCheck(..., 4, "number") + end + else + AceEvent:argCheck(event, 2, "string", "function") + AceEvent:argCheck(delay, 3, "number") + end + + return ScheduleEvent(self, true, event, delay, ...) +end + +function AceEvent:CancelScheduledEvent(t) + if useTablesAsIDs then + AceEvent:argCheck(t, 2, "string", "table") + else + AceEvent:argCheck(t, 2, "string") + end + if delayRegistry then + local v = delayRegistry[t] + if v then + if not useTablesAsIDs or type(t) == "string" then + del(delayRegistry[t]) + end + delayRegistry[t] = nil + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + return true + end + end + return false +end + +function AceEvent:IsEventScheduled(t) + if useTablesAsIDs then + AceEvent:argCheck(t, 2, "string", "table") + else + AceEvent:argCheck(t, 2, "string") + end + if delayRegistry then + local v = delayRegistry[t] + if v then + return true, v.time - GetTime() + end + end + return false, nil +end + +function AceEvent:UnregisterEvent(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[event] and AceEvent_registry[event][self] then + AceEvent_registry[event][self] = nil + local AceEvent_onceRegistry = AceEvent.onceRegistry + if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then + AceEvent_onceRegistry[event][self] = nil + if not next(AceEvent_onceRegistry[event]) then + AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event]) + end + end + local AceEvent_throttleRegistry = AceEvent.throttleRegistry + if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then + AceEvent_throttleRegistry[event][self] = nil + if not next(AceEvent_throttleRegistry[event]) then + AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event]) + end + end + if not next(AceEvent_registry[event]) then + AceEvent_registry[event] = del(AceEvent_registry[event]) + if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent.frame:UnregisterEvent(event) + end + end + else + if self == AceEvent then + error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2) + else + AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self) + end + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) +end + +function AceEvent:UnregisterAllEvents() + local AceEvent_registry = AceEvent.registry + if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then + AceEvent_registry[ALL_EVENTS][self] = nil + if not next(AceEvent_registry[ALL_EVENTS]) then + AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS]) + AceEvent.frame:UnregisterAllEvents() + for k,v in pairs(AceEvent_registry) do + AceEvent.frame:RegisterEvent(k) + end + end + end + if AceEvent_registry.AceEvent_EventUnregistered then + local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered + local x = data[self] + data[self] = nil + if x then + if not next(data) then + if not AceEvent_registry[ALL_EVENTS] then + AceEvent.frame:UnregisterEvent(event) + end + AceEvent_registry[event] = del(AceEvent_registry[event]) + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) + end + end + for event, data in pairs(AceEvent_registry) do + local x = data[self] + data[self] = nil + if x and event ~= ALL_EVENTS then + if not next(data) then + if not AceEvent_registry[ALL_EVENTS] then + AceEvent.frame:UnregisterEvent(event) + end + AceEvent_registry[event] = del(AceEvent_registry[event]) + end + AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) + end + end + if AceEvent.onceRegistry then + for event, data in pairs(AceEvent.onceRegistry) do + data[self] = nil + end + end +end + +function AceEvent:CancelAllScheduledEvents() + if delayRegistry then + for k,v in pairs(delayRegistry) do + if v.self == self then + if not useTablesAsIDs or type(k) == "string" then + del(delayRegistry[k]) + end + delayRegistry[k] = nil + end + end + if not next(delayRegistry) then + AceEvent.frame:Hide() + end + end +end + +function AceEvent:IsEventRegistered(event) + AceEvent:argCheck(event, 2, "string") + local AceEvent_registry = AceEvent.registry + if self == AceEvent then + return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false + end + if AceEvent_registry[event] and AceEvent_registry[event][self] then + return true, AceEvent_registry[event][self] + end + if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then + return true, AceEvent_registry[ALL_EVENTS][self] + end + return false, nil +end + +local UnitExists = UnitExists +local bucketfunc +function AceEvent:RegisterBucketEvent(event, delay, method, ...) + AceEvent:argCheck(event, 2, "string", "table") + if type(event) == "table" then + for k,v in pairs(event) do + if type(k) ~= "number" then + AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.") + elseif type(v) ~= "string" then + AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.") + end + end + end + AceEvent:argCheck(delay, 3, "number") + if AceEvent == self then + AceEvent:argCheck(method, 4, "function") + self = method + else + if type(event) == "string" then + AceEvent:argCheck(method, 4, "string", "function", "nil") + if not method then + method = event + end + else + AceEvent:argCheck(method, 4, "string", "function") + end + + if type(method) == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) + end + end + local buckets = AceEvent.buckets + if not buckets[event] then + buckets[event] = new() + end + if not buckets[event][self] then + local t = new() + t.current = new() + t.self = self + buckets[event][self] = t + else + AceEvent.CancelScheduledEvent(self, buckets[event][self].id) + end + local bucket = buckets[event][self] + bucket.method = method + + local n = select('#', ...) + if n > 0 then + for i = 1, n do + bucket[i] = select(i, ...) + end + end + bucket.n = n + + local func = function(arg1) + bucket.run = true + if arg1 then + bucket.current[arg1] = true + end + end + buckets[event][self].func = func + local isUnitBucket = true + if type(event) == "string" then + AceEvent.RegisterEvent(self, event, func) + if not event:find("^UNIT_") then + isUnitBucket = false + end + else + for _,v in ipairs(event) do + AceEvent.RegisterEvent(self, v, func) + if isUnitBucket and not v:find("^UNIT_") then + isUnitBucket = false + end + end + end + bucket.unit = isUnitBucket + if not bucketfunc then + bucketfunc = function(bucket) + local current = bucket.current + local method = bucket.method + local self = bucket.self + if bucket.run then + if bucket.unit then + for unit in pairs(current) do + if not UnitExists(unit) then + current[unit] = nil + end + end + end + if type(method) == "string" then + self[method](self, current, unpack(bucket, 1, bucket.n)) + elseif method then -- function + method(current, unpack(bucket, 1, bucket.n)) + end + for k in pairs(current) do + current[k] = nil + k = nil + end + bucket.run = false + end + end + end + bucket.id = "AceEvent-Bucket-" .. tostring(bucket) + AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket) +end + +function AceEvent:IsBucketEventRegistered(event) + AceEvent:argCheck(event, 2, "string", "table") + return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self] +end + +function AceEvent:UnregisterBucketEvent(event) + AceEvent:argCheck(event, 2, "string", "table") + if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then + AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self) + end + + local bucket = AceEvent.buckets[event][self] + + if type(event) == "string" then + AceEvent.UnregisterEvent(self, event) + else + for _,v in ipairs(event) do + AceEvent.UnregisterEvent(self, v) + end + end + AceEvent:CancelScheduledEvent(bucket.id) + + bucket.current = del(bucket.current) + AceEvent.buckets[event][self] = del(bucket) + if not next(AceEvent.buckets[event]) then + AceEvent.buckets[event] = del(AceEvent.buckets[event]) + end +end + +function AceEvent:UnregisterAllBucketEvents() + if not AceEvent.buckets or not next(AceEvent.buckets) then + return + end + for k,v in pairs(AceEvent.buckets) do + if v == self then + AceEvent.UnregisterBucketEvent(self, k) + k = nil + end + end +end + +local combatSchedules +function AceEvent:CancelAllCombatSchedules() + local i = 0 + while true do + i = i + 1 + if not combatSchedules[i] then + break + end + local v = combatSchedules[i] + if v.self == self then + v = del(v) + table.remove(combatSchedules, i) + i = i - 1 + end + end +end + +local inCombat = false + +function AceEvent:PLAYER_REGEN_DISABLED() + inCombat = true +end + +do + local tmp = {} + function AceEvent:PLAYER_REGEN_ENABLED() + inCombat = false + for i, v in ipairs(combatSchedules) do + tmp[i] = v + combatSchedules[i] = nil + end + for i, v in ipairs(tmp) do + local func = v.func + if func then + local success, err = pcall(func, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + else + local obj = v.obj or v.self + local method = v.method + local obj_method = obj[method] + if obj_method then + local success, err = pcall(obj_method, obj, unpack(v, 1, v.n)) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + end + end + tmp[i] = del(v) + end + end +end + +function AceEvent:ScheduleLeaveCombatAction(method, ...) + local style = type(method) + if self == AceEvent then + if style == "table" then + local func = (...) + AceEvent:argCheck(func, 3, "string") + if type(method[func]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) + end + else + AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table") + end + self = method + else + AceEvent:argCheck(method, 2, "function", "string", "table") + if style == "string" and type(self[method]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method) + elseif style == "table" then + local func = (...) + AceEvent:argCheck(func, 3, "string") + if type(method[func]) ~= "function" then + AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func) + end + end + end + + if not inCombat then + local success, err + if type(method) == "function" then + success, err = pcall(method, ...) + elseif type(method) == "table" then + local func = (...) + success, err = pcall(method[func], method, select(2, ...)) + else + success, err = pcall(self[method], self, ...) + end + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end + return + end + local t + local n = select('#', ...) + if style == "table" then + t = new(select(2, ...)) + t.obj = method + t.method = (...) + t.n = n-1 + else + t = new(...) + t.n = n + if style == "function" then + t.func = method + else + t.method = method + end + end + t.self = self + table.insert(combatSchedules, t) +end + +function AceEvent:OnEmbedDisable(target) + self.UnregisterAllEvents(target) + + self.CancelAllScheduledEvents(target) + + self.UnregisterAllBucketEvents(target) + + self.CancelAllCombatSchedules(target) +end + +function AceEvent:IsFullyInitialized() + return self.postInit or false +end + +function AceEvent:IsPostPlayerLogin() + return IsLoggedIn() and true or false +end + +local function activate(self, oldLib, oldDeactivate) + AceEvent = self + + self.onceRegistry = oldLib and oldLib.onceRegistry or {} + self.throttleRegistry = oldLib and oldLib.throttleRegistry or {} + self.delayRegistry = oldLib and oldLib.delayRegistry or {} + self.buckets = oldLib and oldLib.buckets or {} + self.registry = oldLib and oldLib.registry or {} + self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame") + self.playerLogin = IsLoggedIn() and true + self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true + self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy() + self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy() + self.RATE = oldLib and oldLib.RATE or _G.newproxy() + self.combatSchedules = oldLib and oldLib.combatSchedules or {} + self.UID_NUM = oldLib and oldLib.UID_NUM or 0 + + -- Delete this down the road. Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered. + local addonframes = oldLib and oldLib.addonframes + if addonframes then + for _, v in pairs(addonframes) do + v:UnregisterAllEvents() + end + end + + combatSchedules = self.combatSchedules + ALL_EVENTS = self.ALL_EVENTS + FAKE_NIL = self.FAKE_NIL + RATE = self.RATE + local inPlw = false + local blacklist = { + UNIT_INVENTORY_CHANGED = true, + BAG_UPDATE = true, + ITEM_LOCK_CHANGED = true, + ACTIONBAR_SLOT_CHANGED = true, + } + self.frame:SetScript("OnEvent", function(_, event, ...) + if event == "PLAYER_ENTERING_WORLD" then + inPlw = false + elseif event == "PLAYER_LEAVING_WORLD" then + inPlw = true + end + if event and (not inPlw or not blacklist[event]) then + self:TriggerEvent(event, ...) + end + end) + if self.delayRegistry then + delayRegistry = self.delayRegistry + self.frame:SetScript("OnUpdate", OnUpdate) + end + + self:UnregisterAllEvents() + self:CancelAllScheduledEvents() + + registeringFromAceEvent = true + self:RegisterEvent("LOOT_OPENED", function() + SendAddonMessage("LOOT_OPENED", "", "RAID") + end) + registeringFromAceEvent = nil + + local function handleFullInit() + if not self.postInit then + local function func() + self.postInit = true + self:TriggerEvent("AceEvent_FullyInitialized") + if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then + self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") + end + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + self:UnregisterEvent("MEETINGSTONE_CHANGED") + end + if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then + self:UnregisterEvent("MINIMAP_ZONE_CHANGED") + end + if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then + self:UnregisterEvent("LANGUAGE_LIST_CHANGED") + end + collectgarbage('collect') + end + registeringFromAceEvent = true + local f = function() + self.playerLogin = true + self:ScheduleEvent("AceEvent_FullyInitialized", func, 1) + end + self:RegisterEvent("MEETINGSTONE_CHANGED", f, true) + self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function() + self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15) + end) + self:RegisterEvent("LANGUAGE_LIST_CHANGED", function() + if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then + registeringFromAceEvent = true + self:UnregisterEvent("MEETINGSTONE_CHANGED") + self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true) + registeringFromAceEvent = nil + end + end) + self:ScheduleEvent("AceEvent_FullyInitialized", func, 10) + registeringFromAceEvent = nil + end + end + + if not self.playerLogin then + registeringFromAceEvent = true + self:RegisterEvent("PLAYER_LOGIN", function() + self.playerLogin = true + handleFullInit() + handleFullInit = nil + collectgarbage('collect') + end, true) + registeringFromAceEvent = nil + else + handleFullInit() + handleFullInit = nil + end + + if not AceEvent20EditBox then + CreateFrame("Editbox", "AceEvent20EditBox") + end + local editbox = AceEvent20EditBox + function editbox:Execute(line) + local defaulteditbox = DEFAULT_CHAT_FRAME.editBox + self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType")) + self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget")) + self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget")) + self:SetText(line) + ChatEdit_SendText(self) + end + editbox:Hide() + _G["SLASH_IN1"] = "/in" + SlashCmdList["IN"] = function(msg) + local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$") + seconds = tonumber(seconds) + if not seconds then + DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'") + return + end + if IsSecureCmd(command) then + DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command)) + return + end + self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest) + end + registeringFromAceEvent = true + self:RegisterEvent("PLAYER_REGEN_ENABLED") + self:RegisterEvent("PLAYER_REGEN_DISABLED") + inCombat = InCombatLockdown() + registeringFromAceEvent = nil + + -- another hack to make sure that we clean up properly from rev 33121 - 36174 + if self.registry[ALL_EVENTS] then + self.frame:RegisterAllEvents() + else + for event in pairs(self.registry) do + self.frame:RegisterEvent(event) + end + end + + self:activate(oldLib, oldDeactivate) + if oldLib then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceLibrary/AceLibrary.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,856 @@ +--[[ +Name: AceLibrary +Revision: $Rev: 49421 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Iriel (iriel@vigilance-committee.org) + Tekkub (tekkub@gmail.com) + Revision: $Rev: 49421 $ +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceLibrary +SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary +Description: Versioning library to handle other library instances, upgrading, + and proper access. + It also provides a base for libraries to work off of, providing + proper error tools. It is handy because all the errors occur in the + file that called it, not in the library file itself. +Dependencies: None +License: LGPL v2.1 +]] + +local ACELIBRARY_MAJOR = "AceLibrary" +local ACELIBRARY_MINOR = "$Revision: 49421 $" + +local _G = getfenv(0) +local previous = _G[ACELIBRARY_MAJOR] +if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end + +do + -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info + -- LibStub is hereby placed in the Public Domain -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke + local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! + local LibStub = _G[LIBSTUB_MAJOR] + + if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) + end +end +local LibStub = _G.LibStub + +-- If you don't want AceLibrary to enable libraries that are LoadOnDemand but +-- disabled in the addon screen, set this to true. +local DONT_ENABLE_LIBRARIES = nil + +local function safecall(func,...) + local success, err = pcall(func,...) + if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end +end + +local WoW22 = false +if type(GetBuildInfo) == "function" then + local success, buildinfo = pcall(GetBuildInfo) + if success and type(buildinfo) == "string" then + local num = tonumber(buildinfo:match("^(%d+%.%d+)")) + if num and num >= 2.2 then + WoW22 = true + end + end +end + +-- @table AceLibrary +-- @brief System to handle all versioning of libraries. +local AceLibrary = {} +local AceLibrary_mt = {} +setmetatable(AceLibrary, AceLibrary_mt) + +local function error(self, message, ...) + if type(self) ~= "table" then + return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) + end + + local stack = debugstack() + if not message then + local second = stack:match("\n(.-)\n") + message = "error raised! " .. second + else + local arg = { ... } -- not worried about table creation, as errors don't happen often + + for i = 1, #arg do + arg[i] = tostring(arg[i]) + end + for i = 1, 10 do + table.insert(arg, "nil") + end + message = message:format(unpack(arg)) + end + + if getmetatable(self) and getmetatable(self).__tostring then + message = ("%s: %s"):format(tostring(self), message) + elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then + message = ("%s: %s"):format(self:GetLibraryVersion(), message) + elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then + message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) + end + + local first = stack:gsub("\n.*", "") + local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + + + local i = 0 + for s in stack:gmatch("\n([^\n]*)") do + i = i + 1 + if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") + file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") + break + end + end + local j = 0 + for s in stack:gmatch("\n([^\n]*)") do + j = j + 1 + if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then + return _G.error(message, j+1) + end + end + return _G.error(message, 2) +end + +local assert +if not WoW22 then + function assert(self, condition, message, ...) + if not condition then + if not message then + local stack = debugstack() + local second = stack:match("\n(.-)\n") + message = "assertion failed! " .. second + end + return error(self, message, ...) + end + return condition + end +end + +local type = type +local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) + if type(num) ~= "number" then + return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) + elseif type(kind) ~= "string" then + return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) + end + arg = type(arg) + if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then + local stack = debugstack() + local func = stack:match("`argCheck'.-([`<].-['>])") + if not func then + func = stack:match("([`<].-['>])") + end + if kind5 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) + elseif kind4 then + return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) + elseif kind3 then + return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) + elseif kind2 then + return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) + else + return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) + end + end +end + +local pcall +do + local function check(self, ret, ...) + if not ret then + local s = ... + return error(self, (s:gsub(".-%.lua:%d-: ", ""))) + else + return ... + end + end + + function pcall(self, func, ...) + return check(self, _G.pcall(func, ...)) + end +end + +local recurse = {} +local function addToPositions(t, major) + if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then + rawset(t, recurse, true) + AceLibrary.positions[t] = major + for k,v in pairs(t) do + if type(v) == "table" and not rawget(v, recurse) then + addToPositions(v, major) + end + if type(k) == "table" and not rawget(k, recurse) then + addToPositions(k, major) + end + end + local mt = getmetatable(t) + if mt and not rawget(mt, recurse) then + addToPositions(mt, major) + end + rawset(t, recurse, nil) + end +end + +local function svnRevisionToNumber(text) + local kind = type(text) + if kind == "number" or tonumber(text) then + return tonumber(text) + elseif kind == "string" then + if text:find("^%$Revision: (%d+) %$$") then + return tonumber((text:match("^%$Revision: (%d+) %$$"))) + elseif text:find("^%$Rev: (%d+) %$$") then + return tonumber((text:match("^%$Rev: (%d+) %$$"))) + elseif text:find("^%$LastChangedRevision: (%d+) %$$") then + return tonumber((text:match("^%$LastChangedRevision: (%d+) %$$"))) + end + end + return nil +end + +local crawlReplace +do + local recurse = {} + local function func(t, to, from) + if recurse[t] then + return + end + recurse[t] = true + local mt = getmetatable(t) + setmetatable(t, nil) + rawset(t, to, rawget(t, from)) + rawset(t, from, nil) + for k,v in pairs(t) do + if v == from then + t[k] = to + elseif type(v) == "table" then + if not recurse[v] then + func(v, to, from) + end + end + + if type(k) == "table" then + if not recurse[k] then + func(k, to, from) + end + end + end + setmetatable(t, mt) + if mt then + if mt == from then + setmetatable(t, to) + elseif not recurse[mt] then + func(mt, to, from) + end + end + end + function crawlReplace(t, to, from) + func(t, to, from) + for k in pairs(recurse) do + recurse[k] = nil + end + end +end + +-- @function destroyTable +-- @brief remove all the contents of a table +-- @param t table to destroy +local function destroyTable(t) + setmetatable(t, nil) + for k,v in pairs(t) do + t[k] = nil + end +end + +local function isFrame(frame) + return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" +end + +-- @function copyTable +-- @brief Create a shallow copy of a table and return it. +-- @param from The table to copy from +-- @return A shallow copy of the table +local function copyTable(from, to) + if not to then + to = {} + end + for k,v in pairs(from) do + to[k] = v + end + setmetatable(to, getmetatable(from)) + return to +end + +-- @function deepTransfer +-- @brief Fully transfer all data, keeping proper previous table +-- backreferences stable. +-- @param to The table with which data is to be injected into +-- @param from The table whose data will be injected into the first +-- @param saveFields If available, a shallow copy of the basic data is saved +-- in here. +-- @param list The account of table references +-- @param list2 The current status on which tables have been traversed. +local deepTransfer +do + -- @function examine + -- @brief Take account of all the table references to be shared + -- between the to and from tables. + -- @param to The table with which data is to be injected into + -- @param from The table whose data will be injected into the first + -- @param list An account of the table references + local function examine(to, from, list, major) + list[from] = to + for k,v in pairs(from) do + if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then + if from[k] == to[k] then + list[from[k]] = to[k] + elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then + list[from[k]] = from[k] + elseif not list[from[k]] then + examine(to[k], from[k], list, major) + end + end + end + return list + end + + function deepTransfer(to, from, saveFields, major, list, list2) + setmetatable(to, nil) + if not list then + list = {} + list2 = {} + examine(to, from, list, major) + end + list2[to] = to + for k,v in pairs(to) do + if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then + if saveFields then + saveFields[k] = v + end + to[k] = nil + elseif v ~= _G then + if saveFields then + saveFields[k] = copyTable(v) + end + end + end + for k in pairs(from) do + if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then + if not list2[to[k]] then + deepTransfer(to[k], from[k], nil, major, list, list2) + end + to[k] = list[to[k]] or list2[to[k]] + else + rawset(to, k, from[k]) + end + end + setmetatable(to, getmetatable(from)) + local mt = getmetatable(to) + if mt then + if list[mt] then + setmetatable(to, list[mt]) + elseif mt.__index and list[mt.__index] then + mt.__index = list[mt.__index] + end + end + destroyTable(from) + end +end + +local function TryToEnable(addon) + if DONT_ENABLE_LIBRARIES then return end + local isondemand = IsAddOnLoadOnDemand(addon) + if isondemand then + local _, _, _, enabled = GetAddOnInfo(addon) + EnableAddOn(addon) + local _, _, _, _, loadable = GetAddOnInfo(addon) + if not loadable and not enabled then + DisableAddOn(addon) + end + + return loadable + end +end + +-- @method TryToLoadStandalone +-- @brief Attempt to find and load a standalone version of the requested library +-- @param major A string representing the major version +-- @return If library is found and loaded, true is return. If not loadable, false is returned. +-- If the library has been requested previously, nil is returned. +local function TryToLoadStandalone(major) + if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end + if AceLibrary.scannedlibs[major] then return end + + AceLibrary.scannedlibs[major] = true + + local name, _, _, enabled, loadable = GetAddOnInfo(major) + + loadable = (enabled and loadable) or TryToEnable(name) + + local loaded = false + if loadable then + loaded = true + LoadAddOn(name) + end + + local field = "X-AceLibrary-" .. major + for i = 1, GetNumAddOns() do + if GetAddOnMetadata(i, field) then + name, _, _, enabled, loadable = GetAddOnInfo(i) + + loadable = (enabled and loadable) or TryToEnable(name) + if loadable then + loaded = true + LoadAddOn(name) + end + end + end + return loaded +end + +-- @method IsNewVersion +-- @brief Obtain whether the supplied version would be an upgrade to the +-- current version. This allows for bypass code in library +-- declaration. +-- @param major A string representing the major version +-- @param minor An integer or an svn revision string representing the minor version +-- @return whether the supplied version would be newer than what is +-- currently available. +function AceLibrary:IsNewVersion(major, minor) + argCheck(self, major, 2, "string") + TryToLoadStandalone(major) + + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + local lib, oldMinor = LibStub:GetLibrary(major, true) + if lib then + return oldMinor < minor + end + local data = self.libs[major] + if not data then + return true + end + return data.minor < minor +end + +-- @method HasInstance +-- @brief Returns whether an instance exists. This allows for optional support of a library. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return Whether an instance exists. +function AceLibrary:HasInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local lib, ver = LibStub:GetLibrary(major, true) + if not lib and self.libs[major] then + lib, ver = self.libs[major].instance, self.libs[major].minor + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 3, "number") + if not lib then + return false + end + return ver == minor + end + return not not lib +end + +-- @method GetInstance +-- @brief Returns the library with the given major/minor version. +-- @param major A string representing the major version. +-- @param minor (optional) An integer or an svn revision string representing the minor version. +-- @return The library with the given major/minor version. +function AceLibrary:GetInstance(major, minor) + argCheck(self, major, 2, "string") + if minor ~= false then + TryToLoadStandalone(major) + end + + local data, ver = LibStub:GetLibrary(major, true) + if not data then + if self.libs[major] then + data, ver = self.libs[major].instance, self.libs[major].minor + else + _G.error(("Cannot find a library instance of %s."):format(major), 2) + return + end + end + if minor then + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 2, "number") + if ver ~= minor then + _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) + end + end + return data +end + +-- Syntax sugar. AceLibrary("FooBar-1.0") +AceLibrary_mt.__call = AceLibrary.GetInstance + +local donothing = function() end + +local AceEvent + +local tmp = {} + +-- @method Register +-- @brief Registers a new version of a given library. +-- @param newInstance the library to register +-- @param major the major version of the library +-- @param minor the minor version of the library +-- @param activateFunc (optional) A function to be called when the library is +-- fully activated. Takes the arguments +-- (newInstance [, oldInstance, oldDeactivateFunc]). If +-- oldInstance is given, you should probably call +-- oldDeactivateFunc(oldInstance). +-- @param deactivateFunc (optional) A function to be called by a newer library's +-- activateFunc. +-- @param externalFunc (optional) A function to be called whenever a new +-- library is registered. +function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) + argCheck(self, newInstance, 2, "table") + argCheck(self, major, 3, "string") + if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == newInstance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end + if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then + _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) + end + if type(minor) == "string" then + local m = svnRevisionToNumber(minor) + if m then + minor = m + else + _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) + end + end + argCheck(self, minor, 4, "number") + if math.floor(minor) ~= minor or minor < 0 then + error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) + end + argCheck(self, activateFunc, 5, "function", "nil") + argCheck(self, deactivateFunc, 6, "function", "nil") + argCheck(self, externalFunc, 7, "function", "nil") + if not deactivateFunc then + deactivateFunc = donothing + end + local data = self.libs[major] + if not data then + -- This is new + if LibStub:GetLibrary(major, true) then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + end + local instance = LibStub:NewLibrary(major, minor) + copyTable(newInstance, instance) + crawlReplace(instance, instance, newInstance) + destroyTable(newInstance) + if AceLibrary == newInstance then + self = instance + AceLibrary = instance + end + self.libs[major] = { + instance = instance, + minor = minor, + deactivateFunc = deactivateFunc, + externalFunc = externalFunc, + } + rawset(instance, 'GetLibraryVersion', function(self) + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + addToPositions(instance, major) + if activateFunc then + safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + end + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + for k,data in pairs(self.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end + if major == "AceEvent-2.0" then + AceEvent = instance + end + if AceEvent then + AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) + end + + return instance + end + if minor <= data.minor then + -- This one is already obsolete, raise an error. + _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2) + return + end + local instance = data.instance + -- This is an update + local oldInstance = {} + + local libStubInstance = LibStub:GetLibrary(major, true) + if not libStubInstance then -- non-LibStub AceLibrary registered the library + -- pass + elseif libStubInstance ~= instance then + error(self, "Cannot register library %q. It is already registered with LibStub.", major) + else + LibStub:NewLibrary(major, minor) -- upgrade the minor version + end + + addToPositions(newInstance, major) + local isAceLibrary = (AceLibrary == newInstance) + local old_error, old_assert, old_argCheck, old_pcall + if isAceLibrary then + self = instance + AceLibrary = instance + + old_error = instance.error + if not WoW22 then + old_assert = instance.assert + end + old_argCheck = instance.argCheck + old_pcall = instance.pcall + + self.error = error + if not WoW22 then + self.assert = assert + end + self.argCheck = argCheck + self.pcall = pcall + end + deepTransfer(instance, newInstance, oldInstance, major) + crawlReplace(instance, instance, newInstance) + local oldDeactivateFunc = data.deactivateFunc + data.minor = minor + data.deactivateFunc = deactivateFunc + data.externalFunc = externalFunc + rawset(instance, 'GetLibraryVersion', function() + return major, minor + end) + if not rawget(instance, 'error') then + rawset(instance, 'error', error) + end + if not WoW22 and not rawget(instance, 'assert') then + rawset(instance, 'assert', assert) + end + if not rawget(instance, 'argCheck') then + rawset(instance, 'argCheck', argCheck) + end + if not rawget(instance, 'pcall') then + rawset(instance, 'pcall', pcall) + end + if isAceLibrary then + for _,v in pairs(self.libs) do + local i = type(v) == "table" and v.instance + if type(i) == "table" then + if not rawget(i, 'error') or i.error == old_error then + rawset(i, 'error', error) + end + if not WoW22 and (not rawget(i, 'assert') or i.assert == old_assert) then + rawset(i, 'assert', assert) + end + if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then + rawset(i, 'argCheck', argCheck) + end + if not rawget(i, 'pcall') or i.pcall == old_pcall then + rawset(i, 'pcall', pcall) + end + end + end + end + if activateFunc then + safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) + +--[[ if major ~= ACELIBRARY_MAJOR then + for k,v in pairs(_G) do + if v == instance then + geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) + end + end + end]] + else + safecall(oldDeactivateFunc, oldInstance) + end + oldInstance = nil + + if externalFunc then + for k, data_instance in LibStub:IterateLibraries() do -- all libraries + tmp[k] = data_instance + end + for k, data in pairs(self.libs) do -- Ace libraries which may not have been registered with LibStub + tmp[k] = data.instance + end + for k, data_instance in pairs(tmp) do + if k ~= major then + safecall(externalFunc, instance, k, data_instance) + end + tmp[k] = nil + end + end + + return instance +end + +function AceLibrary:IterateLibraries() + local t = {} + for major, instance in LibStub:IterateLibraries() do + t[major] = instance + end + for major, data in pairs(self.libs) do + t[major] = data.instance + end + return pairs(t) +end + +local function manuallyFinalize(major, instance) + if AceLibrary.libs[major] then + -- don't work on Ace libraries + return + end + local finalizedExternalLibs = AceLibrary.finalizedExternalLibs + if finalizedExternalLibs[major] then + return + end + finalizedExternalLibs[major] = true + + for k,data in pairs(AceLibrary.libs) do -- only Ace libraries + if k ~= major and data.externalFunc then + safecall(data.externalFunc, data.instance, major, instance) + end + end +end + +-- @function Activate +-- @brief The activateFunc for AceLibrary itself. Called when +-- AceLibrary properly registers. +-- @param self Reference to AceLibrary +-- @param oldLib (optional) Reference to an old version of AceLibrary +-- @param oldDeactivate (optional) Function to deactivate the old lib +local function activate(self, oldLib, oldDeactivate) + AceLibrary = self + if not self.libs then + self.libs = oldLib and oldLib.libs or {} + self.scannedlibs = oldLib and oldLib.scannedlibs or {} + end + if not self.positions then + self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" }) + end + self.finalizedExternalLibs = oldLib and oldLib.finalizedExternalLibs or {} + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("ADDON_LOADED") + self.frame:SetScript("OnEvent", function() + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + end) + for major, instance in LibStub:IterateLibraries() do + manuallyFinalize(major, instance) + end + + -- Expose the library in the global environment + _G[ACELIBRARY_MAJOR] = self + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +if not previous then + previous = AceLibrary +end +if not previous.libs then + previous.libs = {} +end +AceLibrary.libs = previous.libs +if not previous.positions then + previous.positions = setmetatable({}, { __mode = "k" }) +end +AceLibrary.positions = previous.positions +AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate, nil)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceLocale-2.2/AceLocale-2.2.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,669 @@ +--[[ +Name: AceLocale-2.2 +Revision: $Rev: 40629 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceLocale-2.2 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2 +Description: Localization library for addons to use to handle proper + localization and internationalization. +Dependencies: AceLibrary +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "AceLocale-2.2" +local MINOR_VERSION = "$Revision: 40629 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local AceLocale = {} +AceLocale.prototype = { class = AceLocale } + +local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME + +local _G = _G +local rawget = rawget +local rawset = rawset +local type = type +local pairs = pairs +local next = next +local getmetatable = getmetatable +local setmetatable = setmetatable +local GetTime = GetTime +local geterrorhandler = geterrorhandler +local pcall = pcall +local ipairs = ipairs +local GetLocale = GetLocale + +local newRegistries = {} +local scheduleClear + +local lastSelf +local strict__index = function(self, key) + lastSelf = self + local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key] + rawset(self, key, value) + return value +end +local nonstrict__index = function(self, key) + lastSelf = self + local t = rawget(self, TRANSLATIONS) + if t then + local value = rawget(t, key) + if value then + rawset(self, key, value) + return value + end + end + local value = (rawget(self, BASE_TRANSLATIONS) or AceLocale.prototype)[key] + rawset(self, key, value) + return value +end + +local __newindex = function(self, k, v) + if type(v) ~= "function" and type(k) ~= "table" then + AceLocale.error(self, "Cannot change the values of an AceLocale instance.") + end + rawset(self, k, v) +end + +local __tostring = function(self) + if type(rawget(self, 'GetLibraryVersion')) == "function" then + return self:GetLibraryVersion() + else + return "AceLocale(" .. self[NAME] .. ")" + end +end + +local function clearCache(self) + for k, v in pairs(AceLocale.prototype) do + if type(v) == "function" and type(rawget(self, k)) == "function" then + self[k] = nil + end + end + if not rawget(self, BASE_TRANSLATIONS) then + return + end + + local cache = self[BASE_TRANSLATIONS] + rawset(self, REVERSE_TRANSLATIONS, nil) + + for k in pairs(self) do + if rawget(cache, k) ~= nil then + self[k] = nil + end + end + rawset(self, 'tmp', true) + self.tmp = nil +end + +local strict_instance_mt, nonstrict_instance_mt +local baseTranslations_mt + +local function refixInstance(instance) + if getmetatable(instance) then + setmetatable(instance, nil) + end + local translations = instance[TRANSLATIONS] + if translations then + if getmetatable(translations) then + setmetatable(translations, nil) + end + local baseTranslations = instance[BASE_TRANSLATIONS] + if getmetatable(baseTranslations) then + setmetatable(baseTranslations, nil) + end + if translations == baseTranslations or instance[STRICTNESS] then + setmetatable(instance, strict_instance_mt) + + setmetatable(translations, baseTranslations_mt) + else + setmetatable(instance, nonstrict_instance_mt) + + setmetatable(baseTranslations, baseTranslations_mt) + end + else + setmetatable(instance, strict_instance_mt) + end + clearCache(instance) + newRegistries[instance] = true + scheduleClear() + return instance +end + +function AceLocale:new(name) + self:argCheck(name, 2, "string") + + if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then + return self.registry[name] + end + + AceLocale.registry[name] = refixInstance({ + [STRICTNESS] = false, + [NAME] = name, + }) + newRegistries[AceLocale.registry[name]] = true + return AceLocale.registry[name] +end + +function AceLocale.prototype:EnableDebugging() + if rawget(self, BASE_TRANSLATIONS) then + AceLocale.error(self, "Cannot enable debugging after a translation has been registered.") + end + rawset(self, DEBUGGING, true) +end + +function AceLocale.prototype:EnableDynamicLocales(override) + AceLocale.argCheck(self, override, 2, "boolean", "nil") + if not override and rawget(self, BASE_TRANSLATIONS) then + AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.") + end + if not rawget(self, DYNAMIC_LOCALES) then + rawset(self, DYNAMIC_LOCALES, true) + if rawget(self, BASE_LOCALE) then + if not rawget(self, TRANSLATION_TABLES) then + rawset(self, TRANSLATION_TABLES, {}) + end + self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS] + self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS] + end + end +end + +function AceLocale.prototype:RegisterTranslations(locale, func) + AceLocale.argCheck(self, locale, 2, "string") + AceLocale.argCheck(self, func, 3, "function") + + if locale == rawget(self, BASE_LOCALE) then + AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) + end + + if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then + if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then + if not rawget(self, TRANSLATION_TABLES) then + rawset(self, TRANSLATION_TABLES, {}) + end + if self[TRANSLATION_TABLES][locale] then + AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) + end + local t = func() + func = nil + if type(t) ~= "table" then + AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) + end + self[TRANSLATION_TABLES][locale] = t + t = nil + end + func = nil + return + end + local t = func() + func = nil + if type(t) ~= "table" then + AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) + end + + rawset(self, TRANSLATIONS, t) + if not rawget(self, BASE_TRANSLATIONS) then + rawset(self, BASE_TRANSLATIONS, t) + rawset(self, BASE_LOCALE, locale) + for key,value in pairs(t) do + if value == true then + t[key] = key + end + end + else + for key, value in pairs(self[TRANSLATIONS]) do + if not rawget(self[BASE_TRANSLATIONS], key) then + AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) + end + if value == true then + AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale) + end + end + end + rawset(self, CURRENT_LOCALE, locale) + if not rawget(self, 'reverse') then + rawset(self, 'reverse', setmetatable({}, { __index = function(self2, key) + local self = AceLocale.reverseToBase[self2] + if not rawget(self, REVERSE_TRANSLATIONS) then + self:GetReverseTranslation(key) + end + self.reverse = self[REVERSE_TRANSLATIONS] + return self.reverse[key] + end })) + AceLocale.reverseToBase[self.reverse] = self + end + refixInstance(self) + if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then + if not rawget(self, TRANSLATION_TABLES) then + rawset(self, TRANSLATION_TABLES, {}) + end + self[TRANSLATION_TABLES][locale] = t + end + t = nil +end + +function AceLocale.prototype:SetLocale(locale) + AceLocale.argCheck(self, locale, 2, "string", "boolean") + if not rawget(self, DYNAMIC_LOCALES) then + AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.") + end + if not rawget(self, TRANSLATION_TABLES) then + AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.") + end + if locale == true then + locale = GetLocale() + if not self[TRANSLATION_TABLES][locale] then + locale = self[BASE_LOCALE] + end + end + + if self[CURRENT_LOCALE] == locale then + return + end + + if not self[TRANSLATION_TABLES][locale] then + AceLocale.error(self, "Locale %q not registered.", locale) + end + + self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale] + self[CURRENT_LOCALE] = locale + refixInstance(self) +end + +function AceLocale.prototype:GetLocale() + if not rawget(self, TRANSLATION_TABLES) then + AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.") + end + return self[CURRENT_LOCALE] +end + +local function iter(t, position) + return (next(t, position)) +end + +function AceLocale.prototype:IterateAvailableLocales() + if not rawget(self, DYNAMIC_LOCALES) then + AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.") + end + if not rawget(self, TRANSLATION_TABLES) then + AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.") + end + return iter, self[TRANSLATION_TABLES], nil +end + +function AceLocale.prototype:HasLocale(locale) + if not rawget(self, DYNAMIC_LOCALES) then + AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.") + end + AceLocale.argCheck(self, locale, 2, "string") + return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil +end + +function AceLocale.prototype:SetStrictness(strict) + AceLocale.argCheck(self, strict, 2, "boolean") + local mt = getmetatable(self) + if not mt then + AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.") + end + if not rawget(self, TRANSLATIONS) then + AceLocale.error(self, "No translations registered.") + end + rawset(self, STRICTNESS, strict) + refixInstance(self) +end + +local function initReverse(self) + rawset(self, REVERSE_TRANSLATIONS, setmetatable({}, { __index = function(_, key) + AceLocale.error(self, "Reverse translation for %q does not exist", key) + end })) + local alpha = self[TRANSLATIONS] + local bravo = self[REVERSE_TRANSLATIONS] + for base, localized in pairs(alpha) do + bravo[localized] = base + end +end + +function AceLocale.prototype:GetTranslation(text) + AceLocale.argCheck(self, text, 1, "string", "number") + if not rawget(self, TRANSLATIONS) then + AceLocale.error(self, "No translations registered") + end + return self[text] +end + +function AceLocale.prototype:GetStrictTranslation(text) + AceLocale.argCheck(self, text, 1, "string", "number") + local x = rawget(self, TRANSLATIONS) + if not x then + AceLocale.error(self, "No translations registered") + end + local value = rawget(x, text) + if value == nil then + local _, ret = pcall(AceLocale.error, self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE]) + geterrorhandler()(ret) + return text + end + return value +end + +function AceLocale.prototype:GetReverseTranslation(text) + local x = rawget(self, REVERSE_TRANSLATIONS) + if not x then + if not rawget(self, TRANSLATIONS) then + AceLocale.error(self, "No translations registered") + end + initReverse(self) + x = self[REVERSE_TRANSLATIONS] + end + local translation = x[text] + if not translation then + local _, ret = pcall(AceLocale.error, self, "Reverse translation for %q does not exist", text) + geterrorhandler()(ret) + return text + end + return translation +end + +function AceLocale.prototype:GetIterator() + local x = rawget(self, TRANSLATIONS) + if not x then + AceLocale.error(self, "No translations registered") + end + return next, x, nil +end + +function AceLocale.prototype:GetReverseIterator() + local x = rawget(self, REVERSE_TRANSLATIONS) + if not x then + if not rawget(self, TRANSLATIONS) then + AceLocale.error(self, "No translations registered") + end + initReverse(self) + x = self[REVERSE_TRANSLATIONS] + end + return next, x, nil +end + +function AceLocale.prototype:HasTranslation(text) + AceLocale.argCheck(self, text, 1, "string", "number") + local x = rawget(self, TRANSLATIONS) + if not x then + AceLocale.error(self, "No translations registered") + end + return rawget(x, text) and true +end + +function AceLocale.prototype:HasBaseTranslation(text) + AceLocale.argCheck(self, text, 1, "string", "number") + local x = rawget(self, BASE_TRANSLATIONS) + if not x then + AceLocale.error(self, "No translations registered") + end + return rawget(x, text) and true +end + +function AceLocale.prototype:HasReverseTranslation(text) + local x = rawget(self, REVERSE_TRANSLATIONS) + if not x then + if not rawget(self, TRANSLATIONS) then + AceLocale.error(self, "No translations registered") + end + initReverse(self) + x = self[REVERSE_TRANSLATIONS] + end + return rawget(x, text) and true +end + +function AceLocale.prototype:Debug() + if not rawget(self, DEBUGGING) then + return + end + local words = {} + local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"} + local localizations = {} + DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---") + for _,locale in ipairs(locales) do + if not self[TRANSLATION_TABLES][locale] then + DEFAULT_CHAT_FRAME:AddMessage(("Locale %q not found"):format(locale)) + else + localizations[locale] = self[TRANSLATION_TABLES][locale] + end + end + local localeDebug = {} + for locale, localization in pairs(localizations) do + localeDebug[locale] = {} + for word in pairs(localization) do + if type(localization[word]) == "table" then + if type(words[word]) ~= "table" then + words[word] = {} + end + for bit in pairs(localization[word]) do + if type(localization[word][bit]) == "string" then + words[word][bit] = true + end + end + elseif type(localization[word]) == "string" then + words[word] = true + end + end + end + for word in pairs(words) do + if type(words[word]) == "table" then + for bit in pairs(words[word]) do + for locale, localization in pairs(localizations) do + if not rawget(localization, word) or not localization[word][bit] then + localeDebug[locale][word .. "::" .. bit] = true + end + end + end + else + for locale, localization in pairs(localizations) do + if not rawget(localization, word) then + localeDebug[locale][word] = true + end + end + end + end + for locale, t in pairs(localeDebug) do + if not next(t) then + DEFAULT_CHAT_FRAME:AddMessage(("Locale %q complete"):format(locale)) + else + DEFAULT_CHAT_FRAME:AddMessage(("Locale %q missing:"):format(locale)) + for word in pairs(t) do + DEFAULT_CHAT_FRAME:AddMessage((" %q"):format(word)) + end + end + end + DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---") +end + +setmetatable(AceLocale.prototype, { + __index = function(self, k) + if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later. + local _, ret = pcall(AceLocale.error, lastSelf or self, "Translation %q does not exist.", k) + geterrorhandler()(ret) + return k + end + return nil + end +}) + +local function activate(self, oldLib, oldDeactivate) + AceLocale = self + + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.registry = oldLib and oldLib.registry or {} + self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {} + self.DEBUGGING = oldLib and oldLib.DEBUGGING or {} + self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {} + self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {} + self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {} + self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {} + self.STRICTNESS = oldLib and oldLib.STRICTNESS or {} + self.NAME = oldLib and oldLib.NAME or {} + self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {} + self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {} + self.reverseToBase = oldLib and oldLib.reverseToBase or {} + + BASE_TRANSLATIONS = self.BASE_TRANSLATIONS + DEBUGGING = self.DEBUGGING + TRANSLATIONS = self.TRANSLATIONS + BASE_LOCALE = self.BASE_LOCALE + TRANSLATION_TABLES = self.TRANSLATION_TABLES + REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS + STRICTNESS = self.STRICTNESS + NAME = self.NAME + DYNAMIC_LOCALES = self.DYNAMIC_LOCALES + CURRENT_LOCALE = self.CURRENT_LOCALE + + strict_instance_mt = { + __index = strict__index, + __newindex = __newindex, + __tostring = __tostring + } + + nonstrict_instance_mt = { + __index = nonstrict__index, + __newindex = __newindex, + __tostring = __tostring + } + + baseTranslations_mt = { + __index = AceLocale.prototype + } + + local GetTime = GetTime + local timeUntilClear = GetTime() + 5 + scheduleClear = function() + if next(newRegistries) then + self.frame:Show() + timeUntilClear = GetTime() + 5 + end + end + + for name, instance in pairs(self.registry) do + local name = name + setmetatable(instance, nil) + instance[NAME] = name + local strict + if instance[STRICTNESS] ~= nil then + strict = instance[STRICTNESS] + elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then + if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then + strict = true + end + end + instance[STRICTNESS] = strict and true or false + refixInstance(instance) + end + + self.frame:SetScript("OnEvent", scheduleClear) + self.frame:SetScript("OnUpdate", function() -- (this, elapsed) + if timeUntilClear - GetTime() <= 0 then + self.frame:Hide() + for k in pairs(newRegistries) do + clearCache(k) + newRegistries[k] = nil + k = nil + end + end + end) + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("ADDON_LOADED") + self.frame:RegisterEvent("PLAYER_ENTERING_WORLD") + self.frame:Show() + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate) +--[[ +if true then -- debug + local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3") + L:RegisterTranslations("enUS", function() return { + Monkey = true, + House = true, + } end) + + L:RegisterTranslations("deDE", function() return { + Monkey = "Affe" + } end) + + L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG" or "AceLocale_DEBUG3") + assert(L.Monkey == "Monkey") + assert(L.House == "House") + if not L.Debug then + local pants = L.Pants + assert(not pants) + end + assert(L.Debug) + assert(L.Debug == AceLocale.prototype.Debug) + + if MINOR_VERSION == 100000 then + L = AceLocale:new("AceLocale_DEBUG") + assert(L.Monkey == "Monkey") + assert(L.House == "House") + assert(L.Debug) + assert(type(L.Debug) == "function") + assert(AceLocale.prototype.Debug) + assert(type(AceLocale.prototype.Debug) == "function") + assert(L.Debug == AceLocale.prototype.Debug) + end + + local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4") + L:RegisterTranslations("deDE", function() return { + Affe = true, + Haus = true, + } end) + + L:RegisterTranslations("enUS", function() return { + Affe = "Monkey" + } end) + + L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG2" or "AceLocale_DEBUG4") + assert(L.Affe == "Monkey") + assert(L.Haus == "Haus") + assert(L.Debug) + assert(L.Debug == AceLocale.prototype.Debug) + + if MINOR_VERSION == 100000 then + L = AceLocale:new("AceLocale_DEBUG2") + assert(L.Affe == "Monkey") + assert(L.Haus == "Haus") + assert(L.Debug) + assert(L.Debug == AceLocale.prototype.Debug) + end + + local L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6") + L:RegisterTranslations("deDE", function() return { + Affe = true, + Haus = true, + } end) + + L:RegisterTranslations("enUS", function() return { + Affe = "Monkey" + } end) + + L:SetStrictness(true) + + L = AceLocale:new(MINOR_VERSION ~= 100000 and "AceLocale_DEBUG5" or "AceLocale_DEBUG6") + assert(L.Affe == "Monkey") + assert(L.Haus == "Haus") + assert(L.Debug) + assert(L.Debug == AceLocale.prototype.Debug) + + if MINOR_VERSION == 100000 then + L = AceLocale:new("AceLocale_DEBUG5") + assert(L.Affe == "Monkey") + assert(L.Haus == "Haus") + assert(L.Debug) + assert(L.Debug == AceLocale.prototype.Debug) + end +end +]] \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/AceOO-2.0/AceOO-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,980 @@ +--[[ +Name: AceOO-2.0 +Revision: $Rev: 38641 $ +Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) +Inspired By: Ace 1.x by Turan (turan@gryphon.com) +Website: http://www.wowace.com/ +Documentation: http://www.wowace.com/index.php/AceOO-2.0 +SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 +Description: Library to provide an object-orientation framework. +Dependencies: AceLibrary +License: MIT +]] + +local MAJOR_VERSION = "AceOO-2.0" +local MINOR_VERSION = "$Revision: 38641 $" + +-- This ensures the code is only executed if the libary doesn't already exist, or is a newer version +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local AceOO = { + error = AceLibrary.error, + argCheck = AceLibrary.argCheck +} + +-- @function getuid +-- @brief Obtain a unique string identifier for the object in question. +-- @param t The object to obtain the uid for. +-- @return The uid string. +local function getuid(t) + local mt = getmetatable(t) + setmetatable(t, nil) + local str = tostring(t) + setmetatable(t, mt) + local cap = str:match("[^:]*: 0x(.*)$") or str:match("[^:]*: (.*)$") + if cap then + return ("0"):rep(8 - #cap) .. cap + end +end + +local function getlibrary(o) + if type(o) == "table" then + return o + elseif type(o) == "string" then + if not AceLibrary:HasInstance(o) then + AceOO:error("Library %q does not exist.", o) + end + return AceLibrary(o) + end +end + +local function deeprawget(self, k) + while true do + local v = rawget(self, k) + if v ~= nil then + return v + end + local mt = getmetatable(self) + if not mt or type(mt.__index) ~= "table" then + return nil + end + self = mt.__index + end +end + +-- @function Factory +-- @brief Construct a factory for the creation of objects. +-- @param obj The object whose init method will be called on the new factory +-- object. +-- @param newobj The object whose init method will be called on the new +-- objects that the Factory creates, to initialize them. +-- @param (...) Arguments which will be passed to obj.init() in addition +-- to the Factory object. +-- @return The new factory which creates a newobj when its new method is called, +-- or when it is called directly (__call metamethod). +local Factory +do + local function getlibraries(...) + if select('#', ...) == 0 then + return + end + return getlibrary((select(1, ...))), getlibraries(select(2, ...)) + end + local arg = {} + local function new(obj, ...) + local t = {} + local uid = getuid(t) + obj:init(t, getlibraries(...)) + t.uid = uid + return t + end + + local function createnew(self, ...) + local o = self.prototype + local x = new(o, getlibraries(...)) + return x + end + + function Factory(obj, newobj, ...) + local t = new(obj, ...) + t.prototype = newobj + t.new = createnew + getmetatable(t).__call = t.new + return t + end +end + + +local function objtostring(self) + if self.ToString then + return self:ToString() + elseif self.GetLibraryVersion then + return (self:GetLibraryVersion()) + elseif self.super then + local s = "Sub-" .. tostring(self.super) + local first = true + if self.interfaces then + for interface in pairs(self.interfaces) do + if first then + s = s .. "(" .. tostring(interface) + first = false + else + s = s .. ", " .. tostring(interface) + end + end + end + if self.mixins then + for mixin in pairs(self.mixins) do + if first then + s = s .. tostring(mixin) + first = false + else + s = s .. ", " .. tostring(mixin) + end + end + end + if first then + if self.uid then + return s .. ":" .. self.uid + else + return s + end + else + return s .. ")" + end + else + return self.uid and 'Subclass:' .. self.uid or 'Subclass' + end +end + +-- @table Object +-- @brief Base of all objects, including Class. +-- +-- @method init +-- @brief Initialize a new object. +-- @param newobject The object to initialize +-- @param class The class to make newobject inherit from +local Object +do + Object = {} + function Object:init(newobject, class) + local parent = class or self + if not rawget(newobject, 'uid') then + newobject.uid = getuid(newobject) + end + local mt = { + __index = parent, + __tostring = objtostring, + } + setmetatable(newobject, mt) + end + Object.uid = getuid(Object) + setmetatable(Object, { __tostring = function() return 'Object' end }) +end + +local Interface + +local function validateInterface(object, interface) + if not object.class and object.prototype then + object = object.prototype + end + for k,v in pairs(interface.interface) do + if tostring(type(object[k])) ~= v then + return false + end + end + if interface.superinterfaces then + for superinterface in pairs(interface.superinterfaces) do + if not validateInterface(object, superinterface) then + return false + end + end + end + if type(object.class) == "table" and rawequal(object.class.prototype, object) then + if not object.class.interfaces then + rawset(object.class, 'interfaces', {}) + end + object.class.interfaces[interface] = true + elseif type(object.class) == "table" and type(object.class.prototype) == "table" then + validateInterface(object.class.prototype, interface) + -- check if class is proper, thus preventing future checks. + end + return true +end + +-- @function inherits +-- @brief Return whether an Object or Class inherits from a given +-- parent. +-- @param object Object or Class to check +-- @param parent Parent to test inheritance from +-- @return whether an Object or Class inherits from a given +-- parent. +local function inherits(object, parent) + object = getlibrary(object) + if type(parent) == "string" then + if not AceLibrary:HasInstance(parent) then + return false + else + parent = AceLibrary(parent) + end + end + AceOO:argCheck(parent, 2, "table") + if type(object) ~= "table" then + return false + end + local current + local class = deeprawget(object, 'class') + if class then + current = class + else + current = object + end + if type(current) ~= "table" then + return false + end + if rawequal(current, parent) then + return true + end + if parent.class then + while true do + if rawequal(current, Object) then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if rawequal(mixin, parent) then + return true + end + end + end + if current.interfaces then + for interface in pairs(current.interfaces) do + if rawequal(interface, parent) then + return true + end + end + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + break + end + end + + local isInterface = false + local curr = parent.class + while true do + if rawequal(curr, Object) then + break + elseif rawequal(curr, Interface) then + isInterface = true + break + end + curr = deeprawget(curr, 'super') + if type(curr) ~= "table" then + break + end + end + return isInterface and validateInterface(object, parent) + else + while true do + if rawequal(current, parent) then + return true + elseif rawequal(current, Object) then + return false + end + current = deeprawget(current, 'super') + if type(current) ~= "table" then + return false + end + end + end +end + +-- @table Class +-- @brief An object factory which sets up inheritence and supports +-- 'mixins'. +-- +-- @metamethod Class call +-- @brief Call ClassFactory:new() to create a new class. +-- +-- @method Class new +-- @brief Construct a new object. +-- @param (...) Arguments to pass to the object init function. +-- @return The new object. +-- +-- @method Class init +-- @brief Initialize a new class. +-- @param parent Superclass. +-- @param (...) Mixins. +-- +-- @method Class ToString +-- @return A string representing the object, in this case 'Class'. +local initStatus +local Class +local Mixin +local autoEmbed = false +local function traverseInterfaces(bit, total) + if bit.superinterfaces then + for interface in pairs(bit.superinterfaces) do + if not total[interface] then + total[interface] = true + traverseInterfaces(interface, total) + end + end + end +end +local class_new +do + Class = Factory(Object, setmetatable({}, {__index = Object}), Object) + Class.super = Object + + local function protostring(t) + return '<' .. tostring(t.class) .. ' prototype>' + end + local function classobjectstring(t) + if t.ToString then + return t:ToString() + elseif t.GetLibraryVersion then + return (t:GetLibraryVersion()) + else + return '<' .. tostring(t.class) .. ' instance>' + end + end + local function classobjectequal(self, other) + if type(self) == "table" and self.Equals then + return self:Equals(other) + elseif type(other) == "table" and other.Equals then + return other:Equals(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) == 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) == 0 + else + return rawequal(self, other) + end + end + local function classobjectlessthan(self, other) + if type(self) == "table" and self.IsLessThan then + return self:IsLessThan(other) + elseif type(other) == "table" and other.IsLessThanOrEqualTo then + return not other:IsLessThanOrEqualTo(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) < 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) > 0 + elseif type(other) == "table" and other.IsLessThan and other.Equals then + return other:Equals(self) or other:IsLessThan(self) + else + AceOO:error("cannot compare two objects") + end + end + local function classobjectlessthanequal(self, other) + if type(self) == "table" and self.IsLessThanOrEqualTo then + return self:IsLessThanOrEqualTo(other) + elseif type(other) == "table" and other.IsLessThan then + return not other:IsLessThan(self) + elseif type(self) == "table" and self.CompareTo then + return self:CompareTo(other) <= 0 + elseif type(other) == "table" and other.CompareTo then + return other:CompareTo(self) >= 0 + elseif type(self) == "table" and self.IsLessThan and self.Equals then + return self:Equals(other) or self:IsLessThan(other) + else + AceOO:error("cannot compare two incompatible objects") + end + end + local function classobjectadd(self, other) + if type(self) == "table" and self.Add then + return self:Add(other) + else + AceOO:error("cannot add two incompatible objects") + end + end + local function classobjectsub(self, other) + if type(self) == "table" and self.Subtract then + return self:Subtract(other) + else + AceOO:error("cannot subtract two incompatible objects") + end + end + local function classobjectunm(self, other) + if type(self) == "table" and self.UnaryNegation then + return self:UnaryNegation(other) + else + AceOO:error("attempt to negate an incompatible object") + end + end + local function classobjectmul(self, other) + if type(self) == "table" and self.Multiply then + return self:Multiply(other) + else + AceOO:error("cannot multiply two incompatible objects") + end + end + local function classobjectdiv(self, other) + if type(self) == "table" and self.Divide then + return self:Divide(other) + else + AceOO:error("cannot divide two incompatible objects") + end + end + local function classobjectpow(self, other) + if type(self) == "table" and self.Exponent then + return self:Exponent(other) + else + AceOO:error("cannot exponentiate two incompatible objects") + end + end + local function classobjectconcat(self, other) + if type(self) == "table" and self.Concatenate then + return self:Concatenate(other) + else + AceOO:error("cannot concatenate two incompatible objects") + end + end + function class_new(self, ...) + if self.virtual then + AceOO:error("Cannot instantiate a virtual class.") + end + + local o = self.prototype + local newobj = {} + if o.class and o.class.instancemeta then + setmetatable(newobj, o.class.instancemeta) + else + Object:init(newobj, o) + end + + if self.interfaces and not self.interfacesVerified then + -- Verify the interfaces + + for interface in pairs(self.interfaces) do + for field,kind in pairs(interface.interface) do + if tostring(type(newobj[field])) ~= kind then + AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) + end + end + end + self.interfacesVerified = true + end + local tmp = initStatus + initStatus = newobj + newobj:init(...) + if initStatus then + initStatus = tmp + AceOO:error("Initialization not completed, be sure to call the superclass's init method.") + return + end + initStatus = tmp + return newobj + end + local classmeta = { + __tostring = objtostring, + __call = function(self, ...) + return self:new(...) + end, + } + function Class:init(newclass, parent, ...) + parent = parent or self + + local total + + if parent.class then + total = { parent, ... } + parent = self + else + total = { ... } + end + if not inherits(parent, Class) then + AceOO:error("Classes must inherit from a proper class") + end + if parent.sealed then + AceOO:error("Cannot inherit from a sealed class") + end + for i,v in ipairs(total) do + if inherits(v, Mixin) and v.class then + if v.__deprecated then + AceOO:error(v.__deprecated) + end + if not newclass.mixins then + newclass.mixins = {} + end + if newclass.mixins[v] then + AceOO:error("Cannot explicitly inherit from the same mixin twice") + end + newclass.mixins[v] = true + elseif inherits(v, Interface) and v.class then + if not newclass.interfaces then + newclass.interfaces = {} + end + if newclass.interfaces[v] then + AceOO:error("Cannot explicitly inherit from the same interface twice") + end + newclass.interfaces[v] = true + else + AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") + end + end + if parent.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(parent.interfaces) do + newclass.interfaces[interface] = true + end + end + for k in pairs(total) do + total[k] = nil + end + + newclass.super = parent + + newclass.prototype = setmetatable(total, { + __index = parent.prototype, + __tostring = protostring, + }) + total = nil + + newclass.instancemeta = { + __index = newclass.prototype, + __tostring = classobjectstring, + __eq = classobjectequal, + __lt = classobjectlessthan, + __le = classobjectlessthanequal, + __add = classobjectadd, + __sub = classobjectsub, + __unm = classobjectunm, + __mul = classobjectmul, + __div = classobjectdiv, + __pow = classobjectpow, + __concat = classobjectconcat, + } + + setmetatable(newclass, classmeta) + + newclass.new = class_new + + if newclass.mixins then + -- Fold in the mixins + local err, msg + for mixin in pairs(newclass.mixins) do + local ret + autoEmbed = true + ret, msg = pcall(mixin.embed, mixin, newclass.prototype) + autoEmbed = false + if not ret then + err = true + break + end + end + + if err then + local pt = newclass.prototype + for k,v in pairs(pt) do + pt[k] = nil + end + + -- method conflict + AceOO:error(msg) + end + end + + newclass.prototype.class = newclass + + if newclass.interfaces then + for interface in pairs(newclass.interfaces) do + traverseInterfaces(interface, newclass.interfaces) + end + end + if newclass.mixins then + for mixin in pairs(newclass.mixins) do + if mixin.interfaces then + if not newclass.interfaces then + newclass.interfaces = {} + end + for interface in pairs(mixin.interfaces) do + newclass.interfaces[interface] = true + end + end + end + end + end + function Class:ToString() + if type(self.GetLibraryVersion) == "function" then + return (self:GetLibraryVersion()) + else + return "Class" + end + end + + local tmp + function Class.prototype:init() + if rawequal(self, initStatus) then + initStatus = nil + else + AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) + end + self.uid = getuid(self) + local current = self.class + while true do + if current == Class then + break + end + if current.mixins then + for mixin in pairs(current.mixins) do + if type(mixin.OnInstanceInit) == "function" then + mixin:OnInstanceInit(self) + end + end + end + current = current.super + end + end +end + + +-- @object ClassFactory +-- @brief A factory for creating classes. Rarely used directly. +local ClassFactory = Factory(Object, Class, Object) + +function Class:new(...) + local x = ClassFactory:new(...) + if AceOO.classes then + AceOO.classes[x] = true + end + return x +end +getmetatable(Class).__call = Class.new + +-- @class Mixin +-- @brief A class to create mixin objects, which contain methods that get +-- "mixed in" to class prototypes. +-- +-- @object Mixin prototype +-- @brief The prototype that mixin objects inherit their methods from. +-- +-- @method Mixin prototype embed +-- @brief Mix in the methods of our object which are listed in our interface +-- to the supplied target table. +-- +-- @method Mixin prototype init +-- @brief Initialize the mixin object. +-- @param newobj The new object we're initializing. +-- @param interface The interface we implement (the list of methods our +-- prototype provides which should be mixed into the target +-- table by embed). +do + Mixin = Class() + function Mixin:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Mixin' + end + end + local function _Embed(state, field, target) + field = next(state.export, field) + if field == nil then + return + end + + if rawget(target, field) or (target[field] and target[field] ~= state[field]) then + AceOO:error("Method conflict in attempt to mixin. Field %q", field) + end + + target[field] = state[field] + + local ret,msg = pcall(_Embed, state, field, target) + if not ret then + -- Mix in the next method according to the defined interface. If that + -- fails due to a conflict, re-raise to back out the previous mixed + -- methods. + + target[field] = nil + AceOO:error(msg) + end + end + function Mixin.prototype:embed(target) + if self.__deprecated then + AceOO:error(self.__deprecated) + end + local mt = getmetatable(target) + setmetatable(target, nil) + local err, msg = pcall(_Embed, self, nil, target) + if not err then + setmetatable(target, mt) + AceOO:error(msg) + return + end + if type(self.embedList) == "table" then + self.embedList[target] = true + end + if type(target.class) ~= "table" then + target[self] = true + end + if not autoEmbed and type(self.OnManualEmbed) == "function" then + self:OnManualEmbed(target) + end + setmetatable(target, mt) + end + + function Mixin.prototype:activate(oldLib, oldDeactivate) + if oldLib and oldLib.embedList then + for target in pairs(oldLib.embedList) do + local mt = getmetatable(target) + setmetatable(target, nil) + for field in pairs(oldLib.export) do + target[field] = nil + end + setmetatable(target, mt) + end + self.embedList = oldLib.embedList + for target in pairs(self.embedList) do + self:embed(target) + end + else + self.embedList = setmetatable({}, {__mode="k"}) + end + end + + function Mixin.prototype:init(export, ...) + AceOO:argCheck(export, 2, "table") + for k,v in pairs(export) do + if type(k) ~= "number" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + end + end + local num = #export + for i = 1, num do + local v = export[i] + export[i] = nil + export[v] = true + end + + local interfaces + if select('#', ...) >= 1 then + interfaces = { ... } + for i,v in ipairs(interfaces) do + v = getlibrary(v) + interfaces[i] = v + if not v.class or not inherits(v, Interface) then + AceOO:error("Mixins can inherit only from interfaces") + end + end + local num = #interfaces + for i = 1, num do + local v = interfaces[i] + interfaces[i] = nil + interfaces[v] = true + end + for interface in pairs(interfaces) do + traverseInterfaces(interface, interfaces) + end + for interface in pairs(interfaces) do + for field,kind in pairs(interface.interface) do + if kind ~= "nil" then + local good = false + for bit in pairs(export) do + if bit == field then + good = true + break + end + end + if not good then + AceOO:error("Mixin does not fully accommodate field %q", field) + end + end + end + end + end + self.super = Mixin.prototype + Mixin.super.prototype.init(self) + self.export = export + self.interfaces = interfaces + end +end + +-- @class Interface +-- @brief A class to create interfaces, which contain contracts that classes +-- which inherit from this must comply with. +-- +-- @object Interface prototype +-- @brief The prototype that interface objects must adhere to. +-- +-- @method Interface prototype init +-- @brief Initialize the mixin object. +-- @param interface The interface we contract (the hash of fields forced). +-- @param (...) Superinterfaces +do + Interface = Class() + function Interface:ToString() + if self.GetLibraryVersion then + return (self:GetLibraryVersion()) + else + return 'Instance' + end + end + function Interface.prototype:init(interface, ...) + Interface.super.prototype.init(self) + AceOO:argCheck(interface, 2, "table") + for k,v in pairs(interface) do + if type(k) ~= "string" then + AceOO:error("All keys to argument #2 must be numbers.") + elseif type(v) ~= "string" then + AceOO:error("All values to argument #2 must be strings.") + elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then + AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') + end + end + if select('#', ...) >= 1 then + self.superinterfaces = { ... } + for i,v in ipairs(self.superinterfaces) do + v = getlibrary(v) + self.superinterfaces[i] = v + if not inherits(v, Interface) or not v.class then + AceOO:error('Cannot provide a non-Interface to inherit from') + end + end + local num = #self.superinterfaces + for i = 1, num do + local v = self.superinterfaces[i] + self.superinterfaces[i] = nil + self.superinterfaces[v] = true + end + end + self.interface = interface + end +end + +-- @function Classpool +-- @brief Obtain a read only class from our pool of classes, indexed by the +-- superclass and mixins. +-- @param sc The superclass of the class we want. +-- @param (m1..m20) Mixins of the class we want's objects. +-- @return A read only class from the class pool. +local Classpool +do + local pool = setmetatable({}, {__mode = 'v'}) + local function newindex(k, v) + AceOO:error('Attempt to modify a read-only class.') + end + local function protonewindex(k, v) + AceOO:error('Attempt to modify a read-only class prototype.') + end + local function ts(bit) + if type(bit) ~= "table" then + return tostring(bit) + elseif getmetatable(bit) and bit.__tostring then + return tostring(bit) + elseif type(bit.GetLibraryVersion) == "function" then + return bit:GetLibraryVersion() + else + return tostring(bit) + end + end + local t = {} + local function getcomplexuid(sc, ...) + if sc then + if sc.uid then + table.insert(t, sc.uid) + else + AceOO:error("%s is not an appropriate class/mixin", ts(sc)) + end + end + for i = 1, select('#', ...) do + local m = select(i, ...) + if m.uid then + table.insert(t, m.uid) + else + AceOO:error("%s is not an appropriate mixin", ts(m)) + end + end + table.sort(t) + local uid = table.concat(t, '') + local num = #t + for i = 1, num do + t[i] = nil + end + return uid + end + local classmeta + local arg = {} + function Classpool(superclass, ...) + local l = getlibrary + superclass = getlibrary(superclass) + arg = { ... } + for i, v in ipairs(arg) do + arg[i] = getlibrary(v) + end + if superclass then + if superclass.class then -- mixin + table.insert(arg, 1, superclass) + superclass = Class + end + else + superclass = Class + end + local key = getcomplexuid(superclass, unpack(arg)) + if not pool[key] then + local class = Class(superclass, unpack(arg)) + if not classmeta then + classmeta = {} + local mt = getmetatable(class) + for k,v in pairs(mt) do + classmeta[k] = v + end + classmeta.__newindex = newindex + end + -- Prevent the user from adding methods to this class. + -- NOTE: I'm not preventing modifications of existing class members, + -- but it's likely that only a truly malicious user will be doing so. + class.sealed = true + setmetatable(class, classmeta) + getmetatable(class.prototype).__newindex = protonewindex + pool[key] = class + end + return pool[key] + end +end + +AceOO.Factory = Factory +AceOO.Object = Object +AceOO.Class = Class +AceOO.Mixin = Mixin +AceOO.Interface = Interface +AceOO.Classpool = Classpool +AceOO.inherits = inherits + +-- Library handling bits + +local function activate(self, oldLib, oldDeactivate) + AceOO = self + Factory = self.Factory + Object = self.Object + Class = self.Class + ClassFactory.prototype = Class + Mixin = self.Mixin + Interface = self.Interface + Classpool = self.Classpool + + if oldLib then + self.classes = oldLib.classes + end + if not self.classes then + self.classes = setmetatable({}, {__mode="k"}) + else + for class in pairs(self.classes) do + class.new = class_new + end + end + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) +AceOO = AceLibrary(MAJOR_VERSION)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/Dewdrop-2.0/Dewdrop-2.0.lua Fri Mar 07 22:10:55 2008 +0000 @@ -0,0 +1,3487 @@ +--[[ +Name: Dewdrop-2.0 +Revision: $Rev: 48630 $ +Author(s): ckknight (ckknight@gmail.com) +Website: http://ckknight.wowinterface.com/ +Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0 +SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0 +Description: A library to provide a clean dropdown menu interface. +Dependencies: AceLibrary +License: LGPL v2.1 +]] + +local MAJOR_VERSION = "Dewdrop-2.0" +local MINOR_VERSION = "$Revision: 48630 $" + +if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end +if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end + +local Dewdrop = {} + +local SharedMedia + +local CLOSE = "Close" +local CLOSE_DESC = "Close the menu." +local VALIDATION_ERROR = "Validation error." +local USAGE_TOOLTIP = "Usage: %s." +local RANGE_TOOLTIP = "Note that you can scroll your mouse wheel while over the slider to step by one." +local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." +local KEY_BUTTON1 = "Left Mouse" +local KEY_BUTTON2 = "Right Mouse" +local DISABLED = "Disabled" +local DEFAULT_CONFIRM_MESSAGE = "Are you sure you want to perform `%s'?" + +if GetLocale() == "deDE" then + CLOSE = "Schlie\195\159en" + CLOSE_DESC = "Men\195\188 schlie\195\159en." + VALIDATION_ERROR = "Validierungsfehler." + USAGE_TOOLTIP = "Benutzung: %s." + RANGE_TOOLTIP = "Beachte das du mit dem Mausrad scrollen kannst solange du \195\188ber dem Schieberegler bist, um 10er Spr\195\188nge zu machen." + RESET_KEYBINDING_DESC = "Escape dr\195\188cken, um die Tastenbelegung zu l\195\182schen." + KEY_BUTTON1 = "Linke Maustaste" + KEY_BUTTON2 = "Rechte Maustaste" + DISABLED = "Deaktiviert" + DEFAULT_CONFIRM_MESSAGE = "Bist du sicher das du `%s' machen willst?" +elseif GetLocale() == "koKR" then + CLOSE = "닫기" + CLOSE_DESC = "메뉴를 닫습니다." + VALIDATION_ERROR = "오류 확인." + USAGE_TOOLTIP = "사용법: %s." + RANGE_TOOLTIP = "알림 : 슬라이더 위에서 마우스 휠을 사용하면 한단계씩 조절할 수 있습니다." + RESET_KEYBINDING_DESC = "단축키를 해제하려면 ESC키를 누르세요." + KEY_BUTTON1 = "왼쪽 마우스" + KEY_BUTTON2 = "오른쪽 마우스" + DISABLED = "비활성화됨" + DEFAULT_CONFIRM_MESSAGE = "정말로 `%s' 실행을 하시겠습니까 ?" +elseif GetLocale() == "frFR" then + CLOSE = "Fermer" + CLOSE_DESC = "Ferme le menu." + VALIDATION_ERROR = "Erreur de validation." + USAGE_TOOLTIP = "Utilisation : %s." + RANGE_TOOLTIP = "Vous pouvez aussi utiliser la molette de la souris pour pour modifier progressivement." + RESET_KEYBINDING_DESC = "Appuyez sur la touche Echappement pour effacer le raccourci." + KEY_BUTTON1 = "Clic gauche" + KEY_BUTTON2 = "Clic droit" + DISABLED = "D\195\169sactiv\195\169" + DEFAULT_CONFIRM_MESSAGE = "\195\138tes-vous s\195\187r de vouloir effectuer '%s' ?" +elseif GetLocale() == "esES" then + CLOSE = "Cerrar" + CLOSE_DESC = "Cierra el menú." + VALIDATION_ERROR = "Error de validación." + USAGE_TOOLTIP = "Uso: %s." + RANGE_TOOLTIP = "Puedes desplazarte verticalmente con la rueda del ratón sobre el desplazador." + RESET_KEYBINDING_DESC = "Pulsa Escape para borrar la asignación de tecla." + KEY_BUTTON1 = "Clic Izquierdo" + KEY_BUTTON2 = "Clic Derecho" + DISABLED = "Desactivado" + DEFAULT_CONFIRM_MESSAGE = "¿Estás seguro de querer realizar `%s'?" +elseif GetLocale() == "zhTW" then + CLOSE = "關閉" + CLOSE_DESC = "關閉選單。" + VALIDATION_ERROR = "驗證錯誤。" + USAGE_TOOLTIP = "用法: %s。" + RANGE_TOOLTIP = "你可以在捲動條上使用滑鼠滾輪來捲動。" + RESET_KEYBINDING_DESC = "按Esc鍵清除快捷鍵。" + KEY_BUTTON1 = "滑鼠左鍵" + KEY_BUTTON2 = "滑鼠右鍵" + DISABLED = "停用" + DEFAULT_CONFIRM_MESSAGE = "是否執行「%s」?" +elseif GetLocale() == "zhCN" then + CLOSE = "关闭" + CLOSE_DESC = "关闭菜单" + VALIDATION_ERROR = "验证错误." + USAGE_TOOLTIP = "用法: %s." + RANGE_TOOLTIP = "你可以在滚动条上使用鼠标滚轮来翻页." + RESET_KEYBINDING_DESC = "按ESC键清除按键绑定" + KEY_BUTTON1 = "鼠标左键" + KEY_BUTTON2 = "鼠标右键" + DISABLED = "禁用" + DEFAULT_CONFIRM_MESSAGE = "是否执行'%s'?" +end + +Dewdrop.KEY_BUTTON1 = KEY_BUTTON1 +Dewdrop.KEY_BUTTON2 = KEY_BUTTON2 + +local function new(...) + local t = {} + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t +end + +local tmp +do + local t = {} + function tmp(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local tmp2 +do + local t = {} + function tmp2(...) + for k in pairs(t) do + t[k] = nil + end + for i = 1, select('#', ...), 2 do + local k = select(i, ...) + if k then + t[k] = select(i+1, ...) + else + break + end + end + return t + end +end +local levels +local buttons + + +-- Secure frame handling: +-- Rather than using secure buttons in the menu (has problems), we have one +-- master secureframe that we pop onto menu items on mouseover. This requires +-- some dark magic with OnLeave etc, but it's not too bad. + +local secureFrame = CreateFrame("Button", nil, nil, "SecureActionButtonTemplate") +secureFrame:Hide() + +local function secureFrame_Show(self) + local owner = self.owner + + if self.secure then -- Leftovers from previos owner, clean up! ("Shouldn't" happen but does..) + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = owner.secure; -- Grab hold of new secure data + + local scale = owner:GetEffectiveScale() + + self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", owner:GetLeft() * scale, owner:GetTop() * scale) + self:SetPoint("BOTTOMRIGHT", nil, "BOTTOMLEFT", owner:GetRight() * scale, owner:GetBottom() * scale) + self:EnableMouse(true) + for k,v in pairs(self.secure) do + self:SetAttribute(k, v) + end + + secureFrame:SetFrameStrata(owner:GetFrameStrata()) + secureFrame:SetFrameLevel(owner:GetFrameLevel()+1) + + self:Show() +end + +local function secureFrame_Hide(self) + self:Hide() + if self.secure then + for k,v in pairs(self.secure) do + self:SetAttribute(k, nil) + end + end + self.secure = nil +end + +secureFrame:SetScript("OnEvent", + function() + if event=="PLAYER_REGEN_ENABLED" then + this.combat = false + if not this:IsShown() and this.owner then + secureFrame_Show(this) + end + elseif event=="PLAYER_REGEN_DISABLED" then + this.combat = true + if this:IsShown() then + secureFrame_Hide(this) + end + end + end +) +secureFrame:RegisterEvent("PLAYER_REGEN_ENABLED") +secureFrame:RegisterEvent("PLAYER_REGEN_DISABLED") + +secureFrame:SetScript("OnLeave", + function() + local owner=this.owner + this:Deactivate() + owner:GetScript("OnLeave")() + end +) + +secureFrame:HookScript("OnClick", + function() + local realthis = this + this = this.owner + this:GetScript("OnClick")() + end +) + +function secureFrame:IsOwnedBy(frame) + return self.owner == frame +end + +function secureFrame:Activate(owner) + if self.owner then -- "Shouldn't" happen but apparently it does and I cba to troubleshoot... + if not self.combat then + secureFrame_Hide(self) + end + end + self.owner = owner + if not self.combat then + secureFrame_Show(self) + end +end + +function secureFrame:Deactivate() + if not self.combat then + secureFrame_Hide(self) + end + self.owner = nil +end + +-- END secure frame utilities + + +-- Underline on mouseover - use a single global underline that we move around, no point in creating lots of copies +local underlineFrame = CreateFrame("Frame", nil) +underlineFrame.tx = underlineFrame:CreateTexture() +underlineFrame.tx:SetTexture(1,1,0.5,0.75) +underlineFrame:SetScript("OnHide", function(this) this:Hide(); end) +underlineFrame:SetScript("OnShow", function(this) -- change sizing on the fly to catch runtime uiscale changes + underlineFrame.tx:SetPoint("TOPLEFT", -1, -2/this:GetEffectiveScale()) + underlineFrame.tx:SetPoint("RIGHT", 1,0) + underlineFrame.tx:SetHeight(0.6 / this:GetEffectiveScale()); +end) +underlineFrame:SetHeight(1) + +-- END underline on mouseover + + +local function GetScaledCursorPosition() + local x, y = GetCursorPosition() + local scale = UIParent:GetEffectiveScale() + return x / scale, y / scale +end + +local function StartCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = 3 + end + end +end + +local function StopCounting(self, level) + for i = level, 1, -1 do + if levels[i] then + levels[i].count = nil + end + end +end + +local function OnUpdate(self, elapsed) + for _,level in ipairs(levels) do + local count = level.count + if count then + count = count - elapsed + if count < 0 then + level.count = nil + self:Close(level.num) + else + level.count = count + end + end + end +end + +local function CheckDualMonitor(self, frame) + local ratio = GetScreenWidth() / GetScreenHeight() + if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then + local offsetx + if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then + offsetx = GetScreenWidth() / 2 - frame:GetRight() + else + offsetx = GetScreenWidth() / 2 - frame:GetLeft() + end + local point, parent, relativePoint, x, y = frame:GetPoint(1) + frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) + end +end + +local function CheckSize(self, level) + if not level.buttons then + return + end + local height = 20 + for _, button in ipairs(level.buttons) do + height = height + button:GetHeight() + end + level:SetHeight(height) + local width = 160 + for _, button in ipairs(level.buttons) do + local extra = 1 + if button.hasArrow or button.hasColorSwatch then + extra = extra + 16 + end + if not button.notCheckable then + extra = extra + 24 + end + button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) + if button.text:GetWidth() + extra > width then + width = button.text:GetWidth() + extra + end + end + level:SetWidth(width + 20) + if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local dirty = false + if not level:GetRight() then + self:Close() + return + end + if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then + level.lastDirection = "LEFT" + dirty = true + elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then + level.lastDirection = "RIGHT" + dirty = true + end + if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then + level.lastVDirection = "DOWN" + dirty = true + elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then + level.lastVDirection = "UP" + dirty = true + end + if dirty then + level:ClearAllPoints() + local parent = level.parent or level:GetParent() + if type(parent) ~= "table" then + parent = UIParent + end + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + if level:GetTop() > GetScreenHeight() then + local top = level:GetTop() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) + elseif level:GetBottom() < 0 then + local bottom = level:GetBottom() + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:ClearAllPoints() + level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) + end + CheckDualMonitor(self, level) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end +end + +local Open +local OpenSlider +local OpenEditBox +local Refresh +local Clear +local function ReleaseButton(self, level, index) + if not level.buttons then + return + end + if not level.buttons[index] then + return + end + local button = level.buttons[index] + button:Hide() + if button.highlight then + button.highlight:Hide() + end +-- button.arrow:SetVertexColor(1, 1, 1) +-- button.arrow:SetHeight(16) +-- button.arrow:SetWidth(16) + table.remove(level.buttons, index) + table.insert(buttons, button) + for k in pairs(button) do + if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then + button[k] = nil + end + end + return true +end + +local function Scroll(self, level, down) + if down then + if level:GetBottom() < 0 then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y + 50) + if level:GetBottom() > 0 then + level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) + end + end + else + if level:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = level:GetPoint(1) + level:SetPoint(point, parent, relativePoint, x, y - 50) + if level:GetTop() < GetScreenHeight() then + level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) + end + end + end +end + +local function getArgs(t, str, num, ...) + local x = t[str .. num] + if x == nil then + return ... + else + return x, getArgs(t, str, num + 1, ...) + end +end + +local sliderFrame +local editBoxFrame + +local normalFont +local lastSetFont +local justSetFont = false +local regionTmp = {} +local function fillRegionTmp(...) + for i = 1, select('#', ...) do + regionTmp[i] = select(i, ...) + end +end + +local function showGameTooltip(this) + if this.tooltipTitle or this.tooltipText then + GameTooltip_SetDefaultAnchor(GameTooltip, this) + local disabled = not this.isTitle and this.disabled + local font + if this.tooltipTitle then + if SharedMedia and SharedMedia:IsValid("font", this.tooltipTitle) then + font = SharedMedia:Fetch("font", this.tooltipTitle) + end + if disabled then + GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) + end + if this.tooltipText then + if not font and SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1) + else + GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) + end + end + else + if SharedMedia and SharedMedia:IsValid("font", this.tooltipText) then + font = SharedMedia:Fetch("font", this.tooltipText) + end + if disabled then + GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) + else + GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) + end + end + if font then + fillRegionTmp(GameTooltip:GetRegions()) + lastSetFont = font + justSetFont = true + for i,v in ipairs(regionTmp) do + if v.SetFont then + local norm,size,outline = v:GetFont() + v:SetFont(font, size, outline) + if not normalFont then + normalFont = norm + end + end + regionTmp[i] = nil + end + elseif not normalFont then + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont and not normalFont then + normalFont = v:GetFont() + end + regionTmp[i] = nil + end + end + GameTooltip:Show() + end + if this.tooltipFunc then + GameTooltip:SetOwner(this, "ANCHOR_NONE") + GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) + this.tooltipFunc(getArgs(this, 'tooltipArg', 1)) + GameTooltip:Show() + end +end + +local tmpt = setmetatable({}, {mode='v'}) +local numButtons = 0 +local function AcquireButton(self, level) + if not levels[level] then + return + end + level = levels[level] + if not level.buttons then + level.buttons = {} + end + local button + if #buttons == 0 then + numButtons = numButtons + 1 + button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) + button:SetFrameStrata("FULLSCREEN_DIALOG") + button:SetHeight(16) + local highlight = button:CreateTexture(nil, "BACKGROUND") + highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") + button.highlight = highlight + highlight:SetBlendMode("ADD") + highlight:SetAllPoints(button) + highlight:Hide() + local check = button:CreateTexture(nil, "ARTWORK") + button.check = check + check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + check:SetPoint("CENTER", button, "LEFT", 12, 0) + check:SetWidth(24) + check:SetHeight(24) + local radioHighlight = button:CreateTexture(nil, "ARTWORK") + button.radioHighlight = radioHighlight + radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") + radioHighlight:SetAllPoints(check) + radioHighlight:SetBlendMode("ADD") + radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) + radioHighlight:Hide() + button:SetScript("OnEnter", function() + if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then + for i = 1, this.level.num do + Refresh(self, levels[i]) + end + return + end + self:Close(this.level.num + 1) + if not this.disabled then + if this.secure then + secureFrame:Activate(this) + elseif this.hasSlider then + OpenSlider(self, this) + elseif this.hasEditBox then + OpenEditBox(self, this) + elseif this.hasArrow then + Open(self, this, nil, this.level.num + 1, this.value) + end + end + if not this.level then -- button reclaimed + return + end + StopCounting(self, this.level.num + 1) + if not this.disabled then + highlight:Show() + if this.isRadio then + button.radioHighlight:Show() + end + if this.mouseoverUnderline then + underlineFrame:SetParent(this) + underlineFrame:SetPoint("BOTTOMLEFT",this.text,0,0) + underlineFrame:SetWidth(this.text:GetWidth()) + underlineFrame:Show() + end + end + showGameTooltip(this) + end) + button:SetScript("OnHide", function() + if this.secure and secureFrame:IsOwnedBy(this) then + secureFrame:Deactivate() + end + end) + button:SetScript("OnLeave", function() + if this.secure and secureFrame:IsShown() then + return; -- it's ok, we didn't actually mouse out of the button, only onto the secure frame on top of it + end + underlineFrame:Hide() + if not this.selected then + highlight:Hide() + end + button.radioHighlight:Hide() + if this.level then + StartCounting(self, this.level.num) + end + GameTooltip:Hide() + end) + local first = true + button:SetScript("OnClick", function() + if not this.disabled then + if this.hasColorSwatch then + local func = button.colorFunc + local hasOpacity = this.hasOpacity + local this = this + for k in pairs(tmpt) do + tmpt[k] = nil + end + for i = 1, 1000 do + local x = this['colorArg'..i] + if x == nil then + break + else + tmpt[i] = x + end + end + ColorPickerFrame.func = function() + if func then + local r,g,b = ColorPickerFrame:GetColorRGB() + local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + tmpt[n+1] = nil + tmpt[n+2] = nil + tmpt[n+3] = nil + tmpt[n+4] = nil + end + end + ColorPickerFrame.hasOpacity = this.hasOpacity + ColorPickerFrame.opacityFunc = ColorPickerFrame.func + ColorPickerFrame.opacity = 1 - this.opacity + ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) + local r, g, b, a = this.r, this.g, this.b, this.opacity + ColorPickerFrame.cancelFunc = function() + if func then + local n = #tmpt + tmpt[n+1] = r + tmpt[n+2] = g + tmpt[n+3] = b + tmpt[n+4] = a + func(unpack(tmpt)) + for i = 1, n+4 do + tmpt[i] = nil + end + end + end + self:Close(1) + ShowUIPanel(ColorPickerFrame) + elseif this.func then + local level = this.level + if type(this.func) == "string" then + if type(this.arg1[this.func]) ~= "function" then + self:error("Cannot call method %q", this.func) + end + this.arg1[this.func](this.arg1, getArgs(this, 'arg', 2)) + else + this.func(getArgs(this, 'arg', 1)) + end + if this.closeWhenClicked then + self:Close() + elseif level:IsShown() then + for i = 1, level.num do + Refresh(self, levels[i]) + end + local value = levels[level.num].value + for i = level.num-1, 1, -1 do + local level = levels[i] + local good = false + for _,button in ipairs(level.buttons) do + if button.value == value then + good = true + break + end + end + if not good then + Dewdrop:Close(i+1) + end + value = levels[i].value + end + end + elseif this.closeWhenClicked then + self:Close() + end + end + end) + local text = button:CreateFontString(nil, "ARTWORK") + button.text = text + text:SetFontObject(GameFontHighlightSmall) + button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) + button:SetScript("OnMouseDown", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) + end + end) + button:SetScript("OnMouseUp", function() + if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then + text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) + end + end) + local arrow = button:CreateTexture(nil, "ARTWORK") + button.arrow = arrow + arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) + arrow:SetWidth(16) + arrow:SetHeight(16) + arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") + local colorSwatch = button:CreateTexture(nil, "ARTWORK") + button.colorSwatch = colorSwatch + colorSwatch:SetWidth(20) + colorSwatch:SetHeight(20) + colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") + local texture = button:CreateTexture(nil, "OVERLAY") + colorSwatch.texture = texture + texture:SetTexture("Interface\\Buttons\\WHITE8X8") + texture:SetWidth(11.5) + texture:SetHeight(11.5) + texture:Show() + texture:SetPoint("CENTER", colorSwatch, "CENTER") + colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) + else + button = table.remove(buttons) + end + button:ClearAllPoints() + button:SetParent(level) + button:SetFrameStrata(level:GetFrameStrata()) + button:SetFrameLevel(level:GetFrameLevel() + 1) + button:SetPoint("LEFT", level, "LEFT", 10, 0) + button:SetPoint("RIGHT", level, "RIGHT", -10, 0) + if #level.buttons == 0 then + button:SetPoint("TOP", level, "TOP", 0, -10) + else + button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) + end + button.text:SetPoint("LEFT", button, "LEFT", 24, 0) + button:Show() + button.level = level + table.insert(level.buttons, button) + if not level.parented then + level.parented = true + level:ClearAllPoints() + if level.num == 1 then + if level.parent ~= UIParent and type(level.parent) == "table" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") + else + level:SetPoint("CENTER", UIParent, "CENTER") + end + else + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) + else + level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) + else + level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) + end + end + end + level:SetFrameStrata("FULLSCREEN_DIALOG") + end + button:SetAlpha(1) + return button +end + +local numLevels = 0 +local function AcquireLevel(self, level) + if not levels[level] then + for i = #levels + 1, level, -1 do + local i = i + numLevels = numLevels + 1 + local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) + if i == 1 then + local old_CloseSpecialWindows = CloseSpecialWindows + function CloseSpecialWindows() + local found = old_CloseSpecialWindows() + if levels[1]:IsShown() then + self:Close() + return 1 + end + return found + end + end + levels[i] = frame + frame.num = i + frame:SetParent(UIParent) + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:Hide() + frame:SetWidth(180) + frame:SetHeight(10) + frame:SetFrameLevel(i * 3) + frame:SetScript("OnHide", function() + self:Close(level + 1) + end) + if frame.SetTopLevel then + frame:SetTopLevel(true) + end + frame:EnableMouse(true) + frame:EnableMouseWheel(true) + local backdrop = CreateFrame("Frame", nil, frame) + backdrop:SetAllPoints(frame) + backdrop:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + frame:SetScript("OnClick", function() + self:Close(i) + end) + frame:SetScript("OnEnter", function() + StopCounting(self, i) + end) + frame:SetScript("OnLeave", function() + StartCounting(self, i) + end) + frame:SetScript("OnMouseWheel", function() + Scroll(self, frame, arg1 < 0) + end) + if i == 1 then + frame:SetScript("OnUpdate", function(this, arg1) + OnUpdate(self, arg1) + end) + levels[1].lastDirection = "RIGHT" + levels[1].lastVDirection = "DOWN" + else + levels[i].lastDirection = levels[i - 1].lastDirection + levels[i].lastVDirection = levels[i - 1].lastVDirection + end + end + end + local fullscreenFrame = GetUIPanel("fullscreen") + local l = levels[level] + local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() + if fullscreenFrame then + l:SetParent(fullscreenFrame) + else + l:SetParent(UIParent) + end + l:SetFrameStrata(strata) + l:SetFrameLevel(framelevel) + l:SetAlpha(1) + return l +end + +local function validateOptions(options, position, baseOptions, fromPass) + if not baseOptions then + baseOptions = options + end + if type(options) ~= "table" then + return "Options must be a table.", position + end + local kind = options.type + if type(kind) ~= "string" then + return '"type" must be a string.', position + elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "dragLink" and kind ~= "header" then + return '"type" must either be "range", "text", "group", "toggle", "execute", "color", "dragLink", or "header".', position + end + if options.aliases then + if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then + return '"alias" must be a table or string', position + end + end + if not fromPass then + if kind == "execute" then + if type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + elseif kind == "range" or kind == "text" or kind == "toggle" then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if kind == "text" and options.get == false then + elseif type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif kind == "group" and options.pass then + if options.pass ~= true then + return '"pass" must be either nil, true, or false', position + end + if not options.func then + if type(options.set) ~= "string" and type(options.set) ~= "function" then + return '"set" must be a string or function', position + end + if type(options.get) ~= "string" and type(options.get) ~= "function" then + return '"get" must be a string or function', position + end + elseif type(options.func) ~= "string" and type(options.func) ~= "function" then + return '"func" must be a string or function', position + end + end + end + if options ~= baseOptions then + if kind == "header" then + elseif type(options.desc) ~= "string" then + return '"desc" must be a string', position + elseif options.desc:len() == 0 then + return '"desc" cannot be a 0-length string', position + end + end + if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then + if options.type == "header" and not options.cmdName and not options.name then + elseif options.cmdName then + if type(options.cmdName) ~= "string" then + return '"cmdName" must be a string or nil', position + elseif options.cmdName:len() == 0 then + return '"cmdName" cannot be a 0-length string', position + end + if type(options.guiName) ~= "string" then + if not options.guiNameIsMap then + return '"guiName" must be a string or nil', position + end + elseif options.guiName:len() == 0 then + return '"guiName" cannot be a 0-length string', position + end + else + if type(options.name) ~= "string" then + return '"name" must be a string', position + elseif options.name:len() == 0 then + return '"name" cannot be a 0-length string', position + end + end + end + if options.guiNameIsMap then + if type(options.guiNameIsMap) ~= "boolean" then + return '"guiNameIsMap" must be a boolean or nil', position + elseif options.type ~= "toggle" then + return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position + elseif type(options.map) ~= "table" then + return '"map" must be a table', position + end + end + if options.message and type(options.message) ~= "string" then + return '"message" must be a string or nil', position + end + if options.error and type(options.error) ~= "string" then + return '"error" must be a string or nil', position + end + if options.current and type(options.current) ~= "string" then + return '"current" must be a string or nil', position + end + if options.order then + if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then + return '"order" must be a non-zero number or nil', position + end + end + if options.disabled then + if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then + return '"disabled" must be a function, string, or boolean', position + end + end + if options.cmdHidden then + if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then + return '"cmdHidden" must be a function, string, or boolean', position + end + end + if options.guiHidden then + if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then + return '"guiHidden" must be a function, string, or boolean', position + end + end + if options.hidden then + if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then + return '"hidden" must be a function, string, or boolean', position + end + end + if kind == "text" then + if type(options.validate) == "table" then + local t = options.validate + local iTable = nil + for k,v in pairs(t) do + if type(k) == "number" then + if iTable == nil then + iTable = true + elseif not iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + elseif k < 1 or k > #t then + return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position + end + else + if iTable == nil then + iTable = false + elseif iTable then + return '"validate" must either have all keys be indexed numbers or strings', position + end + end + if type(v) ~= "string" then + return '"validate" values must all be strings', position + end + end + if options.multiToggle and options.multiToggle ~= true then + return '"multiToggle" must be a boolean or nil if "validate" is a table', position + end + elseif options.validate == "keybinding" then + -- no other checks + else + if type(options.usage) ~= "string" then + return '"usage" must be a string', position + elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then + return '"validate" must be a string, function, or table', position + end + end + if options.multiToggle and type(options.validate) ~= "table" then + return '"validate" must be a table if "multiToggle" is true', position + end + elseif kind == "range" then + if options.min or options.max then + if type(options.min) ~= "number" then + return '"min" must be a number', position + elseif type(options.max) ~= "number" then + return '"max" must be a number', position + elseif options.min >= options.max then + return '"min" must be less than "max"', position + end + end + if options.step then + if type(options.step) ~= "number" then + return '"step" must be a number', position + elseif options.step < 0 then + return '"step" must be nonnegative', position + end + end + if options.bigStep then + if type(options.bigStep) ~= "number" then + return '"bigStep" must be a number', position + elseif options.bigStep < 0 then + return '"bigStep" must be nonnegative', position + end + end + if options.isPercent and options.isPercent ~= true then + return '"isPercent" must either be nil, true, or false', position + end + elseif kind == "toggle" then + if options.map then + if type(options.map) ~= "table" then + return '"map" must be a table', position + elseif type(options.map[true]) ~= "string" then + return '"map[true]" must be a string', position + elseif type(options.map[false]) ~= "string" then + return '"map[false]" must be a string', position + end + end + elseif kind == "color" then + if options.hasAlpha and options.hasAlpha ~= true then + return '"hasAlpha" must be nil, true, or false', position + end + elseif kind == "group" then + if options.pass and options.pass ~= true then + return '"pass" must be nil, true, or false', position + end + if type(options.args) ~= "table" then + return '"args" must be a table', position + end + for k,v in pairs(options.args) do + if type(k) ~= "number" then + if type(k) ~= "string" then + return '"args" keys must be strings or numbers', position + elseif k:len() == 0 then + return '"args" keys must not be 0-length strings.', position + end + end + if type(v) ~= "table" then + return '"args" values must be tables', position and position .. "." .. k or k + end + local newposition + if position then + newposition = position .. ".args." .. k + else + newposition = "args." .. k + end + local err, pos = validateOptions(v, newposition, baseOptions, options.pass) + if err then + return err, pos + end + end + elseif kind == "execute" then + if type(options.confirm) ~= "string" and type(options.confirm) ~= "boolean" and type(options.confirm) ~= "nil" then + return '"confirm" must be a string, boolean, or nil', position + end + end + if options.icon and type(options.icon) ~= "string" then + return'"icon" must be a string', position + end + if options.iconWidth or options.iconHeight then + if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then + return '"iconHeight" and "iconWidth" must be numbers', position + end + end + if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then + if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then + return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position + end + end +end + +local validatedOptions + +local values +local mysort_args +local mysort +local othersort +local othersort_validate + +local baseFunc, currentLevel + +local function confirmPopup(message, func, ...) + if not StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] then + StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] = {} + end + local t = StaticPopupDialogs["DEWDROP20_CONFIRM_DIALOG"] + for k in pairs(t) do + t[k] = nil + end + t.text = message + t.button1 = ACCEPT or "Accept" + t.button2 = CANCEL or "Cancel" + t.OnAccept = function() + func(unpack(t)) + end + for i = 1, select('#', ...) do + t[i] = select(i, ...) + end + t.timeout = 0 + t.whileDead = 1 + t.hideOnEscape = 1 + + Dewdrop:Close() + StaticPopup_Show("DEWDROP20_CONFIRM_DIALOG") +end + + +local function getMethod(settingname, handler, v, methodName, ...) -- "..." is simply returned straight out cause you can't do "a,b,c = 111,f(),222" + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + return method, ... + elseif type(method)=="string" then + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' method %q not defined", tostring(settingname), method) + end + return handler[method], handler, ... + end + + Dewdrop:error("[%s] Missing %q directive", tostring(settingname), methodName) +end + +local function callMethod(settingname, handler, v, methodName, ...) + assert(v and type(v)=="table") + assert(methodName and type(methodName)=="string") + + local method = v[methodName] + if type(method)=="function" then + local success, ret,ret2,ret3,ret4 = pcall(v[methodName], ...) + if not success then + geterrorhandler()(ret) + return nil + end + return ret,ret2,ret3,ret4 + + elseif type(method)=="string" then + + local neg = method:match("^~(.-)$") + if neg then + method = neg + end + if not handler then + Dewdrop:error("[%s] 'handler' is required if providing a method name: %q", tostring(settingname), method) + elseif not handler[method] then + Dewdrop:error("[%s] 'handler' (%q) method %q not defined", tostring(settingname), handler.name or "(unnamed)", method) + end + local success, ret,ret2,ret3,ret4 = pcall(handler[method], handler, ...) + if not success then + geterrorhandler()(ret) + return nil + end + if neg then + return not ret + end + return ret,ret2,ret3,ret4 + elseif method == false then + return nil + end + + Dewdrop:error("[%s] Missing %q directive in %q", tostring(settingname), methodName, v.name or "(unnamed)") +end + +local function skip1Nil(...) + if select(1,...)==nil then + return select(2,...) + end + return ... +end + +function Dewdrop:FeedAceOptionsTable(options, difference) + self:argCheck(options, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + if not validatedOptions then + validatedOptions = {} + end + if not validatedOptions[options] then + local err, position = validateOptions(options) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + + validatedOptions[options] = true + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + + local current = level + while current do -- this traverses from higher level numbers to lower, building "values" with leaf nodes first and trunk nodes later + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + local realOptions = options + local handler = options.handler + local passTable + local passValue + while #values > 0 do -- This loop traverses values from the END (trunk nodes first, then onto leaf nodes) + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + local value = table.remove(values) + options = options.args and options.args[value] + if not options then + return + end + handler = options.handler or handler + passValue = passTable and value or nil + end + + if options.type == "group" then + local hidden = options.hidden + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(options.name or "(options root)", handler, options, "hidden", options.passValue) or false + end + if hidden then + return + end + local disabled = options.disabled + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(options.name or "(options root)", handler, options, "disabled", options.passValue) or false + end + if disabled then + self:AddLine( + 'text', DISABLED, + 'disabled', true + ) + return + end + for k in pairs(options.args) do + table.insert(values, k) + end + if options.pass then + if options.get and options.set then + passTable = options + elseif not passTable then + passTable = options + end + else + passTable = nil + end + if not mysort then + mysort = function(a, b) + local alpha, bravo = mysort_args[a], mysort_args[b] + local alpha_order = alpha.order or 100 + local bravo_order = bravo.order or 100 + local alpha_name = alpha.guiName or alpha.name + local bravo_name = bravo.guiName or bravo.name + if alpha_order == bravo_order then + if not alpha_name then + return bravo_name + elseif not bravo_name then + return false + else + return alpha_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < bravo_name:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + else + if alpha_order < 0 then + if bravo_order > 0 then + return false + end + else + if bravo_order < 0 then + return true + end + end + return alpha_order < bravo_order + end + end + end + mysort_args = options.args + table.sort(values, mysort) + mysort_args = nil + local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 + local last_order = 1 + for _,k in ipairs(values) do + local v = options.args[k] + local handler = v.handler or handler + if hasBoth and last_order > 0 and (v.order or 100) < 0 then + hasBoth = false + self:AddLine() + end + local hidden, disabled = v.guiHidden or v.hidden, v.disabled + + if type(hidden) == "function" or type(hidden) == "string" then + hidden = callMethod(k, handler, v, "hidden", v.passValue) or false + end + if not hidden then + if type(disabled) == "function" or type(disabled) == "string" then + disabled = callMethod(k, handler, v, "disabled", v.passValue) or false + end + local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) + local desc = v.guiDesc or v.desc + local iconHeight = v.iconHeight or 16 + local iconWidth = v.iconWidth or 16 + local iconCoordLeft = v.iconCoordLeft + local iconCoordRight = v.iconCoordRight + local iconCoordBottom = v.iconCoordBottom + local iconCoordTop = v.iconCoordTop + local tooltipTitle, tooltipText + tooltipTitle = name + if name ~= desc then + tooltipText = desc + end + if type(v.usage) == "string" and v.usage:trim():len() > 0 then + if tooltipText then + tooltipText = tooltipText .. "\n\n" .. USAGE_TOOLTIP:format(v.usage) + else + tooltipText = USAGE_TOOLTIP:format(v.usage) + end + end + local v_p = passTable + if not v_p or (v.type ~= "execute" and v.get and v.set) or (v.type == "execute" and v.func) then + v_p = v + end + local passValue = v.passValue or (v_p~=v and k) or nil + if v.type == "toggle" then + local checked = callMethod(name, handler, v_p, "get", passValue) or false + local checked_arg = checked + if type(v_p.get)=="string" and v_p.get:match("^~") then + checked_arg = not checked + end + local func, arg1, arg2, arg3 = getMethod(name, handler, v_p, "set", skip1Nil(passValue, not checked_arg)) + if v.guiNameIsMap then + checked = checked and true or false + name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + tooltipTitle = name + checked = true--nil + end + self:AddLine( + 'text', name, + 'checked', checked, + 'isRadio', v.isRadio, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "execute" then + local func, arg1, arg2, arg3, arg4 + local confirm = v.confirm + if confirm == true then + confirm = DEFAULT_CONFIRM_MESSAGE:format(tooltipText or tooltipTitle) + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + elseif type(confirm) == "string" then + func,arg1,arg2,arg3,arg4 = confirmPopup, confirm, getMethod(name, handler, v_p, "func", passValue) + else + func,arg1,arg2 = getMethod(name, handler, v_p, "func", passValue) + end + self:AddLine( + 'text', name, + 'checked', checked, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "range" then + local sliderValue + sliderValue = callMethod(name, handler, v_p, "get", passValue) or 0 + local sliderFunc, sliderArg1, sliderArg2 = getMethod(name, handler, v_p, "set", passValue) + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RANGE_TOOLTIP) + else + tooltipText = RANGE_TOOLTIP + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasSlider', true, + 'sliderMin', v.min or 0, + 'sliderMax', v.max or 1, + 'sliderStep', v.step or 0, + 'sliderBigStep', v.bigStep or nil, + 'sliderIsPercent', v.isPercent or false, + 'sliderValue', sliderValue, + 'sliderFunc', sliderFunc, + 'sliderArg1', sliderArg1, + 'sliderArg2', sliderArg2, + 'fromAceOptions', true, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "color" then + local r,g,b,a = callMethod(name, handler, v_p, "get", passValue) + if not r then + r,g,b,a = 0,0,0,0 + end + local colorFunc, colorArg1, colorArg2 = getMethod(name, handler, v_p, "set", passValue) + self:AddLine( + 'text', name, + 'hasArrow', true, + 'hasColorSwatch', true, + 'r', r, + 'g', g, + 'b', b, + 'opacity', v.hasAlpha and a or nil, + 'hasOpacity', v.hasAlpha, + 'colorFunc', colorFunc, + 'colorArg1', colorArg1, + 'colorArg2', colorArg2, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + elseif v.type == "text" then + if type(v.validate) == "table" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + local editBoxText + editBoxText = callMethod(name, handler, v_p, "get", passValue) or "" + local editBoxFunc, editBoxArg1, editBoxArg2 = getMethod(name, handler, v_p, "set", passValue) + + local editBoxValidateFunc, editBoxValidateArg1 + + if v.validate and v.validate ~= "keybinding" then + if v.validate == "keybinding" then + if tooltipText then + tooltipText = format("%s\n\n%s", tooltipText, RESET_KEYBINDING_DESC) + else + tooltipText = RESET_KEYBINDING_DESC + end + else + editBoxValidateFunc, editBoxValidateArg1 = getMethod(name, handler, v, "validate") -- no passvalue! + end + end + + self:AddLine( + 'text', name, + 'hasArrow', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom, + 'hasEditBox', true, + 'editBoxText', editBoxText, + 'editBoxFunc', editBoxFunc, + 'editBoxArg1', editBoxArg1, + 'editBoxArg2', editBoxArg2, + 'editBoxValidateFunc', editBoxValidateFunc, + 'editBoxValidateArg1', editBoxValidateArg1, + 'editBoxIsKeybinding', v.validate == "keybinding", + 'editBoxKeybindingOnly', v.keybindingOnly, + 'editBoxKeybindingExcept', v.keybindingExcept, + 'disabled', disabled, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + elseif v.type == "group" then + local func,arg1,arg2 + if v.onClick then + func,arg1,arg2 = getMethod(name, handler, v, "onClick", passValue) + end + local checked + if v.isChecked then + checked = callMethod(name, handler, v, "isChecked", passValue) or false + end + self:AddLine( + 'text', name, + 'hasArrow', true, + 'value', k, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'mouseoverUnderline', func and true or nil, + 'disabled', disabled, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + elseif v.type == "header" then + if name == "" or not name then + self:AddLine( + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + else + self:AddLine( + 'text', name, + 'isTitle', true, + 'icon', v.icon, + 'iconHeight', iconHeight, + 'iconWidth', iconWidth, + 'iconCoordLeft', iconCoordLeft, + 'iconCoordRight', iconCoordRight, + 'iconCoordTop', iconCoordTop, + 'iconCoordBottom', iconCoordBottom + ) + end + end + end + last_order = v.order or 100 + end + elseif options.type == "text" and type(options.validate) == "table" then + local current + local options_p = passTable + if not options_p or (options.get and options.set) then + options_p = options + passTable = nil + passValue = nil + end + local multiToggle = options.multiToggle + local passValue = options.passValue or passValue + if not multiToggle then + current = callMethod(k, handler, options_p, "get", passValue) + end + local indexed = true + for k,v in pairs(options.validate) do + if type(k) ~= "number" then + indexed = false + end + table.insert(values, k) + end + if not indexed then + if not othersort then + othersort = function(alpha, bravo) + return othersort_validate[alpha]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() < othersort_validate[bravo]:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):upper() + end + end + othersort_validate = options.validate + table.sort(values, othersort) + othersort_validate = nil + end + for _,k in ipairs(values) do + local v = options.validate[k] + if type(k) == "number" then + k = v + end + local func, arg1, arg2, arg3, arg4 = getMethod(k, handler, options_p, "set", skip1Nil(passValue, k)) + local checked + if multiToggle then + checked = callMethod(k, handler, options_p, "get", skip1Nil(passValue, k)) or false + if arg2 == nil then + arg2 = not checked + elseif arg3 == nil then + arg3 = not checked + else + arg4 = not checked + end + else + checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) + if checked then + func, arg1, arg2, arg3, arg4 = nil, nil, nil, nil, nil + end + end + local tooltipTitle + local tooltipText + if options.validateDesc then + tooltipTitle = v + tooltipText = options.validateDesc[k] + else + tooltipTitle = options.guiName or options.name + tooltipText = v + end + self:AddLine( + 'text', v, + 'func', func, + 'arg1', arg1, + 'arg2', arg2, + 'arg3', arg3, + 'arg4', arg4, + 'isRadio', not multiToggle, + 'checked', checked, + 'tooltipTitle', tooltipTitle, + 'tooltipText', tooltipText + ) + end + for k in pairs(values) do + values[k] = nil + end + else + return false + end + return true +end + +function Dewdrop:FeedTable(s, difference) + self:argCheck(s, 2, "table") + self:argCheck(difference, 3, "nil", "number") + if not currentLevel then + self:error("Cannot call `FeedTable' outside of a Dewdrop declaration") + end + if not difference then + difference = 0 + end + local level = levels[currentLevel] + if not level then + self:error("Improper level given") + end + if not values then + values = {} + else + for k,v in pairs(values) do + values[k] = nil + end + end + local t = s.subMenu and s or {subMenu = s} + local current = level + while current do + if current.num == difference + 1 then + break + end + table.insert(values, current.value) + current = levels[current.num - 1] + end + + while #values > 0 do + local value = table.remove(values) + t = t.subMenu and t.subMenu[value] + if not t then + return + end + end + + if t.subMenu or current.num == 1 then + for k in pairs(t.subMenu) do + table.insert(values, k) + end + table.sort(values) + for _,k in ipairs(values) do + local argTable = {"value", k} + for key, val in pairs(t.subMenu[k]) do + table.insert(argTable, key) + table.insert(argTable, val) + end + self:AddLine(unpack(argTable)) + end + for k in pairs(values) do + values[k] = nil + end + return false + end + return true +end + +function Refresh(self, level) + if type(level) == "number" then + level = levels[level] + end + if not level then + return + end + if baseFunc then + Clear(self, level) + currentLevel = level.num + if type(baseFunc) == "table" then + if currentLevel == 1 then + local handler = baseFunc.handler + if handler then + local name = tostring(handler) + if not name:find('^table:') and not handler.hideMenuTitle then + name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") + self:AddLine( + 'text', name, + 'isTitle', true + ) + end + end +-- elseif level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) + end + self:FeedAceOptionsTable(baseFunc) + if currentLevel == 1 then + self:AddLine( + 'text', CLOSE, + 'tooltipTitle', CLOSE, + 'tooltipText', CLOSE_DESC, + 'closeWhenClicked', true + ) + end + else +-- if level.parentText then +-- self:AddLine( +-- 'text', level.parentText, +-- 'tooltipTitle', level.parentTooltipTitle, +-- 'tooltipText', level.parentTooltipText, +-- 'tooltipFunc', level.parentTooltipFunc, +-- 'isTitle', true +-- ) +-- end + baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value) + end + currentLevel = nil + CheckSize(self, level) + end +end + +function Dewdrop:Refresh(level) + self:argCheck(level, 2, "number", "nil") + if not level then + for k,v in pairs(levels) do + Refresh(self, v) + end + else + Refresh(self, levels[level]) + end +end + +function OpenSlider(self, parent) + if not sliderFrame then + sliderFrame = CreateFrame("Frame", nil, nil) + sliderFrame:SetWidth(100) + sliderFrame:SetHeight(170) + sliderFrame:SetScale(UIParent:GetScale()) + sliderFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if sliderFrame.SetTopLevel then + sliderFrame:SetTopLevel(true) + end + sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + sliderFrame:EnableMouse(true) + sliderFrame:EnableMouseWheel(true) + sliderFrame:Hide() + sliderFrame:SetPoint("CENTER", UIParent, "CENTER") + local slider = CreateFrame("Slider", nil, sliderFrame) + sliderFrame.slider = slider + slider:SetOrientation("VERTICAL") + slider:SetMinMaxValues(0, 1) + slider:SetValueStep(0.000000001) + slider:SetValue(0.5) + slider:SetWidth(16) + slider:SetHeight(128) + slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) + slider:SetBackdrop(tmp( + 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", + 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", + 'tile', true, + 'edgeSize', 8, + 'tileSize', 8, + 'insets', tmp2( + 'left', 3, + 'right', 3, + 'top', 3, + 'bottom', 3 + ) + )) + local texture = slider:CreateTexture() + slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.topText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("100%") + text:SetPoint("BOTTOM", slider, "TOP") + local text = slider:CreateFontString(nil, "ARTWORK") + sliderFrame.bottomText = text + text:SetFontObject(GameFontGreenSmall) + text:SetText("0%") + text:SetPoint("TOP", slider, "BOTTOM") + local editBox = CreateFrame("EditBox", nil, sliderFrame) + sliderFrame.currentText = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetHeight(13) + editBox:SetPoint("RIGHT", sliderFrame, "RIGHT", -16, 0) + editBox:SetPoint("LEFT", slider, "RIGHT", 12, 0) + editBox:SetText("50%") + editBox:SetJustifyH("CENTER") + + local width = editBox:GetWidth()/2 + 10 + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, width / 256, 0, 1) + left:SetWidth(width) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(1 - width / 256, 1, 0, 1) + right:SetWidth(width) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + local changed = false + local inside = false + slider:SetScript("OnValueChanged", function() + if sliderFrame.changing then + return + end + changed = true + local done = false + if sliderFrame.parent and sliderFrame.parent.sliderFunc then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if value == sliderFrame.lastValue then + return + end + sliderFrame.lastValue = value + local text = sliderFrame.parent.sliderFunc(getArgs(sliderFrame.parent, 'sliderArg', 1, value)) + if sliderFrame.parent.fromAceOptions then + text = nil + elseif type(text) == "string" or type(text) == "number" then + sliderFrame.currentText:SetText(text) + done = true + end + end + if not done then + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step + if sliderFrame.fineStep then + step = sliderFrame.parent.sliderStep or (max - min) / 100 + else + step = sliderFrame.parent.sliderBigStep or sliderFrame.parent.sliderStep or (max - min) / 100 + end + local value = (1 - slider:GetValue()) * (max - min) + min + if step > 0 then + value = math.floor((value - min) / step + 0.5) * step + min + if value > max then + value = max + elseif value < min then + value = min + end + end + if sliderFrame.parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) + else + if step < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", value)) + elseif step < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", value)) + else + sliderFrame.currentText:SetText(string.format("%.0f", value)) + end + end + end + end) + local function onEnter() + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end + local function onLeave() + GameTooltip:Hide() + end + sliderFrame:SetScript("OnEnter", onEnter) + sliderFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + if changed then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + end) + editBox:SetScript("OnEnter", onEnter) + editBox:SetScript("OnLeave", onLeave) + slider:SetScript("OnMouseDown", function() + sliderFrame.mouseDown = true + GameTooltip:Hide() + end) + slider:SetScript("OnMouseUp", function() + sliderFrame.mouseDown = false + if changed--[[ and not inside]] then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + end + if inside then + showGameTooltip(sliderFrame.parent) + end + end) + slider:SetScript("OnEnter", function() + inside = true + StopCounting(self, sliderFrame.level) + showGameTooltip(sliderFrame.parent) + end) + slider:SetScript("OnLeave", function() + inside = false + GameTooltip:Hide() + if changed and not sliderFrame.mouseDown then + local parent = sliderFrame.parent + local sliderFunc = parent.sliderFunc + for i = 1, sliderFrame.level - 1 do + Refresh(self, levels[i]) + end + local newParent + for _,button in ipairs(levels[sliderFrame.level-1].buttons) do + if button.sliderFunc == sliderFunc then + newParent = button + break + end + end + if newParent then + OpenSlider(self, newParent) + else + sliderFrame:Hide() + end + + changed = false + end + end) + sliderFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + local step = sliderFrame.parent.sliderStep or (max - min) / 100 + if step <= 0 then + step = (max - min) / 100 + end + + local value = (1 - slider:GetValue()) * (max - min) + min + if up then + value = value + step + else + value = value - step + end + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max<=min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + end) + slider:SetScript("OnMouseWheel", sliderFrame:GetScript("OnMouseWheel")) + editBox:SetScript("OnEnterPressed", function(t, a1) + local value = editBox:GetNumber() + + if sliderFrame.parent.sliderIsPercent then + value = value / 100 + end + + local min = sliderFrame.parent.sliderMin or 0 + local max = sliderFrame.parent.sliderMax or 1 + + if value > max then + value = max + elseif value < min then + value = min + end + sliderFrame.fineStep = true + if max <= min then + slider:SetValue(0) + else + slider:SetValue(1 - (value - min) / (max - min)) + end + sliderFrame.fineStep = nil + + StartCounting(self, sliderFrame.level) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(sliderFrame.level) + StartCounting(self, sliderFrame.level) + end) + editBox:SetAutoFocus(false) + end + sliderFrame.parent = parent + sliderFrame.level = parent.level.num + 1 + sliderFrame.parentValue = parent.level.value + sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) + sliderFrame.currentText:ClearFocus() + sliderFrame.changing = true + if not parent.sliderMin or not parent.sliderMax then + return + end + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + sliderFrame:SetClampedToScreen(false) + if not parent.sliderValue then + parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 + end + if parent.sliderMax <= parent.sliderMin then + sliderFrame.slider:SetValue(0) + else + sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) + end + sliderFrame.changing = false + sliderFrame.bottomText:SetText(parent.sliderMinText or "0") + sliderFrame.topText:SetText(parent.sliderMaxText or "1") + local text + if parent.sliderFunc and not parent.fromAceOptions then + text = parent.sliderFunc(getArgs(parent, 'sliderArg', 1, parent.sliderValue)) + end + if type(text) == "number" or type(text) == "string" then + sliderFrame.currentText:SetText(text) + elseif parent.sliderIsPercent then + sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) + else + if parent.sliderStep < 0.1 then + sliderFrame.currentText:SetText(string.format("%.2f", parent.sliderValue)) + elseif parent.sliderStep < 1 then + sliderFrame.currentText:SetText(string.format("%.1f", parent.sliderValue)) + else + sliderFrame.currentText:SetText(string.format("%.0f", parent.sliderValue)) + end + end + + + sliderFrame.lastValue = parent.sliderValue + + local level = parent.level + sliderFrame:Show() + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if sliderFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif sliderFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if sliderFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif sliderFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + sliderFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() + sliderFrame:ClearAllPoints() + sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + sliderFrame:SetClampedToScreen(true) +end + +function OpenEditBox(self, parent) + if not editBoxFrame then + editBoxFrame = CreateFrame("Frame", nil, nil) + editBoxFrame:SetWidth(200) + editBoxFrame:SetHeight(40) + editBoxFrame:SetScale(UIParent:GetScale()) + editBoxFrame:SetBackdrop(tmp( + 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", + 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", + 'tile', true, + 'insets', tmp2( + 'left', 5, + 'right', 5, + 'top', 5, + 'bottom', 5 + ), + 'tileSize', 16, + 'edgeSize', 16 + )) + editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") + if editBoxFrame.SetTopLevel then + editBoxFrame:SetTopLevel(true) + end + editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) + editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) + editBoxFrame:EnableMouse(true) + editBoxFrame:EnableMouseWheel(true) + editBoxFrame:Hide() + editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") + + local editBox = CreateFrame("EditBox", nil, editBoxFrame) + editBoxFrame.editBox = editBox + editBox:SetFontObject(ChatFontNormal) + editBox:SetWidth(160) + editBox:SetHeight(13) + editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) + + local left = editBox:CreateTexture(nil, "BACKGROUND") + left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") + left:SetTexCoord(0, 100 / 256, 0, 1) + left:SetWidth(100) + left:SetHeight(32) + left:SetPoint("LEFT", editBox, "LEFT", -10, 0) + local right = editBox:CreateTexture(nil, "BACKGROUND") + right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") + right:SetTexCoord(156/256, 1, 0, 1) + right:SetWidth(100) + right:SetHeight(32) + right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) + + editBox:SetScript("OnEnterPressed", function() + if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then + local t = editBox.realText or editBox:GetText() or "" + local result = editBoxFrame.parent.editBoxValidateFunc(getArgs(editBoxFrame.parent, 'editBoxValidateArg', 1, t)) + if not result then + UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) + return + end + end + if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + editBoxFrame.parent.editBoxFunc(getArgs(editBoxFrame.parent, 'editBoxArg', 1, t)) + end + self:Close(editBoxFrame.level) + for i = 1, editBoxFrame.level - 1 do + Refresh(self, levels[i]) + end + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnEscapePressed", function() + self:Close(editBoxFrame.level) + StartCounting(self, editBoxFrame.level-1) + end) + editBox:SetScript("OnReceiveDrag", function(this) + if GetCursorInfo then + local type, alpha, bravo = GetCursorInfo() + local text + if type == "spell" then + text = GetSpellName(alpha, bravo) + elseif type == "item" then + text = bravo + end + if not text then + return + end + ClearCursor() + editBox:SetText(text) + end + end) + local changing = false + local skipNext = false + + function editBox:SpecialSetText(text) + local oldText = editBox:GetText() or "" + if not text then + text = "" + end + if text ~= oldText then + changing = true + self:SetText(tostring(text)) + changing = false + skipNext = true + end + end + + editBox:SetScript("OnTextChanged", function() + if skipNext then + skipNext = false + elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then + local t + if editBox.realText ~= "NONE" then + t = editBox.realText or editBox:GetText() or "" + end + local text = editBoxFrame.parent.editBoxChangeFunc(getArgs(editBoxFrame.parent, 'editBoxChangeArg', 1, t)) + if text then + editBox:SpecialSetText(text) + end + end + end) + editBoxFrame:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBoxFrame:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBox:SetScript("OnEnter", function() + StopCounting(self, editBoxFrame.level) + showGameTooltip(editBoxFrame.parent) + end) + editBox:SetScript("OnLeave", function() + GameTooltip:Hide() + end) + editBoxFrame:SetScript("OnKeyDown", function(this, a1) + if not editBox.keybinding then + return + end + local arg1 = a1 or arg1 + local screenshotKey = GetBindingKey("SCREENSHOT") + if screenshotKey and arg1 == screenshotKey then + Screenshot() + return + end + + if arg1 == "LeftButton" then + arg1 = "BUTTON1" + elseif arg1 == "RightButton" then + arg1 = "BUTTON2" + elseif arg1 == "MiddleButton" then + arg1 = "BUTTON3" + elseif arg1 == "Button4" then + arg1 = "BUTTON4" + elseif arg1 == "Button5" then + arg1 = "BUTTON5" + end + if arg1 == "UNKNOWN" then + return + elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then + return + elseif arg1 == "ENTER" then + if editBox.keybindingOnly and not editBox.keybindingOnly[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + elseif editBox.keybindingExcept and editBox.keybindingExcept[editBox.realText] then + return editBox:GetScript("OnEscapePressed")() + else + return editBox:GetScript("OnEnterPressed")() + end + elseif arg1 == "ESCAPE" then + if editBox.realText == "NONE" then + return editBox:GetScript("OnEscapePressed")() + else + editBox:SpecialSetText(NONE or "NONE") + editBox.realText = "NONE" + return + end + elseif editBox.keybindingOnly and not editBox.keybindingOnly[arg1] then + return + elseif editBox.keybindingExcept and editBox.keybindingExcept[arg1] then + return + end + local s = GetBindingText(arg1, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + local real = arg1 + if IsShiftKeyDown() then + s = "Shift-" .. s + real = "SHIFT-" .. real + end + if IsControlKeyDown() then + s = "Ctrl-" .. s + real = "CTRL-" .. real + end + if IsAltKeyDown() then + s = "Alt-" .. s + real = "ALT-" .. real + end + if editBox:GetText() ~= s then + editBox:SpecialSetText("-") + editBox:SpecialSetText(s) + editBox.realText = real + return editBox:GetScript("OnTextChanged")() + end + end) + editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) + editBox:SetScript("OnMouseDown", function(this, ...) + if GetCursorInfo and (CursorHasItem() or CursorHasSpell()) then + return editBox:GetScript("OnReceiveDrag")(this, ...) + end + return editBoxFrame:GetScript("OnKeyDown")(this, ...) + end) + editBoxFrame:SetScript("OnMouseWheel", function(t, a1) + local arg1 = a1 or arg1 + local up = arg1 > 0 + arg1 = up and "MOUSEWHEELUP" or "MOUSEWHEELDOWN" + return editBoxFrame:GetScript("OnKeyDown")(t or this, arg1) + end) + editBox:SetScript("OnMouseWheel", editBoxFrame:GetScript("OnMouseWheel")) + end + editBoxFrame.parent = parent + editBoxFrame.level = parent.level.num + 1 + editBoxFrame.parentValue = parent.level.value + editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) + editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) + editBoxFrame.editBox.realText = nil + editBoxFrame:SetClampedToScreen(false) + + editBoxFrame.editBox:SpecialSetText("") + if parent.editBoxIsKeybinding then + local s = parent.editBoxText + if s == "" then + s = "NONE" + end + editBoxFrame.editBox.realText = s + if s and s ~= "NONE" then + local alpha,bravo = s:match("^(.+)%-(.+)$") + if not bravo then + alpha = nil + bravo = s + end + bravo = GetBindingText(bravo, "KEY_") + if alpha then + editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) + else + editBoxFrame.editBox:SpecialSetText(bravo) + end + else + editBoxFrame.editBox:SpecialSetText(NONE or "NONE") + end + else + editBoxFrame.editBox:SpecialSetText(parent.editBoxText) + end + + editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding + editBoxFrame.editBox.keybindingOnly = parent.editBoxKeybindingOnly + editBoxFrame.editBox.keybindingExcept = parent.editBoxKeybindingExcept + editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) + editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) + + if parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + + local level = parent.level + editBoxFrame:Show() + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + local dirty + if level.lastDirection == "RIGHT" then + if editBoxFrame:GetRight() > GetScreenWidth() then + level.lastDirection = "LEFT" + dirty = true + end + elseif editBoxFrame:GetLeft() < 0 then + level.lastDirection = "RIGHT" + dirty = true + end + if level.lastVDirection == "DOWN" then + if editBoxFrame:GetBottom() < 0 then + level.lastVDirection = "UP" + dirty = true + end + elseif editBoxFrame:GetTop() > GetScreenWidth() then + level.lastVDirection = "DOWN" + dirty = true + end + if dirty then + editBoxFrame:ClearAllPoints() + if level.lastDirection == "RIGHT" then + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) + else + editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) + end + else + if level.lastVDirection == "DOWN" then + editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) + else + editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) + end + end + end + local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() + editBoxFrame:ClearAllPoints() + editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + if mod(level.num, 5) == 0 then + local left, bottom = level:GetLeft(), level:GetBottom() + level:ClearAllPoints() + level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) + end + editBoxFrame:SetClampedToScreen(true) +end + +function Dewdrop:EncodeKeybinding(text) + if text == nil or text == "NONE" then + return nil + end + text = tostring(text):upper() + local shift, ctrl, alt + local modifier + while true do + if text == "-" then + break + end + modifier, text = strsplit('-', text, 2) + if text then + if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then + return false + end + if modifier == "SHIFT" then + if shift then + return false + end + shift = true + end + if modifier == "CTRL" then + if ctrl then + return false + end + ctrl = true + end + if modifier == "ALT" then + if alt then + return false + end + alt = true + end + else + text = modifier + break + end + end + if not text:find("^F%d+$") and text ~= "CAPSLOCK" and text:len() ~= 1 and (text:len() == 0 or text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] and text ~= "BUTTON1" and text ~= "BUTTON2" then + return false + end + local s = GetBindingText(text, "KEY_") + if s == "BUTTON1" then + s = KEY_BUTTON1 + elseif s == "BUTTON2" then + s = KEY_BUTTON2 + end + if shift then + s = "Shift-" .. s + end + if ctrl then + s = "Ctrl-" .. s + end + if alt then + s = "Alt-" .. s + end + return s +end + +function Dewdrop:IsOpen(parent) + self:argCheck(parent, 2, "table", "string", "nil") + return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) +end + +function Dewdrop:GetOpenedParent() + return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) +end + +function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) + self:Close(level) + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + if type(parent) == "table" then + parent:GetCenter() + end + local frame = AcquireLevel(self, level) + if level == 1 then + frame.lastDirection = "RIGHT" + frame.lastVDirection = "DOWN" + else + frame.lastDirection = levels[level - 1].lastDirection + frame.lastVDirection = levels[level - 1].lastVDirection + end + frame:SetFrameStrata("FULLSCREEN_DIALOG") + frame:ClearAllPoints() + frame.parent = parent + frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) + frame:Show() + if level == 1 then + baseFunc = func + end + levels[level].value = value +-- levels[level].parentText = parent.text and parent.text:GetText() or nil +-- levels[level].parentTooltipTitle = parent.tooltipTitle +-- levels[level].parentTooltipText = parent.tooltipText +-- levels[level].parentTooltipFunc = parent.tooltipFunc + if type(parent) == "table" and parent.arrow then +-- parent.arrow:SetVertexColor(0.2, 0.6, 0) +-- parent.arrow:SetHeight(24) +-- parent.arrow:SetWidth(24) + parent.selected = true + parent.highlight:Show() + end + relativePoint = relativePoint or point + Refresh(self, levels[level]) + if point or (cursorX and cursorY) then + frame:ClearAllPoints() + if cursorX and cursorY then + local curX, curY = GetScaledCursorPosition() + if curY < GetScreenHeight() / 2 then + point, relativePoint = "BOTTOM", "BOTTOM" + else + point, relativePoint = "TOP", "TOP" + end + if curX < GetScreenWidth() / 2 then + point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" + else + point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint) + if cursorX and cursorY then + local left = frame:GetLeft() + local width = frame:GetWidth() + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + local xOffset, yOffset = 0, 0 + if curY > GetScreenHeight() / 2 then + yOffset = -height + end + if curX > GetScreenWidth() / 2 then + xOffset = -width + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorX then + local left = frame:GetLeft() + local width = frame:GetWidth() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "BOTTOM" or point == "TOP" then + if curX < GetScreenWidth() / 2 then + point = point .. "LEFT" + else + point = point .. "RIGHT" + end + elseif point == "CENTER" then + if curX < GetScreenWidth() / 2 then + point = "LEFT" + else + point = "RIGHT" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, curX - left - width / 2, 0) + if level == 1 then + frame.lastDirection = "RIGHT" + end + elseif cursorY then + local bottom = frame:GetBottom() + local height = frame:GetHeight() + local curX, curY = GetScaledCursorPosition() + frame:ClearAllPoints() + relativePoint = relativePoint or point + if point == "LEFT" or point == "RIGHT" then + if curX < GetScreenHeight() / 2 then + point = point .. "BOTTOM" + else + point = point .. "TOP" + end + elseif point == "CENTER" then + if curX < GetScreenHeight() / 2 then + point = "BOTTOM" + else + point = "TOP" + end + end + frame:SetPoint(point, type(parent) == "table" and parent or UIParent, relativePoint, 0, curY - bottom - height / 2) + if level == 1 then + frame.lastDirection = "DOWN" + end + end + if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then + if frame:GetBottom() < 0 then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + elseif frame:GetTop() > GetScreenHeight() then + local point, parent, relativePoint, x, y = frame:GetPoint(1) + local change = GetScreenHeight() - frame:GetTop() + local otherChange = -frame:GetBottom() + if otherChange < change then + change = otherChange + end + frame:SetPoint(point, parent, relativePoint, x, y + change) + end + end + end + CheckDualMonitor(self, frame) + frame:SetClampedToScreen(true) + frame:SetClampedToScreen(false) + StartCounting(self, level) +end + +function Dewdrop:IsRegistered(parent) + self:argCheck(parent, 2, "table", "string") + return not not self.registry[parent] +end + +function Dewdrop:Register(parent, ...) + self:argCheck(parent, 2, "table", "string") + if self.registry[parent] then + self:Unregister(parent) + end + local info = new(...) + if type(info.children) == "table" then + local err, position = validateOptions(info.children) + + if err then + if position then + Dewdrop:error(position .. ": " .. err) + else + Dewdrop:error(err) + end + end + end + self.registry[parent] = info + if not info.dontHook and not self.onceRegistered[parent] and type(parent) == "table" then + if parent:HasScript("OnMouseUp") then + local script = parent:GetScript("OnMouseUp") + parent:SetScript("OnMouseUp", function(this, ...) + if script then + script(this, ...) + end + if arg1 == "RightButton" and self.registry[parent] then + if self:IsOpen(parent) then + self:Close() + else + self:Open(parent) + end + end + end) + end + if parent:HasScript("OnMouseDown") then + local script = parent:GetScript("OnMouseDown") + parent:SetScript("OnMouseDown", function(this, ...) + if script then + script(this, ...) + end + if self.registry[parent] then + self:Close() + end + end) + end + end + self.onceRegistered[parent] = true +end + +function Dewdrop:Unregister(parent) + self:argCheck(parent, 2, "table", "string") + self.registry[parent] = nil +end + +function Dewdrop:Open(parent, ...) + self:argCheck(parent, 2, "table", "string") + local info + local k1 = ... + if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then + info = tmp(select(2, ...)) + for k,v in pairs(self.registry[k1]) do + if info[k] == nil then + info[k] = v + end + end + else + info = tmp(...) + if self.registry[parent] then + for k,v in pairs(self.registry[parent]) do + if info[k] == nil then + info[k] = v + end + end + end + end + local point = info.point + local relativePoint = info.relativePoint + local cursorX = info.cursorX + local cursorY = info.cursorY + if type(point) == "function" then + local b + point, b = point(parent) + if b then + relativePoint = b + end + end + if type(relativePoint) == "function" then + relativePoint = relativePoint(parent) + end + Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) +end + +function Clear(self, level) + if level then + if level.buttons then + for i = #level.buttons, 1, -1 do + ReleaseButton(self, level, i) + end + end + end +end + +function Dewdrop:Close(level) + if DropDownList1:IsShown() then + DropDownList1:Hide() + end + if DewdropLib then + local d = DewdropLib:GetInstance('1.0') + local ret, val = pcall(d, IsOpen, d) + if ret and val then + DewdropLib:GetInstance('1.0'):Close() + end + end + self:argCheck(level, 2, "number", "nil") + if not level then + level = 1 + end + if level == 1 and levels[level] then + levels[level].parented = false + end + if level > 1 and levels[level-1].buttons then + local buttons = levels[level-1].buttons + for _,button in ipairs(buttons) do +-- button.arrow:SetWidth(16) +-- button.arrow:SetHeight(16) + button.selected = nil + button.highlight:Hide() +-- button.arrow:SetVertexColor(1, 1, 1) + end + end + if sliderFrame and sliderFrame.level >= level then + sliderFrame:Hide() + end + if editBoxFrame and editBoxFrame.level >= level then + editBoxFrame:Hide() + end + for i = level, #levels do + Clear(self, levels[level]) + levels[i]:Hide() + levels[i]:ClearAllPoints() + levels[i]:SetPoint("CENTER", UIParent, "CENTER") + levels[i].value = nil + end +end + +function Dewdrop:AddSeparator(level) + level = levels[level or currentLevel] + if not level or not level.buttons then return; end + + local prevbutton = level.buttons[#level.buttons] + if not prevbutton then return; end + + if prevbutton.disabled and prevbutton.text:GetText() == "" then + return + end + self:AddLine("text", "", "disabled", true) +end + +function Dewdrop:AddLine(...) + local info = tmp(...) + local level = info.level or currentLevel + info.level = nil + local button = AcquireButton(self, level) + if not next(info) then + info.disabled = true + end + button.disabled = info.isTitle or info.notClickable or info.disabled or (self.combat and info.secure) + button.isTitle = info.isTitle + button.notClickable = info.notClickable + if button.isTitle then + button.text:SetFontObject(GameFontNormalSmall) + elseif button.notClickable then + button.text:SetFontObject(GameFontHighlightSmall) + elseif button.disabled then + button.text:SetFontObject(GameFontDisableSmall) + else + button.text:SetFontObject(GameFontHighlightSmall) + end + if info.disabled then + button.arrow:SetDesaturated(true) + button.check:SetDesaturated(true) + else + button.arrow:SetDesaturated(false) + button.check:SetDesaturated(false) + end + if info.textR and info.textG and info.textB then + button.textR = info.textR + button.textG = info.textG + button.textB = info.textB + button.text:SetTextColor(button.textR, button.textG, button.textB) + else + button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) + end + button.notCheckable = info.notCheckable + button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) + button.checked = not info.notCheckable and info.checked + button.mouseoverUnderline = info.mouseoverUnderline + button.isRadio = not info.notCheckable and info.isRadio + if info.isRadio then + button.check:Show() + button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + if button.checked then + button.check:SetTexCoord(0.25, 0.5, 0, 1) + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetTexCoord(0, 0.25, 0, 1) + button.check:SetVertexColor(1, 1, 1, 0.5) + end + button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") + button.check:SetWidth(16) + button.check:SetHeight(16) + elseif info.icon then + button.check:Show() + button.check:SetTexture(info.icon) + if info.iconWidth and info.iconHeight then + button.check:SetWidth(info.iconWidth) + button.check:SetHeight(info.iconHeight) + else + button.check:SetWidth(16) + button.check:SetHeight(16) + end + if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then + button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) + elseif info.icon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + if button.checked then + if info.checkIcon then + button.check:SetWidth(16) + button.check:SetHeight(16) + button.check:SetTexture(info.checkIcon) + if info.checkIcon:find("^Interface\\Icons\\") then + button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) + else + button.check:SetTexCoord(0, 1, 0, 1) + end + else + button.check:SetWidth(24) + button.check:SetHeight(24) + button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") + button.check:SetTexCoord(0, 1, 0, 1) + end + button.check:SetVertexColor(1, 1, 1, 1) + else + button.check:SetVertexColor(1, 1, 1, 0) + end + end + if not button.disabled then + button.func = info.func + button.secure = info.secure + end + button.hasColorSwatch = info.hasColorSwatch + if button.hasColorSwatch then + button.colorSwatch:Show() + button.colorSwatch.texture:Show() + button.r = info.r or 1 + button.g = info.g or 1 + button.b = info.b or 1 + button.colorSwatch.texture:SetVertexColor(button.r, button.g, button.b) + button.checked = false + button.func = nil + button.colorFunc = info.colorFunc + local i = 1 + while true do + local k = "colorArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.hasOpacity = info.hasOpacity + button.opacity = info.opacity or 1 + else + button.colorSwatch:Hide() + button.colorSwatch.texture:Hide() + end + button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow + if button.hasArrow then + button.arrow:SetAlpha(1) + if info.hasSlider then + button.hasSlider = true + button.sliderMin = info.sliderMin or 0 + button.sliderMax = info.sliderMax or 1 + button.sliderStep = info.sliderStep or 0 + button.sliderBigStep = info.sliderBigStep or button.sliderStep + if button.sliderBigStep < button.sliderStep then + button.sliderBigStep = button.sliderStep + end + button.sliderIsPercent = info.sliderIsPercent and true or false + button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin + button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax + button.sliderFunc = info.sliderFunc + button.sliderValue = info.sliderValue + button.fromAceOptions = info.fromAceOptions + local i = 1 + while true do + local k = "sliderArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + elseif info.hasEditBox then + button.hasEditBox = true + button.editBoxText = info.editBoxText or "" + button.editBoxFunc = info.editBoxFunc + local i = 1 + while true do + local k = "editBoxArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxChangeFunc = info.editBoxChangeFunc + local i = 1 + while true do + local k = "editBoxChangeArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxValidateFunc = info.editBoxValidateFunc + local i = 1 + while true do + local k = "editBoxValidateArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.editBoxIsKeybinding = info.editBoxIsKeybinding + button.editBoxKeybindingOnly = info.editBoxKeybindingOnly + button.editBoxKeybindingExcept = info.editBoxKeybindingExcept + else + button.value = info.value + local l = levels[level+1] + if l and info.value == l.value then +-- button.arrow:SetWidth(24) +-- button.arrow:SetHeight(24) + button.selected = true + button.highlight:Show() + end + end + else + button.arrow:SetAlpha(0) + end + local i = 1 + while true do + local k = "arg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + button.closeWhenClicked = info.closeWhenClicked + button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 + local font,_ = button.text:GetFont() + button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) + button:SetHeight(button.textHeight + 6) + button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") + button.text:SetJustifyH(info.justifyH or "LEFT") + button.text:SetText(info.text) + button.tooltipTitle = info.tooltipTitle + button.tooltipText = info.tooltipText + button.tooltipFunc = info.tooltipFunc + local i = 1 + while true do + local k = "tooltipArg" .. i + local x = info[k] + if x == nil then + break + end + button[k] = x + i = i + 1 + end + if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then + button.tooltipTitle = info.text + end + if type(button.func) == "string" then + if type(button.arg1) ~= "table" then + self:error("Cannot call method %q on a non-table", button.func) + end + if type(button.arg1[button.func]) ~= "function" then + self:error("Method %q nonexistant.", button.func) + end + end +end + +function Dewdrop:InjectAceOptionsTable(handler, options) + self:argCheck(handler, 2, "table") + self:argCheck(options, 3, "table") + if tostring(options.type):lower() ~= "group" then + self:error('Cannot inject into options table argument #3 if its type is not "group"') + end + if options.handler ~= nil and options.handler ~= handler then + self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") + end + options.handler = handler + local class = handler.class + if not AceLibrary:HasInstance("AceOO-2.0") or not class then + if Rock then + -- possible Rock object + for mixin in Rock:IterateObjectMixins(handler) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + else + -- Ace2 object + while class and class ~= AceLibrary("AceOO-2.0").Class do + if type(class.GetAceOptionsDataTable) == "function" then + local t = class:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + local mixins = class.mixins + if mixins then + for mixin in pairs(mixins) do + if type(mixin.GetAceOptionsDataTable) == "function" then + local t = mixin:GetAceOptionsDataTable(handler) + for k,v in pairs(t) do + if type(options.args) ~= "table" then + options.args = {} + end + if options.args[k] == nil then + options.args[k] = v + end + end + end + end + end + class = class.super + end + end + return options +end + +function Dewdrop:OnTooltipHide() + if lastSetFont then + if lastSetFont == normalFont then + lastSetFont = nil + return + end + fillRegionTmp(GameTooltip:GetRegions()) + for i,v in ipairs(regionTmp) do + if v.GetFont then + local font,size,outline = v:GetFont() + if font == lastSetFont then + v:SetFont(normalFont, size, outline) + end + end + regionTmp[i] = nil + end + lastSetFont = nil + end +end + +local function activate(self, oldLib, oldDeactivate) + Dewdrop = self + if oldLib and oldLib.registry then + self.registry = oldLib.registry + self.onceRegistered = oldLib.onceRegistered + else + self.registry = {} + self.onceRegistered = {} + + local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") + local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") + local oldX, oldY, clickTime + WorldFrame:SetScript("OnMouseDown", function(this, ...) + oldX,oldY = GetCursorPosition() + clickTime = GetTime() + if WorldFrame_OnMouseDown then + WorldFrame_OnMouseDown(this, ...) + end + end) + + WorldFrame:SetScript("OnMouseUp", function(this, ...) + local x,y = GetCursorPosition() + if not oldX or not oldY or not x or not y or not clickTime then + self:Close() + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + return + end + local d = math.abs(x - oldX) + math.abs(y - oldY) + if d <= 5 and GetTime() - clickTime < 0.5 then + self:Close() + end + if WorldFrame_OnMouseUp then + WorldFrame_OnMouseUp(this, ...) + end + end) + + hooksecurefunc(DropDownList1, "Show", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("HideDropDownMenu", function() + if levels[1] and levels[1]:IsVisible() then + self:Close() + end + end) + + hooksecurefunc("CloseDropDownMenus", function() + if levels[1] and levels[1]:IsVisible() then + local stack = debugstack() + if not stack:find("`TargetFrame_OnHide'") then + self:Close() + end + end + end) + end + self.frame = oldLib and oldLib.frame or CreateFrame("Frame") + self.frame:UnregisterAllEvents() + self.frame:RegisterEvent("PLAYER_REGEN_ENABLED") + self.frame:RegisterEvent("PLAYER_REGEN_DISABLED") + self.frame:Hide() + self.frame:SetScript("OnEvent", function(this, event) + this:Show() + if event=="PLAYER_REGEN_ENABLED" then -- track combat state for secure frame operations + self.combat = false + elseif event=="PLAYER_REGEN_DISABLED" then + self.combat = true + end + end) + self.frame:SetScript("OnUpdate", function(this) + this:Hide() + self:Refresh(1) + end) + self.hookedTooltip = true + if not oldLib or not oldLib.hookedTooltip then + local OnTooltipHide = GameTooltip:GetScript("OnHide") + GameTooltip:SetScript("OnHide", function(this, ...) + if OnTooltipHide then + OnTooltipHide(this, ...) + end + if type(self.OnTooltipHide) == "function" then + self:OnTooltipHide() + end + end) + end + levels = {} + buttons = {} + + if oldDeactivate then + oldDeactivate(oldLib) + end +end + +local function external(lib, major, instance) + if major == "SharedMedia-1.0" then + SharedMedia = instance + end +end + +AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/libs/AceAddon-2.0/AceAddon-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1032 +0,0 @@ ---[[ -Name: AceAddon-2.0 -Revision: $Rev: 19844 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceAddon-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceAddon-2.0 -Description: Base for all Ace addons to inherit from. -Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, (optional) AceConsole-2.0 -]] - -local MAJOR_VERSION = "AceAddon-2.0" -local MINOR_VERSION = "$Revision: 19844 $" - --- This ensures the code is only executed if the libary doesn't already exist, or is a newer version -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err) end -end --- Localization -local STANDBY, TITLE, NOTES, VERSION, AUTHOR, DATE, CATEGORY, EMAIL, CREDITS, WEBSITE, CATEGORIES, ABOUT, PRINT_ADDON_INFO -if GetLocale() == "deDE" then - STANDBY = "|cffff5050(Standby)|r" -- capitalized - - TITLE = "Titel" - NOTES = "Anmerkung" - VERSION = "Version" - AUTHOR = "Autor" - DATE = "Datum" - CATEGORY = "Kategorie" - EMAIL = "E-mail" - WEBSITE = "Webseite" - CREDITS = "Credits" -- fix - - ABOUT = "\195\188ber" - PRINT_ADDON_INFO = "Gibt Addondaten aus" - - CATEGORIES = { - ["Action Bars"] = "Aktionsleisten", - ["Auction"] = "Auktion", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Schlachtfeld/PvP", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Kommunikation", - ["Druid"] = "Druide", - ["Hunter"] = "J?r", - ["Mage"] = "Magier", - ["Paladin"] = "Paladin", - ["Priest"] = "Priester", - ["Rogue"] = "Schurke", - ["Shaman"] = "Schamane", - ["Warlock"] = "Hexenmeister", - ["Warrior"] = "Krieger", - ["Healer"] = "Heiler", - ["Tank"] = "Tank", -- noone use "Brecher"... - ["Caster"] = "Caster", - ["Combat"] = "Kampf", - ["Compilations"] = "Compilations", -- whats that o_O - ["Data Export"] = "Datenexport", - ["Development Tools"] = "Entwicklungs Tools", - ["Guild"] = "Gilde", - ["Frame Modification"] = "Frame Modifikation", - ["Interface Enhancements"] = "Interface Verbesserungen", - ["Inventory"] = "Inventar", - ["Library"] = "Library", - ["Map"] = "Map", - ["Mail"] = "Mail", - ["Miscellaneous"] = "Diverses", - ["Quest"] = "Quest", - ["Raid"] = "Schlachtzug", - ["Tradeskill"] = "Handelsf\195\164higkeit", - ["UnitFrame"] = "UnitFrame", - } -elseif GetLocale() == "frFR" then - STANDBY = "|cffff5050(attente)|r" - - TITLE = "Titre" - NOTES = "Notes" - VERSION = "Version" - AUTHOR = "Auteur" - DATE = "Date" - CATEGORY = "Cat\195\169gorie" - EMAIL = "E-mail" - WEBSITE = "Site web" - CREDITS = "Credits" -- fix - - ABOUT = "A propos" - PRINT_ADDON_INFO = "Afficher les informations sur l'addon" - - CATEGORIES = { - ["Action Bars"] = "Barres d'action", - ["Auction"] = "H\195\180tel des ventes", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Champs de bataille/JcJ", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Communication", - ["Druid"] = "Druide", - ["Hunter"] = "Chasseur", - ["Mage"] = "Mage", - ["Paladin"] = "Paladin", - ["Priest"] = "Pr\195\170tre", - ["Rogue"] = "Voleur", - ["Shaman"] = "Chaman", - ["Warlock"] = "D\195\169moniste", - ["Warrior"] = "Guerrier", - ["Healer"] = "Soigneur", - ["Tank"] = "Tank", - ["Caster"] = "Casteur", - ["Combat"] = "Combat", - ["Compilations"] = "Compilations", - ["Data Export"] = "Exportation de donn\195\169es", - ["Development Tools"] = "Outils de d\195\169veloppement", - ["Guild"] = "Guilde", - ["Frame Modification"] = "Modification des fen\195\170tres", - ["Interface Enhancements"] = "Am\195\169liorations de l'interface", - ["Inventory"] = "Inventaire", - ["Library"] = "Biblioth\195\168ques", - ["Map"] = "Carte", - ["Mail"] = "Courrier", - ["Miscellaneous"] = "Divers", - ["Quest"] = "Qu\195\170tes", - ["Raid"] = "Raid", - ["Tradeskill"] = "M\195\169tiers", - ["UnitFrame"] = "Fen\195\170tres d'unit\195\169", - } -elseif GetLocale() == "koKR" then - STANDBY = "|cffff5050(????)|r" - - TITLE = "??" - NOTES = "??" - VERSION = "??" - AUTHOR = "???" - DATE = "??" - CATEGORY = "??" - EMAIL = "E-mail" - WEBSITE = "????" - CREDITS = "Credits" -- fix - - ABOUT = "??" - PRINT_ADDON_INFO = "??? ?? ??" - - CATEGORIES = { - ["Action Bars"] = "???", - ["Auction"] = "??", - ["Audio"] = "??", - ["Battlegrounds/PvP"] = "??/PvP", - ["Buffs"] = "??", - ["Chat/Communication"] = "??/????", - ["Druid"] = "????", - ["Hunter"] = "???", - ["Mage"] = "???", - ["Paladin"] = "???", - ["Priest"] = "??", - ["Rogue"] = "??", - ["Shaman"] = "???", - ["Warlock"] = "????", - ["Warrior"] = "??", - ["Healer"] = "??", - ["Tank"] = "??", - ["Caster"] = "???", - ["Combat"] = "??", - ["Compilations"] = "??", - ["Data Export"] = "?? ??", - ["Development Tools"] = "?? ??", - ["Guild"] = "??", - ["Frame Modification"] = "?? ??", - ["Interface Enhancements"] = "????? ??", - ["Inventory"] = "????", - ["Library"] = "?????", - ["Map"] = "??", - ["Mail"] = "??", - ["Miscellaneous"] = "??", - ["Quest"] = "???", - ["Raid"] = "???", - ["Tradeskill"] = "????", - ["UnitFrame"] = "?? ???", - } -elseif GetLocale() == "zhTW" then - STANDBY = "|cffff5050(??)|r" - - TITLE = "??" - NOTES = "??" - VERSION = "??" - AUTHOR = "??" - DATE = "??" - CATEGORY = "??" - EMAIL = "E-mail" - WEBSITE = "??" - CREDITS = "Credits" -- fix - - ABOUT = "??" - PRINT_ADDON_INFO = "??????" - - CATEGORIES = { - ["Action Bars"] = "???", - ["Auction"] = "??", - ["Audio"] = "??", - ["Battlegrounds/PvP"] = "??/PvP", - ["Buffs"] = "??", - ["Chat/Communication"] = "??/??", - ["Druid"] = "???", - ["Hunter"] = "??", - ["Mage"] = "??", - ["Paladin"] = "???", - ["Priest"] = "??", - ["Rogue"] = "??", - ["Shaman"] = "??", - ["Warlock"] = "??", - ["Warrior"] = "??", - ["Healer"] = "???", - ["Tank"] = "??", - ["Caster"] = "???", - ["Combat"] = "??", - ["Compilations"] = "??", - ["Data Export"] = "????", - ["Development Tools"] = "????", - ["Guild"] = "??", - ["Frame Modification"] = "????", - ["Interface Enhancements"] = "????", - ["Inventory"] = "??", - ["Library"] = "???", - ["Map"] = "??", - ["Mail"] = "??", - ["Miscellaneous"] = "??", - ["Quest"] = "??", - ["Raid"] = "??", - ["Tradeskill"] = "????", - ["UnitFrame"] = "????", - } -elseif GetLocale() == "zhCN" then - STANDBY = "|cffff5050(\230\154\130\230\140\130)|r" - - TITLE = "\230\160\135\233\162\152" - NOTES = "\233\153\132\230\179\168" - VERSION = "\231\137\136\230\156\172" - AUTHOR = "\228\189\156\232\128\133" - DATE = "\230\151\165\230\156\159" - CATEGORY = "\229\136\134\231\177\187" - EMAIL = "\231\148\181\229\173\144\233\130\174\228\187\182" - WEBSITE = "\231\189\145\231\171\153" - CREDITS = "Credits" -- fix - - ABOUT = "\229\133\179\228\186\142" - PRINT_ADDON_INFO = "\229\141\176\229\136\151\229\135\186\230\143\146\228\187\182\228\191\161\230\129\175" - - CATEGORIES = { - ["Action Bars"] = "\229\138\168\228\189\156\230\157\161", - ["Auction"] = "\230\139\141\229\141\150", - ["Audio"] = "\233\159\179\233\162\145", - ["Battlegrounds/PvP"] = "\230\136\152\229\156\186/PvP", - ["Buffs"] = "\229\162\158\231\155\138\233\173\148\230\179\149", - ["Chat/Communication"] = "\232\129\138\229\164\169/\228\186\164\230\181\129", - ["Druid"] = "\229\190\183\233\178\129\228\188\138", - ["Hunter"] = "\231\140\142\228\186\186", - ["Mage"] = "\230\179\149\229\184\136", - ["Paladin"] = "\229\156\163\233\170\145\229\163\171", - ["Priest"] = "\231\137\167\229\184\136", - ["Rogue"] = "\231\155\151\232\180\188", - ["Shaman"] = "\232\144\168\230\187\161\231\165\173\229\143\184", - ["Warlock"] = "\230\156\175\229\163\171", - ["Warrior"] = "\230\136\152\229\163\171", --- ["Healer"] = "\230\178\187\231\150\151\228\191\157\233\154\156", --- ["Tank"] = "\232\191\145\230\136\152\230\142\167\229\136\182", --- ["Caster"] = "\232\191\156\231\168\139\232\190\147\229\135\186", - ["Combat"] = "\230\136\152\230\150\151", - ["Compilations"] = "\231\188\150\232\175\145", - ["Data Export"] = "\230\149\176\230\141\174\229\175\188\229\135\186", - ["Development Tools"] = "\229\188\128\229\143\145\229\183\165\229\133\183", - ["Guild"] = "\229\133\172\228\188\154", - ["Frame Modification"] = "\230\161\134\230\158\182\228\191\174\230\148\185", - ["Interface Enhancements"] = "\231\149\140\233\157\162\229\162\158\229\188\186", - ["Inventory"] = "\232\131\140\229\140\133", - ["Library"] = "\229\186\147", - ["Map"] = "\229\156\176\229\155\190", - ["Mail"] = "\233\130\174\228\187\182", - ["Miscellaneous"] = "\230\157\130\233\161\185", - ["Quest"] = "\228\187\187\229\138\161", - ["Raid"] = "\229\155\162\233\152\159", - ["Tradeskill"] = "\229\149\134\228\184\154\230\138\128\232\131\189", - ["UnitFrame"] = "\229\164\180\229\131\143\230\161\134\230\158\182", - } -else -- enUS - STANDBY = "|cffff5050(standby)|r" - - TITLE = "Title" - NOTES = "Notes" - VERSION = "Version" - AUTHOR = "Author" - DATE = "Date" - CATEGORY = "Category" - EMAIL = "E-mail" - WEBSITE = "Website" - CREDITS = "Credits" - - ABOUT = "About" - PRINT_ADDON_INFO = "Show information about the addon." - - CATEGORIES = { - ["Action Bars"] = "Action Bars", - ["Auction"] = "Auction", - ["Audio"] = "Audio", - ["Battlegrounds/PvP"] = "Battlegrounds/PvP", - ["Buffs"] = "Buffs", - ["Chat/Communication"] = "Chat/Communication", - ["Druid"] = "Druid", - ["Hunter"] = "Hunter", - ["Mage"] = "Mage", - ["Paladin"] = "Paladin", - ["Priest"] = "Priest", - ["Rogue"] = "Rogue", - ["Shaman"] = "Shaman", - ["Warlock"] = "Warlock", - ["Warrior"] = "Warrior", - ["Healer"] = "Healer", - ["Tank"] = "Tank", - ["Caster"] = "Caster", - ["Combat"] = "Combat", - ["Compilations"] = "Compilations", - ["Data Export"] = "Data Export", - ["Development Tools"] = "Development Tools", - ["Guild"] = "Guild", - ["Frame Modification"] = "Frame Modification", - ["Interface Enhancements"] = "Interface Enhancements", - ["Inventory"] = "Inventory", - ["Library"] = "Library", - ["Map"] = "Map", - ["Mail"] = "Mail", - ["Miscellaneous"] = "Miscellaneous", - ["Quest"] = "Quest", - ["Raid"] = "Raid", - ["Tradeskill"] = "Tradeskill", - ["UnitFrame"] = "UnitFrame", - } -end - -setmetatable(CATEGORIES, { __index = function(self, key) -- case-insensitive - local lowerKey = key:lower() - for k,v in pairs(CATEGORIES) do - if k:lower() == lowerKey then - return v - end - end -end }) - --- Create the library object - -local AceOO = AceLibrary("AceOO-2.0") -local AceAddon = AceOO.Class() -local AceEvent -local AceConsole -local AceModuleCore - -function AceAddon:GetLocalizedCategory(name) - self:argCheck(name, 2, "string") - return CATEGORIES[name] or UNKNOWN -end - -function AceAddon:ToString() - return "AceAddon" -end - -local function print(text) - DEFAULT_CHAT_FRAME:AddMessage(text) -end - -function AceAddon:ADDON_LOADED(name) - while table.getn(self.nextAddon) > 0 do - local addon = table.remove(self.nextAddon, 1) - table.insert(self.addons, addon) - if not self.addons[name] then - self.addons[name] = addon - end - self:InitializeAddon(addon, name) - end -end - -local function RegisterOnEnable(self) - if DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage then -- HACK - AceAddon.playerLoginFired = true - end - if AceAddon.playerLoginFired then - AceAddon.addonsStarted[self] = true - if (type(self.IsActive) ~= "function" or self:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(self) or AceModuleCore:IsModuleActive(self)) then - local current = self.class - while true do - if current == AceOO.Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable,mixin,self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable,self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - end - else - if not AceAddon.addonsToOnEnable then - AceAddon.addonsToOnEnable = {} - end - table.insert(AceAddon.addonsToOnEnable, self) - end -end - -local function stripSpaces(text) - if type(text) == "string" then - return strtrim(text) - end - return text -end - -function AceAddon:InitializeAddon(addon, name) - if addon.name == nil then - addon.name = name - end - if GetAddOnMetadata then - -- TOC checks - if addon.title == nil then - addon.title = GetAddOnMetadata(name, "Title") - end - if type(addon.title) == "string" then - local num = addon.title:find(" |cff7fff7f %-Ace2%-|r$") - if num then - addon.title = addon.title:sub(1, num - 1) - end - addon.title = addon.title:trim() - end - if addon.notes == nil then - addon.notes = GetAddOnMetadata(name, "Notes") - end - if type(addon.notes) == "string" then - addon.notes = addon.notes:trim() - end - if addon.version == nil then - addon.version = GetAddOnMetadata(name, "Version") - end - if type(addon.version) == "string" then - if addon.version:find("%$Revision: (%d+) %$") then - addon.version = addon.version:gsub("%$Revision: (%d+) %$", "%1") - elseif addon.version:find("%$Rev: (%d+) %$") then - addon.version = addon.version:gsub("%$Rev: (%d+) %$", "%1") - elseif addon.version:find("%$LastChangedRevision: (%d+) %$") then - addon.version = addon.version:gsub("%$LastChangedRevision: (%d+) %$", "%1") - end - addon.version = addon.version:trim() - end - if addon.author == nil then - addon.author = GetAddOnMetadata(name, "Author") - end - if type(addon.author) == "string" then - addon.author = addon.author:trim() - end - if addon.credits == nil then - addon.credits = GetAddOnMetadata(name, "X-Credits") - end - if type(addon.credits) == "string" then - addon.credits = addon.credits:trim() - end - if addon.date == nil then - addon.date = GetAddOnMetadata(name, "X-Date") or GetAddOnMetadata(name, "X-ReleaseDate") - end - if type(addon.date) == "string" then - if addon.date:find("%$Date: (.-) %$") then - addon.date = addon.date:gsub("%$Date: (.-) %$", "%1") - elseif addon.date:find("%$LastChangedDate: (.-) %$") then - addon.date = addon.date:gsub("%$LastChangedDate: (.-) %$", "%1") - end - addon.date = addon.date:trim() - end - - if addon.category == nil then - addon.category = GetAddOnMetadata(name, "X-Category") - end - if type(addon.category) == "string" then - addon.category = addon.category:trim() - end - if addon.email == nil then - addon.email = GetAddOnMetadata(name, "X-eMail") or GetAddOnMetadata(name, "X-Email") - end - if type(addon.email) == "string" then - addon.email = addon.email:trim() - end - if addon.website == nil then - addon.website = GetAddOnMetadata(name, "X-Website") - end - if type(addon.website) == "string" then - addon.website = addon.website:trim() - end - end - local current = addon.class - while true do - if current == AceOO.Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedInitialize) == "function" then - mixin:OnEmbedInitialize(addon, name) - end - end - end - current = current.super - end - if type(addon.OnInitialize) == "function" then - safecall(addon.OnInitialize, addon, name) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonInitialized", addon) - end - RegisterOnEnable(addon) -end - -function AceAddon.prototype:PrintAddonInfo() - local x - if self.title then - x = "|cffffff7f" .. tostring(self.title) .. "|r" - elseif self.name then - x = "|cffffff7f" .. tostring(self.name) .. "|r" - else - x = "|cffffff7f<" .. tostring(self.class) .. " instance>|r" - end - if type(self.IsActive) == "function" then - if not self:IsActive() then - x = x .. " " .. STANDBY - end - end - if self.version then - x = x .. " - |cffffff7f" .. tostring(self.version) .. "|r" - end - if self.notes then - x = x .. " - " .. tostring(self.notes) - end - print(x) - if self.author then - print(" - |cffffff7f" .. AUTHOR .. ":|r " .. tostring(self.author)) - end - if self.credits then - print(" - |cffffff7f" .. CREDITS .. ":|r " .. tostring(self.credits)) - end - if self.date then - print(" - |cffffff7f" .. DATE .. ":|r " .. tostring(self.date)) - end - if self.category then - local category = CATEGORIES[self.category] - if category then - print(" - |cffffff7f" .. CATEGORY .. ":|r " .. category) - end - end - if self.email then - print(" - |cffffff7f" .. EMAIL .. ":|r " .. tostring(self.email)) - end - if self.website then - print(" - |cffffff7f" .. WEBSITE .. ":|r " .. tostring(self.website)) - end -end - -local options -function AceAddon:GetAceOptionsDataTable(target) - if not options then - options = { - about = { - name = ABOUT, - desc = PRINT_ADDON_INFO, - type = "execute", - func = "PrintAddonInfo", - order = -1, - } - } - end - return options -end - -function AceAddon:PLAYER_LOGIN() - self.playerLoginFired = true - if self.addonsToOnEnable then - while table.getn(self.addonsToOnEnable) > 0 do - local addon = table.remove(self.addonsToOnEnable, 1) - self.addonsStarted[addon] = true - if (type(addon.IsActive) ~= "function" or addon:IsActive()) and (not AceModuleCore or not AceModuleCore:IsModule(addon) or AceModuleCore:IsModuleActive(addon)) then - local current = addon.class - while true do - if current == AceOO.Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable,mixin,addon) - end - end - end - current = current.super - end - if type(addon.OnEnable) == "function" then - safecall(addon.OnEnable,addon) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", addon) - end - end - end - self.addonsToOnEnable = nil - end -end - -function AceAddon.prototype:Inject(t) - AceAddon:argCheck(t, 2, "table") - for k,v in pairs(t) do - self[k] = v - end -end - -function AceAddon.prototype:init() - if not AceEvent then - error(MAJOR_VERSION .. " requires AceEvent-2.0", 4) - end - AceAddon.super.prototype.init(self) - - self.super = self.class.prototype - - AceAddon:RegisterEvent("ADDON_LOADED", "ADDON_LOADED", true) - table.insert(AceAddon.nextAddon, self) -end - -function AceAddon.prototype:ToString() - local x - if type(self.title) == "string" then - x = self.title - elseif type(self.name) == "string" then - x = self.name - else - x = "<" .. tostring(self.class) .. " instance>" - end - if (type(self.IsActive) == "function" and not self:IsActive()) or (AceModuleCore and AceModuleCore:IsModule(addon) and AceModuleCore:IsModuleActive(addon)) then - x = x .. " " .. STANDBY - end - return x -end - -AceAddon.new = function(self, ...) - local class = AceAddon:pcall(AceOO.Classpool, self, ...) - return class:new() -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - - AceEvent:embed(self) - - self:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) - elseif major == "AceConsole-2.0" then - AceConsole = instance - - local slashCommands = { "/ace2" } - local _,_,_,enabled,loadable = GetAddOnInfo("Ace") - if not enabled or not loadable then - table.insert(slashCommands, "/ace") - end - local function listAddon(addon, depth) - if not depth then - depth = 0 - end - - local s = (" "):rep(depth) .. " - " .. tostring(addon) - if rawget(addon, 'version') then - s = s .. " - |cffffff7f" .. tostring(addon.version) .. "|r" - end - if rawget(addon, 'slashCommand') then - s = s .. " |cffffff7f(" .. tostring(addon.slashCommand) .. ")|r" - end - print(s) - if type(rawget(addon, 'modules')) == "table" then - local i = 0 - for k,v in pairs(addon.modules) do - i = i + 1 - if i == 6 then - print((" "):rep(depth + 1) .. " - more...") - break - else - listAddon(v, depth + 1) - end - end - end - end - local function listNormalAddon(i) - local name,_,_,enabled,loadable = GetAddOnInfo(i) - if not loadable then - enabled = false - end - if self.addons[name] then - local addon = self.addons[name] - if not AceCoreAddon or not AceCoreAddon:IsModule(addon) then - listAddon(addon) - end - else - local s = " - " .. tostring(GetAddOnMetadata(i, "Title") or name) - local version = GetAddOnMetadata(i, "Version") - if version then - if version:find("%$Revision: (%d+) %$") then - version = version:gsub("%$Revision: (%d+) %$", "%1") - elseif version:find("%$Rev: (%d+) %$") then - version = version:gsub("%$Rev: (%d+) %$", "%1") - elseif version:find("%$LastChangedRevision: (%d+) %$") then - version = version:gsub("%$LastChangedRevision: (%d+) %$", "%1") - end - s = s .. " - |cffffff7f" .. version .. "|r" - end - if not enabled then - s = s .. " |cffff0000(disabled)|r" - end - if IsAddOnLoadOnDemand(i) then - s = s .. " |cff00ff00[LoD]|r" - end - print(s) - end - end - local function mySort(alpha, bravo) - return tostring(alpha) < tostring(bravo) - end - AceConsole.RegisterChatCommand(self, slashCommands, { - desc = "AddOn development framework", - name = "Ace2", - type = "group", - args = { - about = { - desc = "Get information about Ace2", - name = "About", - type = "execute", - func = function() - print("|cffffff7fAce2|r - |cffffff7f2.0." .. MINOR_VERSION:gsub("%$Revision: (%d+) %$", "%1") .. "|r - AddOn development framework") - print(" - |cffffff7f" .. AUTHOR .. ":|r Ace Development Team") - print(" - |cffffff7f" .. WEBSITE .. ":|r http://www.wowace.com/") - end - }, - list = { - desc = "List addons", - name = "List", - type = "group", - args = { - ace2 = { - desc = "List addons using Ace2", - name = "Ace2", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0") - table.sort(self.addons, mySort) - for _,v in ipairs(self.addons) do - if not AceCoreAddon or not AceCoreAddon:IsModule(v) then - listAddon(v) - end - end - end - }, - all = { - desc = "List all addons", - name = "All", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0") - local count = GetNumAddOns() - for i = 1, count do - listNormalAddon(i) - end - end - }, - enabled = { - desc = "List all enabled addons", - name = "Enabled", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0") - local count = GetNumAddOns() - for i = 1, count do - local _,_,_,enabled,loadable = GetAddOnInfo(i) - if enabled and loadable then - listNormalAddon(i) - end - end - end - }, - disabled = { - desc = "List all disabled addons", - name = "Disabled", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0") - local count = GetNumAddOns() - for i = 1, count do - local _,_,_,enabled,loadable = GetAddOnInfo(i) - if not enabled or not loadable then - listNormalAddon(i) - end - end - end - }, - lod = { - desc = "List all LoadOnDemand addons", - name = "LoadOnDemand", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local AceCoreAddon = AceLibrary:HasInstance("AceCoreAddon-2.0") and AceLibrary("AceCoreAddon-2.0") - local count = GetNumAddOns() - for i = 1, count do - if IsAddOnLoadOnDemand(i) then - listNormalAddon(i) - end - end - end - }, - ace1 = { - desc = "List all addons using Ace1", - name = "Ace 1.x", - type = "execute", - func = function() - print("|cffffff7fAddon list:|r") - local count = GetNumAddOns() - for i = 1, count do - local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) - if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then - listNormalAddon(i) - end - end - end - }, - libs = { - desc = "List all libraries using AceLibrary", - name = "Libraries", - type = "execute", - func = function() - if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then - print("|cffffff7fLibrary list:|r") - for name, data in pairs(AceLibrary.libs) do - local s - if data.minor then - s = " - " .. tostring(name) .. "." .. tostring(data.minor) - else - s = " - " .. tostring(name) - end - if rawget(AceLibrary(name), 'slashCommand') then - s = s .. " |cffffff7f(" .. tostring(AceLibrary(name).slashCommand) .. "|cffffff7f)" - end - print(s) - end - end - end - }, - search = { - desc = "Search by name", - name = "Search", - type = "text", - usage = "<keyword>", - input = true, - get = false, - set = function(...) - local arg = { ... } - for i,v in ipairs(arg) do - arg[i] = v:gsub('%*', '.*'):gsub('%%', '%%%%'):lower() - end - local count = GetNumAddOns() - for i = 1, count do - local name = GetAddOnInfo(i) - local good = true - for _,v in ipairs(arg) do - if not name:lower():find(v) then - good = false - break - end - end - if good then - listNormalAddon(i) - end - end - end - } - }, - }, - enable = { - desc = "Enable addon", - name = "Enable", - type = "text", - usage = "<addon>", - get = false, - set = function(text) - local name,title,_,enabled,_,reason = GetAddOnInfo(text) - if reason == "MISSING" then - print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text)) - elseif not enabled then - EnableAddOn(text) - print(string.format("|cffffff7fAce2:|r %s is now enabled", title or name)) - else - print(string.format("|cffffff7fAce2:|r %s is already enabled", title or name)) - end - end, - }, - disable = { - desc = "Disable addon", - name = "Disable", - type = "text", - usage = "<addon>", - get = false, - set = function(text) - local name,title,_,enabled,_,reason = GetAddOnInfo(text) - if reason == "MISSING" then - print(string.format("|cffffff7fAce2:|r AddOn %q does not exist", text)) - elseif enabled then - DisableAddOn(text) - print(string.format("|cffffff7fAce2:|r %s is now disabled", title or name)) - else - print(string.format("|cffffff7fAce2:|r %s is already disabled", title or name)) - end - end, - }, - load = { - desc = "Load addon", - name = "Load", - type = "text", - usage = "<addon>", - get = false, - set = function(text) - local name,title,_,_,loadable,reason = GetAddOnInfo(text) - if reason == "MISSING" then - print(string.format("|cffffff7fAce2:|r AddOn %q does not exist.", text)) - elseif not loadable then - print(string.format("|cffffff7fAce2:|r AddOn %q is not loadable. Reason: %s", text, reason)) - else - LoadAddOn(text) - print(string.format("|cffffff7fAce2:|r %s is now loaded", title or name)) - end - end - }, - info = { - desc = "Display information", - name = "Information", - type = "execute", - func = function() - local mem, threshold = gcinfo() - print(string.format(" - |cffffff7fMemory usage [|r%.3f MiB|cffffff7f]|r", mem / 1024)) - if threshold then - print(string.format(" - |cffffff7fThreshold [|r%.3f MiB|cffffff7f]|r", threshold / 1024)) - end - print(string.format(" - |cffffff7fFramerate [|r%.0f fps|cffffff7f]|r", GetFramerate())) - local bandwidthIn, bandwidthOut, latency = GetNetStats() - bandwidthIn, bandwidthOut = floor(bandwidthIn * 1024), floor(bandwidthOut * 1024) - print(string.format(" - |cffffff7fLatency [|r%.0f ms|cffffff7f]|r", latency)) - print(string.format(" - |cffffff7fBandwidth in [|r%.0f B/s|cffffff7f]|r", bandwidthIn)) - print(string.format(" - |cffffff7fBandwidth out [|r%.0f B/s|cffffff7f]|r", bandwidthOut)) - print(string.format(" - |cffffff7fTotal addons [|r%d|cffffff7f]|r", GetNumAddOns())) - print(string.format(" - |cffffff7fAce2 addons [|r%d|cffffff7f]|r", table.getn(self.addons))) - local ace = 0 - local enabled = 0 - local disabled = 0 - local lod = 0 - for i = 1, GetNumAddOns() do - local dep1, dep2, dep3, dep4 = GetAddOnDependencies(i) - if dep1 == "Ace" or dep2 == "Ace" or dep3 == "Ace" or dep4 == "Ace" then - ace = ace + 1 - end - if IsAddOnLoadOnDemand(i) then - lod = lod + 1 - end - local _,_,_,IsActive,loadable = GetAddOnInfo(i) - if not IsActive or not loadable then - disabled = disabled + 1 - else - enabled = enabled + 1 - end - end - print(string.format(" - |cffffff7fAce 1.x addons [|r%d|cffffff7f]|r", ace)) - print(string.format(" - |cffffff7fLoadOnDemand addons [|r%d|cffffff7f]|r", lod)) - print(string.format(" - |cffffff7fenabled addons [|r%d|cffffff7f]|r", enabled)) - print(string.format(" - |cffffff7fdisabled addons [|r%d|cffffff7f]|r", disabled)) - local libs = 0 - if type(AceLibrary) == "table" and type(AceLibrary.libs) == "table" then - for _ in pairs(AceLibrary.libs) do - libs = libs + 1 - end - end - print(string.format(" - |cffffff7fAceLibrary instances [|r%d|cffffff7f]|r", libs)) - end - } - } - }) - elseif major == "AceModuleCore-2.0" then - AceModuleCore = instance - end -end - -local function activate(self, oldLib, oldDeactivate) - AceAddon = self - - if oldLib then - self.playerLoginFired = oldLib.playerLoginFired or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage - self.addonsToOnEnable = oldLib.addonsToOnEnable - self.addons = oldLib.addons - self.nextAddon = oldLib.nextAddon - self.addonsStarted = oldLib.addonsStarted - end - if not self.addons then - self.addons = {} - end - if not self.nextAddon then - self.nextAddon = {} - end - if not self.addonsStarted then - self.addonsStarted = {} - end - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceAddon, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/libs/AceConsole-2.0/AceConsole-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2058 +0,0 @@ ---[[ -Name: AceConsole-2.0 -Revision: $Rev: 19865 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceConsole-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceConsole-2.0 -Description: Mixin to allow for input/output capabilities. This uses the - AceOptions data table format to determine input. - http://wiki.wowace.com/index.php/AceOptions_data_table -Dependencies: AceLibrary, AceOO-2.0 -]] - -local MAJOR_VERSION = "AceConsole-2.0" -local MINOR_VERSION = "$Revision: 19865 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end - -local MAP_ONOFF, USAGE, IS_CURRENTLY_SET_TO, IS_NOW_SET_TO, IS_NOT_A_VALID_OPTION_FOR, IS_NOT_A_VALID_VALUE_FOR, NO_OPTIONS_AVAILABLE, OPTION_HANDLER_NOT_FOUND, OPTION_HANDLER_NOT_VALID, OPTION_IS_DISABLED, KEYBINDING_USAGE -if GetLocale() == "deDE" then - MAP_ONOFF = { [false] = "|cffff0000Aus|r", [true] = "|cff00ff00An|r" } - USAGE = "Benutzung" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r steht momentan auf |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r ist nun auf |cffffff7f[|r%s|cffffff7f]|r gesetzt" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] ist keine g\195\188ltige Option f\195\188r |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] ist kein g\195\188ltiger Wert f\195\188r |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "Keine Optionen verfügbar" - OPTION_HANDLER_NOT_FOUND = "Optionen handler |cffffff7f%q|r nicht gefunden." - OPTION_HANDLER_NOT_VALID = "Optionen handler nicht g\195\188ltig." - OPTION_IS_DISABLED = "Option |cffffff7f%s|r deaktiviert." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix -elseif GetLocale() == "frFR" then - MAP_ONOFF = { [false] = "|cffff0000Inactif|r", [true] = "|cff00ff00Actif|r" } - USAGE = "Utilisation" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r est actuellement positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r est maintenant positionn\195\169 sur |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] n'est pas une option valide pour |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] n'est pas une valeur valide pour |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "Pas d'options disponibles" - OPTION_HANDLER_NOT_FOUND = "Le gestionnaire d'option |cffffff7f%q|r n'a pas \195\169t\195\169 trouv\195\169." - OPTION_HANDLER_NOT_VALID = "Le gestionnaire d'option n'est pas valide." - OPTION_IS_DISABLED = "L'option |cffffff7f%s|r est d\195\169sactiv\195\169e." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix -elseif GetLocale() == "koKR" then - MAP_ONOFF = { [false] = "|cffff0000끔|r", [true] = "|cff00ff00켬|r" } - USAGE = "사용법" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r|1은;는; 현재 상태는 |cffffff7f[|r%s|cffffff7f]|r|1으로;로; 설정되어 있습니다" - IS_NOW_SET_TO = "|cffffff7f%s|r|1을;를; |cffffff7f[|r%s|cffffff7f]|r 상태로 변경합니다" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용불가능한 설정입니다" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r]|1은;는; |cffffff7f%s|r에서 사용불가능한 설정값입니다" - NO_OPTIONS_AVAILABLE = "가능한 설정이 없습니다" - OPTION_HANDLER_NOT_FOUND = "설정 조정값인 |cffffff7f%q|r|1을;를; 찾지 못했습니다." - OPTION_HANDLER_NOT_VALID = "설정 조정값이 올바르지 않습니다." - OPTION_IS_DISABLED = "|cffffff7f%s|r 설정은 사용할 수 없습니다." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix -elseif GetLocale() == "zhCN" then - MAP_ONOFF = { [false] = "|cffff0000\229\133\179\233\151\173|r", [true] = "|cff00ff00\229\188\128\229\144\175|r" } - USAGE = "\231\148\168\230\179\149" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r \229\189\147\229\137\141\232\162\171\232\174\190\231\189\174 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r \231\142\176\229\156\168\232\162\171\232\174\190\231\189\174\228\184\186 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\231\154\132\233\128\137\233\161\185 \228\184\186 |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] \228\184\141\230\152\175\228\184\128\228\184\170\230\156\137\230\149\136\229\128\188 \228\184\186 |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "\230\178\161\230\156\137\233\128\137\233\161\185\229\143\175\231\148\168" - OPTION_HANDLER_NOT_FOUND = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 |cffffff7f%q|r \230\178\161\230\159\165\230\137\190." - OPTION_HANDLER_NOT_VALID = "\233\128\137\233\161\185\229\164\132\231\144\134\231\168\139\229\186\143 \230\151\160\230\149\136." - OPTION_IS_DISABLED = "\233\128\137\233\161\185 |cffffff7f%s|r \228\184\141\229\174\140\230\149\180." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix -elseif GetLocale() == "zhTW" then - MAP_ONOFF = { [false] = "|cffff0000關閉|r", [true] = "|cff00ff00開啟|r" } - USAGE = "用法" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r 目前的設定為 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r 現在被設定為 |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] 是一個不符合規定的選項,對 |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] 是一個不符合規定的數值,對 |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "沒有可用的選項處理器。" - OPTION_HANDLER_NOT_FOUND = "找不到 |cffffff7f%q|r 選項處理器。" - OPTION_HANDLER_NOT_VALID = "選項處理器不符合規定。" - OPTION_IS_DISABLED = "|cffffff7f%s|r 已被停用。" - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -- fix -else -- enUS - MAP_ONOFF = { [false] = "|cffff0000Off|r", [true] = "|cff00ff00On|r" } - USAGE = "Usage" - IS_CURRENTLY_SET_TO = "|cffffff7f%s|r is currently set to |cffffff7f[|r%s|cffffff7f]|r" - IS_NOW_SET_TO = "|cffffff7f%s|r is now set to |cffffff7f[|r%s|cffffff7f]|r" - IS_NOT_A_VALID_OPTION_FOR = "[|cffffff7f%s|r] is not a valid option for |cffffff7f%s|r" - IS_NOT_A_VALID_VALUE_FOR = "[|cffffff7f%s|r] is not a valid value for |cffffff7f%s|r" - NO_OPTIONS_AVAILABLE = "No options available" - OPTION_HANDLER_NOT_FOUND = "Option handler |cffffff7f%q|r not found." - OPTION_HANDLER_NOT_VALID = "Option handler not valid." - OPTION_IS_DISABLED = "Option |cffffff7f%s|r is disabled." - KEYBINDING_USAGE = "<ALT-CTRL-SHIFT-KEY>" -end - -local NONE = NONE or "None" - -local AceOO = AceLibrary("AceOO-2.0") -local AceEvent - -local AceConsole = AceOO.Mixin { "Print", "PrintComma", "CustomPrint", "RegisterChatCommand" } -local Dewdrop - -local _G = getfenv(0) - -local function print(text, name, r, g, b, frame, delay) - if not text or text:len() == 0 then - text = " " - end - if not name or name == AceConsole then - (frame or DEFAULT_CHAT_FRAME):AddMessage(text, r, g, b, nil, delay or 5) - else - (frame or DEFAULT_CHAT_FRAME):AddMessage("|cffffff78" .. tostring(name) .. ":|r " .. text, r, g, b, nil, delay or 5) - end -end - -local real_tostring = tostring - -local function tostring(t) - if type(t) == "table" then - if type(rawget(t, 0)) == "userdata" and type(t.GetObjectType) == "function" then - return string.format("<%s:%s>", t:GetObjectType(), t:GetName() or "(anon)") - end - end - return real_tostring(t) -end - -local function _tostring(...) - if select('#', ...) < 1 then - return - end - return tostring((...)), _tostring(select(2, ...)) -end -function AceConsole:CustomPrint(r, g, b, frame, delay, connector, a1, ...) - if tostring(a1):find("%%") and select('#', ...) >= 1 then - local success, text = pcall(string.format, _tostring(a1, ...)) - if success then - print(text, self, r, g, b, frame or self.printFrame, delay) - return - end - end - print((connector or " "):join(_tostring(a1, ...)), self, r, g, b, frame or self.printFrame, delay) -end - -function AceConsole:Print(...) - return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, " ", ...) -end - -function AceConsole:PrintComma(...) - return AceConsole.CustomPrint(self, nil, nil, nil, nil, nil, ", ", ...) -end - -local work -local argwork - -local function findTableLevel(self, options, chat, text, index, passTable) - if not index then - index = 1 - if work then - for k,v in pairs(work) do - work[k] = nil - end - for k,v in pairs(argwork) do - argwork[k] = nil - end - else - work = {} - argwork = {} - end - local len = text:len() - local count - repeat - text, count = text:gsub("(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[[^%]]-) (.-%]|h|r)", "%1\001%2") - until count == 0 - text = text:gsub("(%]|h|r)(|cff%x%x%x%x%x%x|Hitem:%d-:%d-:%d-:%d-|h%[)", "%1 %2") - for token in text:gmatch("([^%s]+)") do - local token = token - local num = tonumber(token) - if num then - token = num - else - token = token:gsub("\001", " ") - end - table.insert(work, token) - end - end - - local path = chat - for i = 1, index - 1 do - path = path .. " " .. tostring(work[i]) - end - - if type(options.args) == "table" then - local disabled, hidden = options.disabled, options.cmdHidden or options.hidden - if hidden then - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local handler = options.handler or self - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled() - elseif type(disabled) == "string" then - local handler = options.handler or self - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - disabled = handler[f](handler) - if neg then - disabled = not disabled - end - end - end - if not disabled then - local next = work[index] and work[index]:lower() - if next then - for k,v in pairs(options.args) do - local good = false - if k:lower() == next then - good = true - elseif type(v.aliases) == "table" then - for _,alias in ipairs(v.aliases) do - if alias:lower() == next then - good = true - break - end - end - elseif type(v.aliases) == "string" and v.aliases:lower() == next then - good = true - end - if good then - return findTableLevel(options.handler or self, v, chat, text, index + 1, options.pass and options or nil) - end - end - end - end - end - for i = index, #work do - table.insert(argwork, work[i]) - end - return options, path, argwork, options.handler or self, passTable, passTable and work[index - 1] -end - -local function validateOptionsMethods(self, options, position) - if type(options) ~= "table" then - return "Options must be a table.", position - end - self = options.handler or self - if options.type == "execute" then - if options.func and type(options.func) ~= "string" and type(options.func) ~= "function" then - return "func must be a string or function", position - end - if options.func and type(options.func) == "string" and type(self[options.func]) ~= "function" then - return string.format("%q is not a proper function", options.func), position - end - else - if options.get then - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return "get must be a string or function", position - end - if type(options.get) == "string" then - local f = options.get - if options.type == "toggle" then - f = f:match("^~(.-)$") or f - end - if type(self[f]) ~= "function" then - return string.format("%q is not a proper function", f), position - end - end - end - if options.set then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return "set must be a string or function", position - end - if type(options.set) == "string" and type(self[options.set]) ~= "function" then - return string.format("%q is not a proper function", options.set), position - end - end - if options.validate and type(options.validate) ~= "table" and options.validate ~= "keybinding" then - if type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return "validate must be a string or function", position - end - if type(options.validate) == "string" and type(self[options.validate]) ~= "function" then - return string.format("%q is not a proper function", options.validate), position - end - end - end - if options.disabled and type(options.disabled) == "string" then - local f = options.disabled - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return string.format("%q is not a proper function", f), position - end - end - if options.cmdHidden and type(options.cmdHidden) == "string" then - local f = options.cmdHidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return string.format("%q is not a proper function", f), position - end - end - if options.guiHidden and type(options.guiHidden) == "string" then - local f = options.guiHidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return string.format("%q is not a proper function", f), position - end - end - if options.hidden and type(options.hidden) == "string" then - local f = options.hidden - f = f:match("^~(.-)$") or f - if type(self[f]) ~= "function" then - return string.format("%q is not a proper function", f), position - end - end - if options.type == "group" and type(options.args) == "table" then - for k,v in pairs(options.args) do - if type(v) == "table" then - local newposition - if position then - newposition = position .. ".args." .. k - else - newposition = "args." .. k - end - local err, pos = validateOptionsMethods(self, v, newposition) - if err then - return err, pos - end - end - end - end -end - -local function validateOptions(options, position, baseOptions, fromPass) - if not baseOptions then - baseOptions = options - end - if type(options) ~= "table" then - return "Options must be a table.", position - end - local kind = options.type - if type(kind) ~= "string" then - return '"type" must be a string.', position - elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then - return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position - end - if options.aliases then - if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then - return '"alias" must be a table or string', position - end - end - if not fromPass then - if kind == "execute" then - if type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - elseif kind == "range" or kind == "text" or kind == "toggle" then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if kind == "text" and options.get == false then - elseif type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif kind == "group" and options.pass then - if options.pass ~= true then - return '"pass" must be either nil, true, or false', position - end - if not options.func then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - end - else - if kind == "group" then - return 'cannot have "type" = "group" as a subgroup of a passing group', position - end - end - if options ~= baseOptions then - if kind == "header" then - elseif type(options.desc) ~= "string" then - return '"desc" must be a string', position - elseif options.desc:len() == 0 then - return '"desc" cannot be a 0-length string', position - end - end - - if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then - if options.type == "header" and not options.cmdName and not options.name then - elseif options.cmdName then - if type(options.cmdName) ~= "string" then - return '"cmdName" must be a string or nil', position - elseif options.cmdName:len() == 0 then - return '"cmdName" cannot be a 0-length string', position - end - if type(options.guiName) ~= "string" then - if not options.guiNameIsMap then - return '"guiName" must be a string or nil', position - end - elseif options.guiName:len() == 0 then - return '"guiName" cannot be a 0-length string', position - end - else - if type(options.name) ~= "string" then - return '"name" must be a string', position - elseif options.name:len() == 0 then - return '"name" cannot be a 0-length string', position - end - end - end - if options.guiNameIsMap then - if type(options.guiNameIsMap) ~= "boolean" then - return '"guiNameIsMap" must be a boolean or nil', position - elseif options.type ~= "toggle" then - return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position - elseif type(options.map) ~= "table" then - return '"map" must be a table', position - end - end - if options.message and type(options.message) ~= "string" then - return '"message" must be a string or nil', position - end - if options.error and type(options.error) ~= "string" then - return '"error" must be a string or nil', position - end - if options.current and type(options.current) ~= "string" then - return '"current" must be a string or nil', position - end - if options.order then - if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then - return '"order" must be a non-zero number or nil', position - end - end - if options.disabled then - if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then - return '"disabled" must be a function, string, or boolean', position - end - end - if options.cmdHidden then - if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then - return '"cmdHidden" must be a function, string, or boolean', position - end - end - if options.guiHidden then - if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then - return '"guiHidden" must be a function, string, or boolean', position - end - end - if options.hidden then - if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then - return '"hidden" must be a function, string, or boolean', position - end - end - if kind == "text" then - if type(options.validate) == "table" then - local t = options.validate - local iTable = nil - for k,v in pairs(t) do - if type(k) == "number" then - if iTable == nil then - iTable = true - elseif not iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - elseif k < 1 or k > #t then - return '"validate" numeric keys must be indexed properly. >= 1 and <= #validate', position - end - else - if iTable == nil then - iTable = false - elseif iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - end - end - if type(v) ~= "string" then - return '"validate" values must all be strings', position - end - end - elseif options.validate == "keybinding" then - - else - if type(options.usage) ~= "string" then - return '"usage" must be a string', position - elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return '"validate" must be a string, function, or table', position - end - end - elseif kind == "range" then - if options.min or options.max then - if type(options.min) ~= "number" then - return '"min" must be a number', position - elseif type(options.max) ~= "number" then - return '"max" must be a number', position - elseif options.min >= options.max then - return '"min" must be less than "max"', position - end - end - if options.step then - if type(options.step) ~= "number" then - return '"step" must be a number', position - elseif options.step < 0 then - return '"step" must be nonnegative', position - end - end - if options.isPercent and options.isPercent ~= true then - return '"isPercent" must either be nil, true, or false', position - end - elseif kind == "toggle" then - if options.map then - if type(options.map) ~= "table" then - return '"map" must be a table', position - elseif type(options.map[true]) ~= "string" then - return '"map[true]" must be a string', position - elseif type(options.map[false]) ~= "string" then - return '"map[false]" must be a string', position - end - end - elseif kind == "color" then - if options.hasAlpha and options.hasAlpha ~= true then - return '"hasAlpha" must be nil, true, or false', position - end - elseif kind == "group" then - if options.pass and options.pass ~= true then - return '"pass" must be nil, true, or false', position - end - if type(options.args) ~= "table" then - return '"args" must be a table', position - end - for k,v in pairs(options.args) do - if type(k) ~= "string" then - return '"args" keys must be strings', position - elseif k:find("%s") then - return string.format('"args" keys must not include spaces. %q is not appropriate.', k), position - elseif k:len() == 0 then - return '"args" keys must not be 0-length strings.', position - end - if type(v) ~= "table" then - return '"args" values must be tables', position and position .. "." .. k or k - end - local newposition - if position then - newposition = position .. ".args." .. k - else - newposition = "args." .. k - end - local err, pos = validateOptions(v, newposition, baseOptions, options.pass) - if err then - return err, pos - end - end - end -end - -local colorTable -local colorFunc -local colorCancelFunc - -local function keybindingValidateFunc(text) - if text == nil or text == "NONE" then - return nil - end - text = text:upper() - local shift, ctrl, alt - local modifier - while true do - if text == "-" then - break - end - modifier, text = strsplit('-', text, 2) - if text then - if modifier ~= "SHIFT" and modifier ~= "CTRL" and modifier ~= "ALT" then - return false - end - if modifier == "SHIFT" then - if shift then - return false - end - shift = true - end - if modifier == "CTRL" then - if ctrl then - return false - end - ctrl = true - end - if modifier == "ALT" then - if alt then - return false - end - alt = true - end - else - text = modifier - break - end - end - if not text:find("^F%d+$") and text:len() ~= 1 and (text:byte() < 128 or text:len() > 4) and not _G["KEY_" .. text] then - return false - end - local s = text - if shift then - s = "SHIFT-" .. s - end - if ctrl then - s = "CTRL-" .. s - end - if alt then - s = "ALT-" .. s - end - return s -end -AceConsole.keybindingValidateFunc = keybindingValidateFunc - -local order - -local mysort_args -local mysort - -local function printUsage(self, handler, realOptions, options, path, args, quiet, filter) - if filter then - filter = "^" .. filter:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - end - local hidden, disabled = options.cmdHidden or options.hidden, options.disabled - if hidden then - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled() - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - disabled = handler[f](handler) - if neg then - disabled = not disabled - end - end - end - local kind = (options.type or "group"):lower() - if disabled then - print(string.format(OPTION_IS_DISABLED, path), realOptions.cmdName or realOptions.name or self) - elseif kind == "text" then - local var - if passTable then - if not passTable.get then - elseif type(passTable.get) == "function" then - var = passTable.get(passValue) - else - local handler = passTable.handler or handler - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if not options.get then - elseif type(options.get) == "function" then - var = options.get() - else - local handler = options.handler or handler - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - - local usage - if type(options.validate) == "table" then - if filter then - if not order then - order = {} - end - for k,v in pairs(options.validate) do - if v:find(filter) then - table.insert(order, v) - end - end - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - else - if not order then - order = {} - end - for k,v in pairs(options.validate) do - table.insert(order, v) - end - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - end - var = options.validate[var] or var - elseif options.validate == "keybinding" then - usage = KEYBINDING_USAGE - else - usage = options.usage or "<value>" - end - if not quiet then - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage), realOptions.cmdName or realOptions.name or self) - end - if (passTable and passTable.get) or options.get then - print(string.format(options.current or IS_CURRENTLY_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE))) - end - elseif kind == "range" then - local var - if passTable then - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - local handler = passTable.handler or handler - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - var = options.get() - else - local handler = options.handler or handler - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - - local usage - local min = options.min or 0 - local max = options.max or 1 - if options.isPercent then - min, max = min * 100, max * 100 - var = tostring(var * 100) .. "%" - end - local bit = "-" - if min < 0 or max < 0 then - bit = " - " - end - usage = string.format("(%s%s%s)", min, bit, max) - if not quiet then - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage), realOptions.cmdName or realOptions.name or self) - end - print(string.format(options.current or IS_CURRENTLY_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE))) - elseif kind == "group" then - local usage - if next(options.args) then - if not order then - order = {} - end - for k,v in pairs(options.args) do - if v.type ~= "header" then - local hidden = v.cmdHidden or v.hidden - if hidden then - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - end - if not hidden then - if filter then - if k:find(filter) then - table.insert(order, k) - elseif type(v.aliases) == "table" then - for _,bit in ipairs(v.aliases) do - if bit:find(filter) then - table.insert(order, k) - break - end - end - elseif type(v.aliases) == "string" then - if v.aliases:find(filter) then - table.insert(order, k) - end - end - else - table.insert(order, k) - end - end - end - end - if not mysort then - mysort = function(a, b) - local alpha, bravo = mysort_args[a], mysort_args[b] - local alpha_order = alpha and alpha.order or 100 - local bravo_order = bravo and bravo.order or 100 - if alpha_order == bravo_order then - return tostring(a) < tostring(b) - else - if alpha_order < 0 then - if bravo_order > 0 then - return false - end - else - if bravo_order < 0 then - return true - end - end - if alpha_order > 0 and bravo_order > 0 then - return tostring(a) < tostring(b) - end - return alpha_order < bravo_order - end - end - end - mysort_args = options.args - table.sort(order, mysort) - mysort_args = nil - if not quiet then - if options == realOptions then - if options.desc then - print(tostring(options.desc), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}")) - elseif self.description or self.notes then - print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}")) - else - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - end - else - if options.desc then - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - print(tostring(options.desc)) - else - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, "{" .. table.concat(order, " || ") .. "}"), realOptions.cmdName or realOptions.name or self) - end - end - end - for _,k in ipairs(order) do - local v = options.args[k] - if v then - local disabled = v.disabled - if disabled then - if type(disabled) == "function" then - disabled = disabled() - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - disabled = handler[f](handler) - if neg then - disabled = not disabled - end - end - end - if type(v.aliases) == "table" then - k = k .. " || " .. table.concat(v.aliases, " || ") - elseif type(v.aliases) == "string" then - k = k .. " || " .. v.aliases - end - if v.get then - local a1,a2,a3,a4 - if type(v.get) == "function" then - if options.pass then - a1,a2,a3,a4 = v.get(k) - else - a1,a2,a3,a4 = v.get() - end - else - local handler = v.handler or handler - local f = v.get - local neg - if v.type == "toggle" then - neg = f:match("^~(.-)$") - if neg then - f = neg - end - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - if options.pass then - a1,a2,a3,a4 = handler[f](handler, k) - else - a1,a2,a3,a4 = handler[f](handler) - end - if neg then - a1 = not a1 - end - end - if v.type == "color" then - if v.hasAlpha then - if not a1 or not a2 or not a3 or not a4 then - s = NONE - else - s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a4*255, a1*255, a2*255, a3*255, a4*255, a1*255, a2*255, a3*255) - end - else - if not a1 or not a2 or not a3 then - s = NONE - else - s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", a1*255, a2*255, a3*255, a1*255, a2*255, a3*255) - end - end - elseif v.type == "toggle" then - if v.map then - s = tostring(v.map[a1 and true or false] or NONE) - else - s = tostring(MAP_ONOFF[a1 and true or false] or NONE) - end - elseif v.type == "range" then - if v.isPercent then - s = tostring(a1 * 100) .. "%" - else - s = tostring(a1) - end - elseif v.type == "text" and type(v.validate) == "table" then - s = tostring(v.validate[a1] or a1 or NONE) - else - s = tostring(a1 or NONE) - end - if disabled then - local s = s:gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - print(string.format("|cffcfcfcf - %s: [%s] %s|r", k, s, desc)) - else - print(string.format(" - |cffffff7f%s: [|r%s|cffffff7f]|r %s", k, s, v.desc or NONE)) - end - else - if disabled then - local desc = (v.desc or NONE):gsub("|cff%x%x%x%x%x%x(.-)|r", "%1") - print(string.format("|cffcfcfcf - %s: %s", k, desc)) - else - print(string.format(" - |cffffff7f%s:|r %s", k, v.desc or NONE)) - end - end - end - end - for k in pairs(order) do - order[k] = nil - end - else - if options.desc then - desc = options.desc - print(string.format("|cffffff7f%s:|r %s", USAGE, path), realOptions.cmdName or realOptions.name or self) - print(tostring(options.desc)) - elseif options == realOptions and (self.description or self.notes) then - print(tostring(self.description or self.notes), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s", USAGE, path)) - else - print(string.format("|cffffff7f%s:|r %s", USAGE, path), realOptions.cmdName or realOptions.name or self) - end - print(NO_OPTIONS_AVAILABLE) - end - end -end - -local function handlerFunc(self, chat, msg, options) - if not msg then - msg = "" - else - msg = msg:gsub("^%s*(.-)%s*$", "%1") - msg = msg:gsub("%s+", " ") - end - - local realOptions = options - local options, path, args, handler, passTable, passValue = findTableLevel(self, options, chat, msg) - - local hidden, disabled = options.cmdHidden or options.hidden, options.disabled - if hidden then - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - end - if hidden then - disabled = true - elseif disabled then - if type(disabled) == "function" then - disabled = disabled() - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - disabled = handler[f](handler) - if neg then - disabled = not disabled - end - end - end - local _G_this = this - local kind = (options.type or "group"):lower() - if disabled then - print(string.format(OPTION_IS_DISABLED, path), realOptions.cmdName or realOptions.name or self) - elseif kind == "text" then - if #args > 0 then - if (type(options.validate) == "table" and #args > 1) or (type(options.validate) ~= "table" and not options.input) then - local arg = table.concat(args, " ") - for k,v in pairs(args) do - args[k] = nil - end - args[1] = arg - end - if options.validate then - local good - if type(options.validate) == "function" then - good = options.validate(unpack(args)) - elseif type(options.validate) == "table" then - local arg = args[1] - arg = tostring(arg):lower() - for k,v in pairs(options.validate) do - if v:lower() == arg then - args[1] = type(k) == "string" and k or v - good = true - break - end - end - if not good and type((next(options.validate))) == "string" then - for k,v in pairs(options.validate) do - if type(k) == "string" and k:lower() == arg then - args[1] = k - good = true - break - end - end - end - elseif options.validate == "keybinding" then - good = keybindingValidateFunc(unpack(args)) - if good ~= false then - args[1] = good - end - else - if type(handler[options.validate]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.validate)) - end - good = handler[options.validate](handler, unpack(args)) - end - if not good then - local usage - if type(options.validate) == "table" then - if not order then - order = {} - end - for k,v in pairs(options.validate) do - table.insert(order, v) - end - usage = "{" .. table.concat(order, " || ") .. "}" - for k in pairs(order) do - order[k] = nil - end - elseif options.validate == "keybinding" then - usage = KEYBINDING_USAGE - else - usage = options.usage or "<value>" - end - print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, tostring(table.concat(args, " ")), path), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage)) - return - end - end - - local var - if passTable then - if not passTable.get then - elseif type(passTable.get) == "function" then - var = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if not options.get then - elseif type(options.get) == "function" then - var = options.get() - else - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - - if var ~= args[1] then - if passTable then - if type(passTable.set) == "function" then - passTable.set(passValue, unpack(args)) - else - if type(handler[passTable.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) - end - handler[passTable.set](handler, passTable.set, unpack(args)) - end - else - if type(options.set) == "function" then - options.set(unpack(args)) - else - if type(handler[options.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) - end - handler[options.set](handler, unpack(args)) - end - end - end - end - - if #args > 0 then - local var - if passTable then - if not passTable.get then - elseif type(passTable.get) == "function" then - var = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if not options.get then - elseif type(options.get) == "function" then - var = options.get() - else - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - if type(options.validate) == "table" then - var = options.validate[var] or var - end - if (passTable and passTable.get) or options.get then - print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) - end - if var == args[1] then - return - end - else - printUsage(self, handler, realOptions, options, path, args) - return - end - elseif kind == "execute" then - if passTable then - if type(passFunc) == "function" then - set(passValue) - else - if type(handler[passFunc]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passFunc)) - end - handler[passFunc](handler, passValue) - end - else - local ret, msg - if type(options.func) == "function" then - options.func() - else - local handler = options.handler or self - if type(handler[options.func]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.func)) - end - handler[options.func](handler) - end - end - elseif kind == "toggle" then - local var - if passTable then - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - local f = passTable.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - var = handler[f](handler, passValue) - if neg then - var = not var - end - end - if type(passTable.set) == "function" then - passTable.set(passValue, not var) - else - if type(handler[passTable.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) - end - handler[passTable.set](handler, passValue, not var) - end - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - local f = passTable.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - var = handler[f](handler, passValue) - if neg then - var = not var - end - end - else - local handler = options.handler or self - if type(options.get) == "function" then - var = options.get() - else - local f = options.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if type(handler[f]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, f)) - end - var = handler[f](handler) - if neg then - var = not var - end - end - if type(options.set) == "function" then - options.set(not var) - else - if type(handler[options.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) - end - handler[options.set](handler, not var) - end - if type(options.get) == "function" then - var = options.get() - else - local f = options.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - var = handler[f](handler) - if neg then - var = not var - end - end - end - - print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), (options.map or MAP_ONOFF)[var and true or false] or NONE), realOptions.cmdName or realOptions.name or self) - elseif kind == "range" then - local arg - if #args <= 1 then - arg = args[1] - else - arg = table.concat(args, " ") - end - - if arg then - local min = options.min or 0 - local max = options.max or 1 - local good = false - if type(arg) == "number" then - if options.isPercent then - arg = arg / 100 - end - - if arg >= min and arg <= max then - good = true - end - - if good and type(options.step) == "number" and options.step > 0 then - local step = options.step - arg = math.floor((arg - min) / step + 0.5) * step + min - if arg > max then - arg = max - elseif arg < min then - arg = min - end - end - end - if not good then - local usage - local min = options.min or 0 - local max = options.max or 1 - if options.isPercent then - min, max = min * 100, max * 100 - end - local bit = "-" - if min < 0 or max < 0 then - bit = " - " - end - usage = string.format("(%s%s%s)", min, bit, max) - print(string.format(options.error or IS_NOT_A_VALID_VALUE_FOR, tostring(arg), path), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s %s", USAGE, path, usage)) - return - end - - local var - if passTable then - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - var = options.get() - else - local handler = options.handler or self - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - - if var ~= arg then - if passTable then - if type(passTable.set) == "function" then - passTable.set(passValue, arg) - else - if type(handler[passTable.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) - end - handler[passTable.set](handler, passValue, arg) - end - else - if type(options.set) == "function" then - options.set(arg) - else - local handler = options.handler or self - if type(handler[options.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) - end - handler[options.set](handler, arg) - end - end - end - end - - if arg then - local var - if passTable then - if type(passTable.get) == "function" then - var = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - var = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - var = options.get() - else - local handler = options.handler or self - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - var = handler[options.get](handler) - end - end - - if var and options.isPercent then - var = tostring(var * 100) .. "%" - end - print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), tostring(var or NONE)), realOptions.cmdName or realOptions.name or self) - if var == arg then - return - end - else - printUsage(self, handler, realOptions, options, path, args) - return - end - elseif kind == "color" then - if #args > 0 then - local r,g,b,a - if #args == 1 then - local arg = tostring(args[1]) - if options.hasAlpha then - if arg:len() == 8 and arg:find("^%x*$") then - r,g,b,a = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255, tonumber(arg:sub(7, 8), 16) / 255 - end - else - if arg:len() == 6 and arg:find("^%x*$") then - r,g,b = tonumber(arg:sub(1, 2), 16) / 255, tonumber(arg:sub(3, 4), 16) / 255, tonumber(arg:sub(5, 6), 16) / 255 - end - end - elseif #args == 4 and options.hasAlpha then - local a1,a2,a3,a4 = args[1], args[2], args[3], args[4] - if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and type(a4) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 and a4 <= 1 then - r,g,b,a = a1,a2,a3,a4 - elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") and (type(a4) == "number" or a4:len() == 2) and a4:find("^%x*$") then - r,g,b,a = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255, tonumber(a4, 16) / 255 - end - elseif #args == 3 and not options.hasAlpha then - local a1,a2,a3 = args[1], args[2], args[3] - if type(a1) == "number" and type(a2) == "number" and type(a3) == "number" and a1 <= 1 and a2 <= 1 and a3 <= 1 then - r,g,b = a1,a2,a3 - elseif (type(a1) == "number" or a1:len() == 2) and a1:find("^%x*$") and (type(a2) == "number" or a2:len() == 2) and a2:find("^%x*$") and (type(a3) == "number" or a3:len() == 2) and a3:find("^%x*$") then - r,g,b = tonumber(a1, 16) / 255, tonumber(a2, 16) / 255, tonumber(a3, 16) / 255 - end - end - if not r then - print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, table.concat(args, ' '), path), realOptions.cmdName or realOptions.name or self) - print(string.format("|cffffff7f%s:|r %s {0-1} {0-1} {0-1}%s", USAGE, path, options.hasAlpha and " {0-1}" or "")) - return - end - if passTable then - if type(passTable.set) == "function" then - passTable.set(passValue, r,g,b,a) - else - if type(handler[passTable.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.set)) - end - handler[passTable.set](handler, passValue, r,g,b,a) - end - else - if type(options.set) == "function" then - options.set(r,g,b,a) - else - if type(handler[options.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.set)) - end - handler[options.set](handler, r,g,b,a) - end - end - - local r,g,b,a - if passTable then - if type(passTable.get) == "function" then - r,g,b,a = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - r,g,b,a = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - r,g,b,a = options.get() - else - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - r,g,b,a = handler[options.get](handler) - end - end - - local s - if type(r) == "number" and type(g) == "number" and type(b) == "number" then - if options.hasAlpha and type(a) == "number" then - s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) - else - s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", r*255, g*255, b*255, r*255, g*255, b*255) - end - else - s = NONE - end - print(string.format(options.message or IS_NOW_SET_TO, tostring(options.cmdName or options.name), s), realOptions.cmdName or realOptions.name or self) - else - local r,g,b,a - if passTable then - if type(passTable.get) == "function" then - r,g,b,a = passTable.get(passValue) - else - if type(handler[passTable.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, passTable.get)) - end - r,g,b,a = handler[passTable.get](handler, passValue) - end - else - if type(options.get) == "function" then - r,g,b,a = options.get() - else - if type(handler[options.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, options.get)) - end - r,g,b,a = handler[options.get](handler) - end - end - - if not colorTable then - colorTable = {} - local t = colorTable - - if ColorPickerOkayButton then - local ColorPickerOkayButton_OnClick = ColorPickerOkayButton:GetScript("OnClick") - ColorPickerOkayButton:SetScript("OnClick", function() - if ColorPickerOkayButton_OnClick then - ColorPickerOkayButton_OnClick() - end - if t.active then - ColorPickerFrame.cancelFunc = nil - ColorPickerFrame.func = nil - ColorPickerFrame.opacityFunc = nil - local r,g,b,a - if t.passValue then - if type(t.get) == "function" then - r,g,b,a = t.get(t.passValue) - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) - end - r,g,b,a = t.handler[t.get](t.handler, t.passValue) - end - else - if type(t.get) == "function" then - r,g,b,a = t.get() - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) - end - r,g,b,a = t.handler[t.get](t.handler) - end - end - if r ~= t.r or g ~= t.g or b ~= t.b or (t.hasAlpha and a ~= t.a) then - local s - if type(r) == "number" and type(g) == "number" and type(b) == "number" then - if t.hasAlpha and type(a) == "number" then - s = string.format("|c%02x%02x%02x%02x%02x%02x%02x%02x|r", a*255, r*255, g*255, b*255, r*255, g*255, b*255, a*255) - else - s = string.format("|cff%02x%02x%02x%02x%02x%02x|r", r*255, g*255, b*255, r*255, g*255, b*255) - end - else - s = NONE - end - print(string.format(t.message, tostring(t.name), s), t.realOptions.cmdName or t.realOptions.name or self) - end - for k,v in pairs(t) do - t[k] = nil - end - end - end) - end - else - for k,v in pairs(colorTable) do - colorTable[k] = nil - end - end - - if type(r) ~= "number" or type(g) ~= "number" or type(b) ~= "number" then - r,g,b = 1, 1, 1 - end - if type(a) ~= "number" then - a = 1 - end - local t = colorTable - t.r = r - t.g = g - t.b = b - if hasAlpha then - t.a = a - end - t.realOptions = realOptions - t.hasAlpha = options.hasAlpha - t.handler = handler - t.set = passTable and passTable.set or options.set - t.get = passTable and passTable.get or options.get - t.name = options.cmdName or options.name - t.message = options.message or IS_NOW_SET_TO - t.passValue = passValue - t.active = true - - if not colorFunc then - colorFunc = function() - local r,g,b = ColorPickerFrame:GetColorRGB() - if t.hasAlpha then - local a = 1 - OpacitySliderFrame:GetValue() - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, r,g,b,a) - else - t.set(r,g,b,a) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, r,g,b,a) - else - t.handler[t.set](t.handler, r,g,b,a) - end - end - else - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, r,g,b) - else - t.set(r,g,b) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, r,g,b) - else - t.handler[t.set](t.handler, r,g,b) - end - end - end - end - end - - ColorPickerFrame.func = colorFunc - ColorPickerFrame.hasOpacity = options.hasAlpha - if options.hasAlpha then - ColorPickerFrame.opacityFunc = ColorPickerFrame.func - ColorPickerFrame.opacity = 1 - a - end - ColorPickerFrame:SetColorRGB(r,g,b) - - if not colorCancelFunc then - colorCancelFunc = function() - if t.hasAlpha then - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, t.r,t.g,t.b,t.a) - else - t.set(t.r,t.g,t.b,t.a) - end - else - if type(t.handler[t.get]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.get)) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b,t.a) - else - t.handler[t.set](t.handler, t.r,t.g,t.b,t.a) - end - end - else - if type(t.set) == "function" then - if t.passValue then - t.set(t.passValue, t.r,t.g,t.b) - else - t.set(t.r,t.g,t.b) - end - else - if type(t.handler[t.set]) ~= "function" then - AceConsole:error("%s: %s", handler, string.format(OPTION_HANDLER_NOT_FOUND, t.set)) - end - if t.passValue then - t.handler[t.set](t.handler, t.passValue, t.r,t.g,t.b) - else - t.handler[t.set](t.handler, t.r,t.g,t.b) - end - end - end - for k,v in pairs(t) do - t[k] = nil - end - ColorPickerFrame.cancelFunc = nil - ColorPickerFrame.func = nil - ColorPickerFrame.opacityFunc = nil - end - end - - ColorPickerFrame.cancelFunc = colorCancelFunc - - ShowUIPanel(ColorPickerFrame) - end - return - elseif kind == "group" then - if #args == 0 then - printUsage(self, handler, realOptions, options, path, args) - else - -- invalid argument - print(string.format(options.error or IS_NOT_A_VALID_OPTION_FOR, args[1], path), realOptions.cmdName or realOptions.name or self) - end - return - end - this = _G_this - if Dewdrop then - Dewdrop:Refresh(1) - Dewdrop:Refresh(2) - Dewdrop:Refresh(3) - Dewdrop:Refresh(4) - Dewdrop:Refresh(5) - end -end - -local external -function AceConsole:RegisterChatCommand(slashCommands, options, name) - if type(slashCommands) ~= "table" and slashCommands ~= false then - AceConsole:error("Bad argument #2 to `RegisterChatCommand' (expected table, got %s)", type(slashCommands)) - end - if not slashCommands and type(name) ~= "string" then - AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string, got %s)", type(name)) - end - if type(options) ~= "table" and type(options) ~= "function" and options ~= nil then - AceConsole:error("Bad argument #3 to `RegisterChatCommand' (expected table, function, or nil, got %s)", type(options)) - end - if name then - if type(name) ~= "string" then - AceConsole:error("Bad argument #4 to `RegisterChatCommand' (expected string or nil, got %s)", type(name)) - elseif not name:find("^%w+$") or name:upper() ~= name or name:len() == 0 then - AceConsole:error("Argument #4 must be an uppercase, letters-only string with at least 1 character") - end - end - if slashCommands then - if #slashCommands == 0 then - AceConsole:error("Argument #2 to `RegisterChatCommand' must include at least one string") - end - - for k,v in pairs(slashCommands) do - if type(k) ~= "number" then - AceConsole:error("All keys in argument #2 to `RegisterChatCommand' must be numbers") - end - if type(v) ~= "string" then - AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be strings") - elseif not v:find("^/[A-Za-z][A-Za-z0-9_]*$") then - AceConsole:error("All values in argument #2 to `RegisterChatCommand' must be in the form of \"/word\"") - end - end - end - - if not options then - options = { - type = 'group', - args = {}, - handler = self - } - end - - if type(options) == "table" then - local err, position = validateOptions(options) - if err then - if position then - AceConsole:error(position .. ": " .. err) - else - AceConsole:error(err) - end - end - - if not options.handler then - options.handler = self - end - - if options.handler == self and options.type:lower() == "group" and self.class then - AceConsole:InjectAceOptionsTable(self, options) - end - end - - local chat - if slashCommands then - chat = slashCommands[1] - else - chat = _G["SLASH_"..name..1] - end - - local handler - if type(options) == "function" then - handler = options - for k,v in pairs(_G) do - if handler == v then - local k = k - handler = function(msg) - return _G[k](msg) - end - end - end - else - function handler(msg) - handlerFunc(self, chat, msg, options) - end - end - - if not _G.SlashCmdList then - _G.SlashCmdList = {} - end - - if not name then - local A = ('A'):byte() - repeat - name = string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) .. string.char(math.random(26) + A - 1) - until not _G.SlashCmdList[name] - end - - if slashCommands then - if _G.SlashCmdList[name] then - local i = 0 - while true do - i = i + 1 - if _G["SLASH_"..name..i] then - _G["SLASH_"..name..i] = nil - else - break - end - end - end - - local i = 0 - for _,command in ipairs(slashCommands) do - i = i + 1 - _G["SLASH_"..name..i] = command - if command:lower() ~= command then - i = i + 1 - _G["SLASH_"..name..i] = command:lower() - end - end - end - _G.SlashCmdList[name] = handler - if self ~= AceConsole and self.slashCommand == nil then - self.slashCommand = chat - end - - if not AceEvent and AceLibrary:HasInstance("AceEvent-2.0") then - external(AceConsole, "AceEvent-2.0", AceLibrary("AceEvent-2.0")) - end - if AceEvent then - if not AceConsole.nextAddon then - AceConsole.nextAddon = {} - end - if type(options) == "table" then - AceConsole.nextAddon[self] = options - if not self.playerLogin then - AceConsole:RegisterEvent("PLAYER_LOGIN", "PLAYER_LOGIN", true) - end - end - end - - AceConsole.registry[name] = options -end - -function AceConsole:InjectAceOptionsTable(handler, options) - self:argCheck(handler, 2, "table") - self:argCheck(options, 3, "table") - if options.type:lower() ~= "group" then - self:error('Cannot inject into options table argument #3 if its type is not "group"') - end - if options.handler ~= nil and options.handler ~= handler then - self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") - end - options.handler = handler - local class = handler.class - if not class then - self:error("Cannot retrieve AceOptions tables from a non-object argument #2") - end - while class and class ~= AceOO.Class do - if type(class.GetAceOptionsDataTable) == "function" then - local t = class:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - local mixins = class.mixins - if mixins then - for mixin in pairs(mixins) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - class = class.super - end - return options -end - -function AceConsole:PLAYER_LOGIN() - self.playerLogin = true - for addon, options in pairs(self.nextAddon) do - local err, position = validateOptionsMethods(addon, options) - if err then - if position then - geterrorhandler()(tostring(addon) .. ": AceConsole: " .. position .. ": " .. err) - else - geterrorhandler()(tostring(addon) .. ": AceConsole: " .. err) - end - end - self.nextAddon[addon] = nil - end -end - -function AceConsole:TabCompleteInfo(cmdpath) - local cmd = cmdpath:match("(/%S+)") - if not cmd then - return - end - local path = cmdpath:sub(cmd:len() + 2) - for name in pairs(SlashCmdList) do --global - if AceConsole.registry[name] then - local i = 0 - while true do - i = i + 1 - local scmd = _G["SLASH_"..name..i] - if not scmd then break end - if cmd == scmd then - return name, cmd, path - end - end - end - end -end - -function external(self, major, instance) - if major == "AceEvent-2.0" then - if not AceEvent then - AceEvent = instance - - AceEvent:embed(self) - end - elseif major == "AceTab-2.0" then - instance:RegisterTabCompletion("AceConsole", "%/.*", function(t, cmdpath, pos) - local ac = AceLibrary("AceConsole-2.0") - local name, cmd, path = ac:TabCompleteInfo(cmdpath:sub(1, pos)) - - if not ac.registry[name] then - return false - else - local validArgs = findTableLevel(ac, ac.registry[name], cmd, path or "") - if validArgs.args then - for arg in pairs(validArgs.args) do - table.insert(t, arg) - end - end - end - end, function(u, matches, gcs, cmdpath) - local ac = AceLibrary("AceConsole-2.0") - local name, cmd, path = ac:TabCompleteInfo(cmdpath) - if ac.registry[name] then - local validArgs, path2, argwork = findTableLevel(ac, ac.registry[name], cmd, path) - printUsage(ac, validArgs.handler, ac.registry[name], validArgs, path2, argwork, not gcs or gcs ~= "", gcs) - end - end) - elseif major == "Dewdrop-2.0" then - Dewdrop = instance - end -end - -local function activate(self, oldLib, oldDeactivate) - AceConsole = self - - if oldLib then - self.registry = oldLib.registry - self.nextAddon = oldLib.nextAddon - end - - if not self.registry then - self.registry = {} - else - for name,options in pairs(self.registry) do - self:RegisterChatCommand(false, options, name) - end - end - - self:RegisterChatCommand({ "/reload", "/rl", "/reloadui" }, ReloadUI, "RELOAD") - - self:RegisterChatCommand({ "/print" }, function(text) - local f, err = loadstring("AceLibrary('AceConsole-2.0'):PrintComma(" .. text .. ")") - if not f then - self:Print("|cffff0000Error:|r", err) - else - f() - end - end, "PRINT") - - self:activate(oldLib, oldDeactivate) - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceConsole, MAJOR_VERSION, MINOR_VERSION, activate, nil, external)
--- a/libs/AceDB-2.0/AceDB-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1665 +0,0 @@ ---[[ -Name: AceDB-2.0 -Revision: $Rev: 18708 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceDB-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceDB-2.0 -Description: Mixin to allow for fast, clean, and featureful saved variable - access. -Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0 -]] - -local MAJOR_VERSION = "AceDB-2.0" -local MINOR_VERSION = "$Revision: 18708 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err) end -end - -local ACTIVE, ENABLED, STATE, TOGGLE_ACTIVE, MAP_ACTIVESUSPENDED, SET_PROFILE, SET_PROFILE_USAGE, PROFILE, PLAYER_OF_REALM, CHOOSE_PROFILE_DESC, CHOOSE_PROFILE_GUI, COPY_PROFILE_DESC, COPY_PROFILE_GUI, OTHER_PROFILE_DESC, OTHER_PROFILE_GUI, OTHER_PROFILE_USAGE, CHARACTER_COLON, REALM_COLON, CLASS_COLON, DEFAULT, ALTERNATIVE - -if GetLocale() == "deDE" then - ACTIVE = "Aktiv" - ENABLED = "Aktiviert" - STATE = "Status" - TOGGLE_ACTIVE = "Stoppt/Aktiviert dieses Addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Aktiv|r", [false] = "|cffff0000Gestoppt|r" } - SET_PROFILE = "Setzt das Profil f\195\188r dieses Addon." - SET_PROFILE_USAGE = "{Charakter || Klasse || Realm || <Profilname>}" - PROFILE = "Profil" - PLAYER_OF_REALM = "%s von %s" - CHOOSE_PROFILE_DESC = "W\195\164hle ein Profil." - CHOOSE_PROFILE_GUI = "W\195\164hle" - COPY_PROFILE_DESC = "Kopiert Einstellungen von einem anderem Profil." - COPY_PROFILE_GUI = "Kopiere von" - OTHER_PROFILE_DESC = "W\195\164hle ein anderes Profil." - OTHER_PROFILE_GUI = "Anderes" - OTHER_PROFILE_USAGE = "<Profilname>" - - CHARACTER_COLON = "Charakter: " - REALM_COLON = "Realm: " - CLASS_COLON = "Klasse: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "frFR" then - ACTIVE = "Actif" - ENABLED = "Activ\195\169" - STATE = "Etat" - TOGGLE_ACTIVE = "Suspend/active cet addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Actif|r", [false] = "|cffff0000Suspendu|r" } - SET_PROFILE = "S\195\169lectionne le profil pour cet addon." - SET_PROFILE_USAGE = "{perso || classe || royaume || <nom de profil>}" - PROFILE = "Profil" - PLAYER_OF_REALM = "%s de %s" - CHOOSE_PROFILE_DESC = "Choisissez un profil." - CHOOSE_PROFILE_GUI = "Choix" - COPY_PROFILE_DESC = "Copier les param\195\168tres d'un autre profil." - COPY_PROFILE_GUI = "Copier \195\160 partir de" - OTHER_PROFILE_DESC = "Choisissez un autre profil." - OTHER_PROFILE_GUI = "Autre" - OTHER_PROFILE_USAGE = "<nom de profil>" - - CHARACTER_COLON = "Personnage: " - REALM_COLON = "Royaume: " - CLASS_COLON = "Classe: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "koKR" then - ACTIVE = "활성화" - ENABLED = "활성화" - STATE = "상태" - TOGGLE_ACTIVE = "이 애드온 중지/계속 실행" - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00활성화|r", [false] = "|cffff0000중지됨|r" } - SET_PROFILE = "이 애드온에 프로필 설정" - SET_PROFILE_USAGE = "{캐릭터명 || 직업 || 서버명 || <프로필명>}" - PROFILE = "프로필" - PLAYER_OF_REALM = "%s (%s 서버)" - CHOOSE_PROFILE_DESC = "프로파일을 선택합니다." - CHOOSE_PROFILE_GUI = "선택" - COPY_PROFILE_DESC = "다른 프로파일에서 설정을 복사합니다." - COPY_PROFILE_GUI = "복사" - OTHER_PROFILE_DESC = "다른 프로파일을 선택합니다." - OTHER_PROFILE_GUI = "기타" - OTHER_PROFILE_USAGE = "<프로파일명>" - - CHARACTER_COLON = "캐릭터: " - REALM_COLON = "서버: " - CLASS_COLON = "직업: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "zhTW" then - ACTIVE = "啟動" - ENABLED = "啟用" - STATE = "狀態" - TOGGLE_ACTIVE = "暫停/重啟這個插件。" - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00啟動|r", [false] = "|cffff0000已暫停|r" } - SET_PROFILE = "設定這插件的記錄檔。" - SET_PROFILE_USAGE = "{角色 || 聯業 || 伺服器 || <記錄檔名稱>}" - PROFILE = "記錄檔" - PLAYER_OF_REALM = "%s 於 %s" - CHOOSE_PROFILE_DESC = "選擇一個記錄檔" - CHOOSE_PROFILE_GUI = "選擇" - COPY_PROFILE_DESC = "由其他記錄檔複製設定。" - COPY_PROFILE_GUI = "複製由" - OTHER_PROFILE_DESC = "選擇其他記錄檔。" - OTHER_PROFILE_GUI = "其他" - OTHER_PROFILE_USAGE = "<記錄檔名稱>" - - CHARACTER_COLON = "角色:" - REALM_COLON = "伺服器:" - CLASS_COLON = "聯業:" - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -elseif GetLocale() == "zhCN" then - ACTIVE = "\230\156\137\230\149\136" - ENABLED = "\229\144\175\231\148\168" - STATE = "\231\138\182\230\128\129" - TOGGLE_ACTIVE = "\230\154\130\229\129\156/\230\129\162\229\164\141 \230\173\164\230\143\146\228\187\182." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00\230\156\137\230\149\136|r", [false] = "|cffff0000\230\154\130\229\129\156|r" } - SET_PROFILE = "\232\174\190\231\189\174\233\133\141\231\189\174\230\150\135\228\187\182\228\184\186\232\191\153\230\143\146\228\187\182." - SET_PROFILE_USAGE = "{\229\173\151\231\172\166 || \233\128\137\228\187\182\231\177\187 || \229\159\159 || <\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>}" - PROFILE = "\233\133\141\231\189\174\230\150\135\228\187\182" - PLAYER_OF_REALM = "%s \231\154\132 %s" - CHOOSE_PROFILE_DESC = "\233\128\137\230\139\169\233\133\141\231\189\174\230\150\135\228\187\182." - CHOOSE_PROFILE_GUI = "\233\128\137\230\139\169" - COPY_PROFILE_DESC = "\229\164\141\229\136\182\232\174\190\231\189\174\228\187\142\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." - COPY_PROFILE_GUI = "\229\164\141\229\136\182\228\187\142" - OTHER_PROFILE_DESC = "\233\128\137\230\139\169\229\143\166\228\184\128\228\184\170\233\133\141\231\189\174\230\150\135\228\187\182." - OTHER_PROFILE_GUI = "\229\133\182\228\187\150" - OTHER_PROFILE_USAGE = "<\233\133\141\231\189\174\230\150\135\228\187\182\229\144\141\229\173\151>" - - CHARACTER_COLON = "\229\173\151\231\172\166: " - REALM_COLON = "\229\159\159: " - CLASS_COLON = "\233\128\137\228\187\182\231\177\187: " - - DEFAULT = "Default" -- fix - ALTERNATIVE = "Alternative" -- fix -else -- enUS - ACTIVE = "Active" - ENABLED = "Enabled" - STATE = "State" - TOGGLE_ACTIVE = "Suspend/resume this addon." - MAP_ACTIVESUSPENDED = { [true] = "|cff00ff00Active|r", [false] = "|cffff0000Suspended|r" } - SET_PROFILE = "Set profile for this addon." - SET_PROFILE_USAGE = "{char || class || realm || <profile name>}" - PROFILE = "Profile" - PLAYER_OF_REALM = "%s of %s" - CHOOSE_PROFILE_DESC = "Choose a profile." - CHOOSE_PROFILE_GUI = "Choose" - COPY_PROFILE_DESC = "Copy settings from another profile." - COPY_PROFILE_GUI = "Copy from" - OTHER_PROFILE_DESC = "Choose another profile." - OTHER_PROFILE_GUI = "Other" - OTHER_PROFILE_USAGE = "<profile name>" - - CHARACTER_COLON = "Character: " - REALM_COLON = "Realm: " - CLASS_COLON = "Class: " - - DEFAULT = "Default" - ALTERNATIVE = "Alternative" -end - -local AceOO = AceLibrary("AceOO-2.0") -local AceEvent -local Mixin = AceOO.Mixin -local AceDB = Mixin { - "RegisterDB", - "RegisterDefaults", - "ResetDB", - "SetProfile", - "GetProfile", - "CopyProfileFrom", - "ToggleActive", - "IsActive", - "AcquireDBNamespace", - } -local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0") - -local _G = getfenv(0) - -local function inheritDefaults(t, defaults) - if not defaults then - return t - end - for k,v in pairs(defaults) do - if k == "*" then - local v = v - if type(v) == "table" then - setmetatable(t, { - __index = function(self, key) - if key == nil then - return nil - end - self[key] = {} - inheritDefaults(self[key], v) - return self[key] - end - } ) - else - setmetatable(t, { - __index = function(self, key) - if key == nil then - return nil - end - self[key] = v - return self[key] - end - } ) - end - for key in pairs(t) do - if (defaults[key] == nil or key == "*") and type(t[key]) == "table" then - inheritDefaults(t[key], v) - end - end - else - if type(v) == "table" then - if type(t[k]) ~= "table" then - t[k] = {} - end - inheritDefaults(t[k], v) - elseif t[k] == nil then - t[k] = v - end - end - end - return t -end - -local _,race = UnitRace("player") -local faction -if race == "Orc" or race == "Scourge" or race == "Troll" or race == "Tauren" or race == "BloodElf" then - faction = FACTION_HORDE -else - faction = FACTION_ALLIANCE -end -local charID = string.format(PLAYER_OF_REALM, UnitName("player"), (string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1"))) -local realm = string.gsub(GetRealmName(), "^%s*(.-)%s*$", "%1") -local realmID = realm .. " - " .. faction -local classID = UnitClass("player") - -AceDB.CHAR_ID = charID -AceDB.REALM_ID = realmID -AceDB.CLASS_ID = classID - -AceDB.FACTION = faction -AceDB.REALM = realm -AceDB.NAME = UnitName("player") - -local new, del -do - local list = setmetatable({}, {__mode="k"}) - function new() - local t = next(list) - if t then - list[t] = nil - return t - else - return {} - end - end - - function del(t) - setmetatable(t, nil) - for k in pairs(t) do - t[k] = nil - end - list[t] = true - end -end - -local caseInsensitive_mt = { - __index = function(self, key) - if type(key) ~= "string" then - return nil - end - local lowerKey = string.lower(key) - for k,v in pairs(self) do - if string.lower(k) == lowerKey then - return self[k] - end - end - end, - __newindex = function(self, key, value) - if type(key) ~= "string" then - return error("table index is nil", 2) - end - local lowerKey = string.lower(key) - for k in pairs(self) do - if string.lower(k) == lowerKey then - rawset(self, k, nil) - rawset(self, key, value) - return - end - end - rawset(self, key, value) - end -} - -local db_mt = { __index = function(db, key) - if key == "char" then - if db.charName then - if type(_G[db.charName]) ~= "table" then - _G[db.charName] = {} - end - if type(_G[db.charName].global) ~= "table" then - _G[db.charName].global = {} - end - rawset(db, 'char', _G[db.charName].global) - else - if type(db.raw.chars) ~= "table" then - db.raw.chars = {} - end - local id = charID - if type(db.raw.chars[id]) ~= "table" then - db.raw.chars[id] = {} - end - rawset(db, 'char', db.raw.chars[id]) - end - if db.defaults and db.defaults.char then - inheritDefaults(db.char, db.defaults.char) - end - return db.char - elseif key == "realm" then - if type(db.raw.realms) ~= "table" then - db.raw.realms = {} - end - local id = realmID - if type(db.raw.realms[id]) ~= "table" then - db.raw.realms[id] = {} - end - rawset(db, 'realm', db.raw.realms[id]) - if db.defaults and db.defaults.realm then - inheritDefaults(db.realm, db.defaults.realm) - end - return db.realm - elseif key == "account" then - if type(db.raw.account) ~= "table" then - db.raw.account = {} - end - rawset(db, 'account', db.raw.account) - if db.defaults and db.defaults.account then - inheritDefaults(db.account, db.defaults.account) - end - return db.account - elseif key == "faction" then - if type(db.raw.factions) ~= "table" then - db.raw.factions = {} - end - local id = faction - if type(db.raw.factions[id]) ~= "table" then - db.raw.factions[id] = {} - end - rawset(db, 'faction', db.raw.factions[id]) - if db.defaults and db.defaults.faction then - inheritDefaults(db.faction, db.defaults.faction) - end - return db.faction - elseif key == "class" then - if type(db.raw.classes) ~= "table" then - db.raw.classes = {} - end - local id = classID - if type(db.raw.classes[id]) ~= "table" then - db.raw.classes[id] = {} - end - rawset(db, 'class', db.raw.classes[id]) - if db.defaults and db.defaults.class then - inheritDefaults(db.class, db.defaults.class) - end - return db.class - elseif key == "profile" then - if type(db.raw.profiles) ~= "table" then - db.raw.profiles = setmetatable({}, caseInsensitive_mt) - else - setmetatable(db.raw.profiles, caseInsensitive_mt) - end - local id = db.raw.currentProfile[charID] - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - if type(db.raw.profiles[id]) ~= "table" then - db.raw.profiles[id] = {} - end - rawset(db, 'profile', db.raw.profiles[id]) - if db.defaults and db.defaults.profile then - inheritDefaults(db.profile, db.defaults.profile) - end - return db.profile - elseif key == "raw" or key == "defaults" or key == "name" or key == "charName" or key == "namespaces" then - return nil - end - error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) -end, __newindex = function(db, key, value) - error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) -end } - -local function RecalculateAceDBCopyFromList(target) - local db = target.db - local t = target['acedb-profile-copylist'] - for k,v in pairs(t) do - t[k] = nil - end - local _,currentProfile = AceDB.GetProfile(target) - if db and db.raw then - if db.raw.profiles then - for k in pairs(db.raw.profiles) do - if currentProfile ~= k then - if string.find(k, '^char/') then - local name = string.sub(k, 6) - t[k] = CHARACTER_COLON .. name - elseif string.find(k, '^realm/') then - local name = string.sub(k, 7) - t[k] = REALM_COLON .. name - elseif string.find(k, '^class/') then - local name = string.sub(k, 7) - t[k] = CLASS_COLON .. name - else - t[k] = k - end - end - end - end - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles then - for k in pairs(n.profiles) do - if currentProfile ~= k then - if string.find(k, '^char/') then - local name = string.sub(k, 6) - t[k] = CHARACTER_COLON .. name - elseif string.find(k, '^realm/') then - local name = string.sub(k, 7) - t[k] = REALM_COLON .. name - elseif string.find(k, '^class/') then - local name = string.sub(k, 7) - t[k] = CLASS_COLON .. name - else - t[k] = k - end - end - end - end - end - end - end - if t.Default then - t.Default = DEFAULT - end - if t.Alternative then - t.Alternative = ALTERNATIVE - end -end - -local function RecalculateAceDBProfileList(target) - local t = target['acedb-profile-list'] - for k,v in pairs(t) do - t[k] = nil - end - t.char = CHARACTER_COLON .. charID - t.realm = REALM_COLON .. realmID - t.class = CLASS_COLON .. classID - t.Default = DEFAULT - local db = target.db - if db and db.raw then - if db.raw.profiles then - for k in pairs(db.raw.profiles) do - if not string.find(k, '^char/') and not string.find(k, '^realm/') and not string.find(k, '^class/') then - t[k] = k - end - end - end - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles then - for k in pairs(n.profiles) do - if not string.find(k, '^char/') and not string.find(k, '^realm/') and not string.find(k, '^class/') then - t[k] = k - end - end - end - end - end - local curr = db.raw.currentProfile and db.raw.currentProfile[charID] - if curr then - t[curr] = curr - end - end - if t.Alternative then - t.Alternative = ALTERNATIVE - end -end - -local CrawlForSerialization -local CrawlForDeserialization - -local function SerializeObject(o) - local t = { o:Serialize() } - CrawlForSerialization(t) - t[0] = o.class:GetLibraryVersion() - return t -end - -local function DeserializeObject(t) - CrawlForDeserialization(t) - local className = t[0] - t[0] = nil - return AceLibrary(className):Deserialize(unpack(t)) -end - -local function IsSerializable(t) - return AceOO.inherits(t, AceOO.Class) and t.class and type(t.class.Deserialize) == "function" and type(t.Serialize) == "function" and type(t.class.GetLibraryVersion) == "function" -end - -function CrawlForSerialization(t) - local tmp = new() - for k,v in pairs(t) do - tmp[k] = v - end - for k,v in pairs(tmp) do - if type(v) == "table" and type(v[0]) ~= "userdata" then - if IsSerializable(v) then - v = SerializeObject(v) - t[k] = v - else - CrawlForSerialization(v) - end - end - if type(k) == "table" and type(k[0]) ~= "userdata" then - if IsSerializable(k) then - t[k] = nil - t[SerializeObject(k)] = v - else - CrawlForSerialization(k) - end - end - tmp[k] = nil - k = nil - end - tmp = del(tmp) -end - -local function IsDeserializable(t) - return type(t[0]) == "string" and AceLibrary:HasInstance(t[0]) -end - -function CrawlForDeserialization(t) - local tmp = new() - for k,v in pairs(t) do - tmp[k] = v - end - for k,v in pairs(tmp) do - if type(v) == "table" then - if IsDeserializable(v) then - t[k] = DeserializeObject(v) - del(v) - v = t[k] - elseif type(v[0]) ~= "userdata" then - CrawlForDeserialization(v) - end - end - if type(k) == "table" then - if IsDeserializable(k) then - t[k] = nil - t[DeserializeObject(k)] = v - del(k) - elseif type(k[0]) ~= "userdata" then - CrawlForDeserialization(k) - end - end - tmp[k] = nil - k = nil - end - tmp = del(tmp) -end - -local namespace_mt = { __index = function(namespace, key) - local db = namespace.db - local name = namespace.name - if key == "char" then - if db.charName then - if type(_G[db.charName]) ~= "table" then - _G[db.charName] = {} - end - if type(_G[db.charName].namespaces) ~= "table" then - _G[db.charName].namespaces = {} - end - if type(_G[db.charName].namespaces[name]) ~= "table" then - _G[db.charName].namespaces[name] = {} - end - rawset(namespace, 'char', _G[db.charName].namespaces[name]) - else - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].chars) ~= "table" then - db.raw.namespaces[name].chars = {} - end - local id = charID - if type(db.raw.namespaces[name].chars[id]) ~= "table" then - db.raw.namespaces[name].chars[id] = {} - end - rawset(namespace, 'char', db.raw.namespaces[name].chars[id]) - end - if namespace.defaults and namespace.defaults.char then - inheritDefaults(namespace.char, namespace.defaults.char) - end - return namespace.char - elseif key == "realm" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].realms) ~= "table" then - db.raw.namespaces[name].realms = {} - end - local id = realmID - if type(db.raw.namespaces[name].realms[id]) ~= "table" then - db.raw.namespaces[name].realms[id] = {} - end - rawset(namespace, 'realm', db.raw.namespaces[name].realms[id]) - if namespace.defaults and namespace.defaults.realm then - inheritDefaults(namespace.realm, namespace.defaults.realm) - end - return namespace.realm - elseif key == "account" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].account) ~= "table" then - db.raw.namespaces[name].account = {} - end - rawset(namespace, 'account', db.raw.namespaces[name].account) - if namespace.defaults and namespace.defaults.account then - inheritDefaults(namespace.account, namespace.defaults.account) - end - return namespace.account - elseif key == "faction" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].factions) ~= "table" then - db.raw.namespaces[name].factions = {} - end - local id = faction - if type(db.raw.namespaces[name].factions[id]) ~= "table" then - db.raw.namespaces[name].factions[id] = {} - end - rawset(namespace, 'faction', db.raw.namespaces[name].factions[id]) - if namespace.defaults and namespace.defaults.faction then - inheritDefaults(namespace.faction, namespace.defaults.faction) - end - return namespace.faction - elseif key == "class" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].classes) ~= "table" then - db.raw.namespaces[name].classes = {} - end - local id = classID - if type(db.raw.namespaces[name].classes[id]) ~= "table" then - db.raw.namespaces[name].classes[id] = {} - end - rawset(namespace, 'class', db.raw.namespaces[name].classes[id]) - if namespace.defaults and namespace.defaults.class then - inheritDefaults(namespace.class, namespace.defaults.class) - end - return namespace.class - elseif key == "profile" then - if type(db.raw.namespaces) ~= "table" then - db.raw.namespaces = {} - end - if type(db.raw.namespaces[name]) ~= "table" then - db.raw.namespaces[name] = {} - end - if type(db.raw.namespaces[name].profiles) ~= "table" then - db.raw.namespaces[name].profiles = setmetatable({}, caseInsensitive_mt) - else - setmetatable(db.raw.namespaces[name].profiles, caseInsensitive_mt) - end - local id = db.raw.currentProfile[charID] - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - if type(db.raw.namespaces[name].profiles[id]) ~= "table" then - db.raw.namespaces[name].profiles[id] = {} - end - rawset(namespace, 'profile', db.raw.namespaces[name].profiles[id]) - if namespace.defaults and namespace.defaults.profile then - inheritDefaults(namespace.profile, namespace.defaults.profile) - end - return namespace.profile - elseif key == "defaults" or key == "name" or key == "db" then - return nil - end - error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) -end, __newindex = function(db, key, value) - error(string.format('Cannot access key %q in db table. You may want to use db.profile[%q]', tostring(key), tostring(key)), 2) -end } - -function AceDB:InitializeDB(addonName) - local db = self.db - - if not db then - if addonName then - AceDB.addonsLoaded[addonName] = true - end - return - end - - if db.raw then - -- someone manually initialized - return - end - - if type(_G[db.name]) ~= "table" then - _G[db.name] = {} - else - CrawlForDeserialization(_G[db.name]) - end - if type(_G[db.charName]) == "table" then - CrawlForDeserialization(_G[db.charName]) - end - rawset(db, 'raw', _G[db.name]) - if not db.raw.currentProfile then - db.raw.currentProfile = {} - end - if not db.raw.currentProfile[charID] then - db.raw.currentProfile[charID] = "Default" - end - if db.raw.disabled then - setmetatable(db.raw.disabled, caseInsensitive_mt) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - setmetatable(db, db_mt) -end - -function AceDB:OnEmbedInitialize(target, name) - if name then - self:ADDON_LOADED(name) - end - self.InitializeDB(target, name) -end - -function AceDB:RegisterDB(name, charName) - AceDB:argCheck(name, 2, "string") - AceDB:argCheck(charName, 3, "string", "nil") - if self.db then - AceDB:error("Cannot call \"RegisterDB\" if self.db is set.") - end - local stack = debugstack() - local addonName = string.gsub(stack, ".-\n.-\\AddOns\\(.-)\\.*", "%1") - self.db = { - name = name, - charName = charName - } - if AceDB.addonsLoaded[addonName] then - AceDB.InitializeDB(self, addonName) - else - AceDB.addonsToBeInitialized[self] = addonName - end - AceDB.registry[self] = true -end - -function AceDB:RegisterDefaults(kind, defaults, a3) - local name - if a3 then - name, kind, defaults = kind, defaults, a3 - AceDB:argCheck(name, 2, "string") - AceDB:argCheck(kind, 3, "string") - AceDB:argCheck(defaults, 4, "table") - else - AceDB:argCheck(kind, 2, "string") - AceDB:argCheck(defaults, 3, "table") - end - if kind ~= "char" and kind ~= "class" and kind ~= "profile" and kind ~= "account" and kind ~= "realm" and kind ~= "faction" then - AceDB:error("Bad argument #%d to `RegisterDefaults' (\"char\", \"class\", \"profile\", \"account\", \"realm\", or \"faction\" expected, got %q)", a3 and 3 or 2, kind) - end - if type(self.db) ~= "table" or type(self.db.name) ~= "string" then - AceDB:error("Cannot call \"RegisterDefaults\" unless \"RegisterDB\" has been previously called.") - end - local db - if name then - local namespace = self:AcquireDBNamespace(name) - if namespace.defaults and namespace.defaults[kind] then - AceDB:error("\"RegisterDefaults\" has already been called for %q::%q.", name, kind) - end - db = namespace - else - if self.db.defaults and self.db.defaults[kind] then - AceDB:error("\"RegisterDefaults\" has already been called for %q.", kind) - end - db = self.db - end - if not db.defaults then - rawset(db, 'defaults', {}) - end - db.defaults[kind] = defaults - if rawget(db, kind) then - inheritDefaults(db[kind], defaults) - end -end - -function AceDB:ResetDB(kind) - AceDB:argCheck(kind, 2, "nil", "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"ResetDB\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - if kind == nil then - if db.charName then - _G[db.charName] = nil - end - _G[db.name] = nil - rawset(db, 'raw', nil) - AceDB.InitializeDB(self) - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'account', nil) - rawset(v, 'char', nil) - rawset(v, 'class', nil) - rawset(v, 'profile', nil) - rawset(v, 'realm', nil) - rawset(v, 'faction', nil) - end - end - elseif kind == "account" then - db.raw.account = nil - rawset(db, 'account', nil) - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'account', nil) - end - end - elseif kind == "char" then - if db.charName then - _G[db.charName] = nil - else - if db.raw.chars then - db.raw.chars[charID] = nil - end - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.chars then - v.chars[charID] = nil - end - end - end - end - rawset(db, 'char', nil) - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'char', nil) - end - end - elseif kind == "realm" then - if db.raw.realms then - db.raw.realms[realmID] = nil - end - rawset(db, 'realm', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.realms then - v.realms[realmID] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'realm', nil) - end - end - elseif kind == "faction" then - if db.raw.factions then - db.raw.factions[faction] = nil - end - rawset(db, 'faction', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.factions then - v.factions[faction] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'faction', nil) - end - end - elseif kind == "class" then - if db.raw.realms then - db.raw.realms[classID] = nil - end - rawset(db, 'class', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.classes then - v.classes[classID] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'class', nil) - end - end - elseif kind == "profile" then - local id = db.raw.currentProfile and db.raw.currentProfile[charID] or "Default" - if id == "char" then - id = "char/" .. charID - elseif id == "class" then - id = "class/" .. classID - elseif id == "realm" then - id = "realm/" .. realmID - end - if db.raw.profiles then - db.raw.profiles[id] = nil - end - rawset(db, 'profile', nil) - if db.raw.namespaces then - for name,v in pairs(db.raw.namespaces) do - if v.profiles then - v.profiles[id] = nil - end - end - end - if db.namespaces then - for name,v in pairs(db.namespaces) do - rawset(v, 'profile', nil) - end - end - end -end - -local function cleanDefaults(t, defaults) - if defaults then - for k,v in pairs(defaults) do - if k == "*" then - if type(v) == "table" then - for k in pairs(t) do - if (defaults[k] == nil or k == "*") and type(t[k]) == "table" then - if cleanDefaults(t[k], v) then - t[k] = nil - end - end - end - else - for k in pairs(t) do - if (defaults[k] == nil or k == "*") and t[k] == v then - t[k] = nil - end - end - end - else - if type(v) == "table" then - if type(t[k]) == "table" then - if cleanDefaults(t[k], v) then - t[k] = nil - end - end - elseif t[k] == v then - t[k] = nil - end - end - end - end - return t and not next(t) -end - -function AceDB:GetProfile() - if not self.db or not self.db.raw then - return nil - end - if not self.db.raw.currentProfile then - self.db.raw.currentProfile = {} - end - if not self.db.raw.currentProfile[charID] then - self.db.raw.currentProfile[charID] = "Default" - end - local profile = self.db.raw.currentProfile[charID] - if profile == "char" then - return "char", "char/" .. charID - elseif profile == "class" then - return "class", "class/" .. classID - elseif profile == "realm" then - return "realm", "realm/" .. realmID - end - return profile, profile -end - -local function copyTable(to, from) - setmetatable(to, nil) - for k,v in pairs(from) do - if type(k) == "table" then - k = copyTable({}, k) - end - if type(v) == "table" then - v = copyTable({}, v) - end - to[k] = v - end - setmetatable(to, from) - return to -end - -function AceDB:SetProfile(name) - AceDB:argCheck(name, 2, "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"SetProfile\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - local lowerName = string.lower(name) - if string.sub(lowerName, 1, 5) == "char/" or string.sub(lowerName, 1, 6) == "realm/" or string.sub(lowerName, 1, 6) == "class/" then - if string.sub(lowerName, 1, 5) == "char/" then - name = "char" - else - name = string.sub(lowerName, 1, 5) - end - lowerName = string.lower(name) - end - local oldName = db.raw.currentProfile[charID] - if string.lower(oldName) == string.lower(name) then - return - end - local oldProfileData = db.profile - local realName = name - if lowerName == "char" then - realName = name .. "/" .. charID - elseif lowerName == "realm" then - realName = name .. "/" .. realmID - elseif lowerName == "class" then - realName = name .. "/" .. classID - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileDisable) == "function" then - safecall(mixin.OnEmbedProfileDisable, mixin, self, realName) - end - end - end - current = current.super - end - if type(self.OnProfileDisable) == "function" then - safecall(self.OnProfileDisable, self, realName) - end - local active = self:IsActive() - db.raw.currentProfile[charID] = name - rawset(db, 'profile', nil) - if db.namespaces then - for k,v in pairs(db.namespaces) do - rawset(v, 'profile', nil) - end - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileEnable) == "function" then - safecall(mixin.OnEmbedProfileEnable, mixin, self, oldName, oldProfileData) - end - end - end - current = current.super - end - if type(self.OnProfileEnable) == "function" then - safecall(self.OnProfileEnable, self, oldName, oldProfileData) - end - if cleanDefaults(oldProfileData, db.defaults and db.defaults.profile) then - db.raw.profiles[oldName] = nil - if not next(db.raw.profiles) then - db.raw.profiles = nil - end - end - local newactive = self:IsActive() - if active ~= newactive then - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - end - if newactive then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if Dewdrop then - Dewdrop:Refresh(1) - Dewdrop:Refresh(2) - Dewdrop:Refresh(3) - Dewdrop:Refresh(4) - Dewdrop:Refresh(5) - end -end - -function AceDB:CopyProfileFrom(copyFrom) - AceDB:argCheck(copyFrom, 2, "string") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"CopyProfileFrom\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - local lowerCopyFrom = string.lower(copyFrom) - if not db.raw.profiles or not db.raw.profiles[copyFrom] then - local good = false - if db.raw.namespaces then - for _,n in pairs(db.raw.namespaces) do - if n.profiles and n.profiles[copyFrom] then - good = true - break - end - end - end - if not good then - AceDB:error("Cannot copy from profile %q, it does not exist.", copyFrom) - end - end - local currentProfile = db.raw.currentProfile[charID] - if string.lower(currentProfile) == lowerCopyFrom then - AceDB:error("Cannot copy from profile %q, it is currently in use.", copyFrom) - end - local oldProfileData = db.profile - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileDisable) == "function" then - safecall(mixin.OnEmbedProfileDisable, mixin, self, currentProfile) - end - end - end - current = current.super - end - if type(self.OnProfileDisable) == "function" then - safecall(self.OnProfileDisable, self, realName) - end - local active = self:IsActive() - for k,v in pairs(db.profile) do - db.profile[k] = nil - end - if db.raw.profiles[copyFrom] then - copyTable(db.profile, db.raw.profiles[copyFrom]) - end - inheritDefaults(db.profile, db.defaults and db.defaults.profile) - if db.namespaces then - for l,u in pairs(db.namespaces) do - for k,v in pairs(u.profile) do - u.profile[k] = nil - end - if db.raw.namespaces[l].profiles[copyFrom] then - copyTable(u.profile, db.raw.namespaces[l].profiles[copyFrom]) - end - inheritDefaults(u.profile, u.defaults and u.defaults.profile) - end - end - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedProfileEnable) == "function" then - safecall(mixin.OnEmbedProfileEnable, mixin, self, copyFrom, oldProfileData, copyFrom) - end - end - end - current = current.super - end - if type(self.OnProfileEnable) == "function" then - safecall(self.OnProfileEnable, self, copyFrom, oldProfileData, copyFrom) - end - local newactive = self:IsActive() - if active ~= newactive then - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - end - if newactive then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - end - if self['acedb-profile-list'] then - RecalculateAceDBProfileList(self) - end - if self['acedb-profile-copylist'] then - RecalculateAceDBCopyFromList(self) - end - if Dewdrop then - Dewdrop:Refresh(1) - Dewdrop:Refresh(2) - Dewdrop:Refresh(3) - Dewdrop:Refresh(4) - Dewdrop:Refresh(5) - end -end - -function AceDB:IsActive() - return not self.db or not self.db.raw or not self.db.raw.disabled or not self.db.raw.disabled[self.db.raw.currentProfile[charID]] -end - -function AceDB:ToggleActive(state) - AceDB:argCheck(state, 2, "boolean", "nil") - if not self.db or not self.db.raw then - AceDB:error("Cannot call \"ToggleActive\" before \"RegisterDB\" has been called and before \"ADDON_LOADED\" has been fired.") - end - local db = self.db - if not db.raw.disabled then - db.raw.disabled = setmetatable({}, caseInsensitive_mt) - end - local profile = db.raw.currentProfile[charID] - local disable - if state == nil then - disable = not db.raw.disabled[profile] - else - disable = not state - if disable == db.raw.disabled[profile] then - return - end - end - db.raw.disabled[profile] = disable or nil - if AceOO.inherits(self, "AceAddon-2.0") then - local AceAddon = AceLibrary("AceAddon-2.0") - if not AceAddon.addonsStarted[self] then - return - end - end - if not disable then - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedEnable) == "function" then - safecall(mixin.OnEmbedEnable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnEnable) == "function" then - safecall(self.OnEnable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonEnabled", self) - end - else - local current = self.class - while current and current ~= AceOO.Class do - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnEmbedDisable) == "function" then - safecall(mixin.OnEmbedDisable, mixin, self) - end - end - end - current = current.super - end - if type(self.OnDisable) == "function" then - safecall(self.OnDisable, self) - end - if AceEvent then - AceEvent:TriggerEvent("Ace2_AddonDisabled", self) - end - end - return not disable -end - -function AceDB:embed(target) - self.super.embed(self, target) - if not AceEvent then - AceDB:error(MAJOR_VERSION .. " requires AceEvent-2.0") - end -end - -function AceDB:ADDON_LOADED(name) - AceDB.addonsLoaded[name] = true - for addon, addonName in pairs(AceDB.addonsToBeInitialized) do - if name == addonName then - AceDB.InitializeDB(addon, name) - AceDB.addonsToBeInitialized[addon] = nil - end - end -end - -function AceDB:PLAYER_LOGOUT() - for addon in pairs(AceDB.registry) do - local db = addon.db - if db then - setmetatable(db, nil) - CrawlForSerialization(db.raw) - if type(_G[db.charName]) == "table" then - CrawlForSerialization(_G[db.charName]) - end - if db.char and cleanDefaults(db.char, db.defaults and db.defaults.char) then - if db.charName and _G[db.charName] and _G[db.charName].global == db.char then - _G[db.charName].global = nil - if not next(_G[db.charName]) then - _G[db.charName] = nil - end - else - if db.raw.chars then - db.raw.chars[charID] = nil - if not next(db.raw.chars) then - db.raw.chars = nil - end - end - end - end - if db.realm and cleanDefaults(db.realm, db.defaults and db.defaults.realm) then - if db.raw.realms then - db.raw.realms[realmID] = nil - if not next(db.raw.realms) then - db.raw.realms = nil - end - end - end - if db.faction and cleanDefaults(db.faction, db.defaults and db.defaults.faction) then - if db.raw.factions then - db.raw.factions[faction] = nil - if not next(db.raw.factions) then - db.raw.factions = nil - end - end - end - if db.class and cleanDefaults(db.class, db.defaults and db.defaults.class) then - if db.raw.classes then - db.raw.classes[classID] = nil - if not next(db.raw.classes) then - db.raw.classes = nil - end - end - end - if db.account and cleanDefaults(db.account, db.defaults and db.defaults.account) then - db.raw.account = nil - end - if db.profile and cleanDefaults(db.profile, db.defaults and db.defaults.profile) then - if db.raw.profiles then - db.raw.profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or "Default"] = nil - if not next(db.raw.profiles) then - db.raw.profiles = nil - end - end - end - if db.namespaces and db.raw.namespaces then - for name,v in pairs(db.namespaces) do - if db.raw.namespaces[name] then - setmetatable(v, nil) - if v.char and cleanDefaults(v.char, v.defaults and v.defaults.char) then - if db.charName and _G[db.charName] and _G[db.charName].namespaces and _G[db.charName].namespaces[name] == v then - _G[db.charName].namespaces[name] = nil - if not next(_G[db.charName].namespaces) then - _G[db.charName].namespaces = nil - if not next(_G[db.charName]) then - _G[db.charName] = nil - end - end - else - if db.raw.namespaces[name].chars then - db.raw.namespaces[name].chars[charID] = nil - if not next(db.raw.namespaces[name].chars) then - db.raw.namespaces[name].chars = nil - end - end - end - end - if v.realm and cleanDefaults(v.realm, v.defaults and v.defaults.realm) then - if db.raw.namespaces[name].realms then - db.raw.namespaces[name].realms[realmID] = nil - if not next(db.raw.namespaces[name].realms) then - db.raw.namespaces[name].realms = nil - end - end - end - if v.faction and cleanDefaults(v.faction, v.defaults and v.defaults.faction) then - if db.raw.namespaces[name].factions then - db.raw.namespaces[name].factions[faction] = nil - if not next(db.raw.namespaces[name].factions) then - db.raw.namespaces[name].factions = nil - end - end - end - if v.class and cleanDefaults(v.class, v.defaults and v.defaults.class) then - if db.raw.namespaces[name].classes then - db.raw.namespaces[name].classes[classID] = nil - if not next(db.raw.namespaces[name].classes) then - db.raw.namespaces[name].classes = nil - end - end - end - if v.account and cleanDefaults(v.account, v.defaults and v.defaults.account) then - db.raw.namespaces[name].account = nil - end - if v.profile and cleanDefaults(v.profile, v.defaults and v.defaults.profile) then - if db.raw.namespaces[name].profiles then - db.raw.namespaces[name].profiles[db.raw.currentProfile and db.raw.currentProfile[charID] or "Default"] = nil - if not next(db.raw.namespaces[name].profiles) then - db.raw.namespaces[name].profiles = nil - end - end - end - if not next(db.raw.namespaces[name]) then - db.raw.namespaces[name] = nil - end - end - end - if not next(db.raw.namespaces) then - db.raw.namespaces = nil - end - end - if db.raw.disabled and not next(db.raw.disabled) then - db.raw.disabled = nil - end - if db.raw.currentProfile then - for k,v in pairs(db.raw.currentProfile) do - if string.lower(v) == "default" then - db.raw.currentProfile[k] = nil - end - end - if not next(db.raw.currentProfile) then - db.raw.currentProfile = nil - end - end - if _G[db.name] and not next(_G[db.name]) then - _G[db.name] = nil - end - end - end -end - -function AceDB:AcquireDBNamespace(name) - AceDB:argCheck(name, 2, "string") - local db = self.db - if not db then - AceDB:error("Cannot call `AcquireDBNamespace' before `RegisterDB' has been called.", 2) - end - if not db.namespaces then - rawset(db, 'namespaces', {}) - end - if not db.namespaces[name] then - local namespace = {} - db.namespaces[name] = namespace - namespace.db = db - namespace.name = name - setmetatable(namespace, namespace_mt) - end - return db.namespaces[name] -end - -function AceDB:GetAceOptionsDataTable(target) - if not target['acedb-profile-list'] then - target['acedb-profile-list'] = setmetatable({}, caseInsensitive_mt) - RecalculateAceDBProfileList(target) - end - if not target['acedb-profile-copylist'] then - target['acedb-profile-copylist'] = setmetatable({}, caseInsensitive_mt) - RecalculateAceDBCopyFromList(target) - end - return { - standby = { - cmdName = STATE, - guiName = ENABLED, - name = ACTIVE, - desc = TOGGLE_ACTIVE, - type = "toggle", - get = "IsActive", - set = "ToggleActive", - map = MAP_ACTIVESUSPENDED, - order = -3, - }, - profile = { - type = 'group', - name = PROFILE, - desc = SET_PROFILE, - order = -3.5, - get = "GetProfile", - args = { - choose = { - guiName = CHOOSE_PROFILE_GUI, - cmdName = PROFILE, - desc = CHOOSE_PROFILE_DESC, - type = 'text', - get = "GetProfile", - set = "SetProfile", - validate = target['acedb-profile-list'] - }, - copy = { - guiName = COPY_PROFILE_GUI, - cmdName = PROFILE, - desc = COPY_PROFILE_DESC, - type = 'text', - get = false, - set = "CopyProfileFrom", - validate = target['acedb-profile-copylist'], - disabled = function() - return not next(target['acedb-profile-copylist']) - end, - }, - other = { - guiName = OTHER_PROFILE_GUI, - cmdName = PROFILE, - desc = OTHER_PROFILE_DESC, - usage = OTHER_PROFILE_USAGE, - type = 'text', - get = "GetProfile", - set = "SetProfile", - } - } - }, - } -end - -local function activate(self, oldLib, oldDeactivate) - AceDB = self - AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") - - self.addonsToBeInitialized = oldLib and oldLib.addonsToBeInitialized or {} - self.addonsLoaded = oldLib and oldLib.addonsLoaded or {} - self.registry = oldLib and oldLib.registry or {} - - self:activate(oldLib, oldDeactivate) - - for t in pairs(self.embedList) do - if t.db then - rawset(t.db, 'char', nil) - rawset(t.db, 'realm', nil) - rawset(t.db, 'class', nil) - rawset(t.db, 'account', nil) - rawset(t.db, 'faction', nil) - rawset(t.db, 'profile', nil) - setmetatable(t.db, db_mt) - end - end - - if oldLib then - oldDeactivate(oldLib) - end -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - - AceEvent:embed(self) - - self:RegisterEvent("ADDON_LOADED") - self:RegisterEvent("PLAYER_LOGOUT") - elseif major == "Dewdrop-2.0" then - Dewdrop = instance - end -end - -AceLibrary:Register(AceDB, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) -AceDB = AceLibrary(MAJOR_VERSION)
--- a/libs/AceEvent-2.0/AceEvent-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,926 +0,0 @@ ---[[ -Name: AceEvent-2.0 -Revision: $Rev: 19845 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceEvent-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0 -Description: Mixin to allow for event handling, scheduling, and inter-addon - communication. -Dependencies: AceLibrary, AceOO-2.0 -]] - -local MAJOR_VERSION = "AceEvent-2.0" -local MINOR_VERSION = "$Revision: 19845 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end - -local AceOO = AceLibrary:GetInstance("AceOO-2.0") -local Mixin = AceOO.Mixin -local AceEvent = Mixin { - "RegisterEvent", - "RegisterAllEvents", - "UnregisterEvent", - "UnregisterAllEvents", - "TriggerEvent", - "ScheduleEvent", - "ScheduleRepeatingEvent", - "CancelScheduledEvent", - "CancelAllScheduledEvents", - "IsEventRegistered", - "IsEventScheduled", - "RegisterBucketEvent", - "UnregisterBucketEvent", - "UnregisterAllBucketEvents", - "IsBucketEventRegistered", - } - -local weakKey = {__mode="k"} - -local FAKE_NIL -local RATE - -local eventsWhichHappenOnce = { - PLAYER_LOGIN = true, - AceEvent_FullyInitialized = true, - VARIABLES_LOADED = true, - PLAYER_LOGOUT = true, -} -local next = next -local pairs = pairs -local pcall = pcall -local type = type -local GetTime = GetTime -local gcinfo = gcinfo -local unpack = unpack -local geterrorhandler = geterrorhandler - -local registeringFromAceEvent -function AceEvent:RegisterEvent(event, method, once) - AceEvent:argCheck(event, 2, "string") - if self == AceEvent and not registeringFromAceEvent then - AceEvent:argCheck(method, 3, "function") - self = method - else - AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number") - if type(method) == "boolean" or type(method) == "number" then - AceEvent:argCheck(once, 4, "nil") - once, method = method, event - end - end - AceEvent:argCheck(once, 4, "number", "boolean", "nil") - if eventsWhichHappenOnce[event] then - once = true - end - local throttleRate - if type(once) == "number" then - throttleRate, once = once - end - if not method then - method = event - end - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) - else - assert(type(method) == "function" or type(method) == "string") - end - - local AceEvent_registry = AceEvent.registry - if not AceEvent_registry[event] then - AceEvent_registry[event] = {} - AceEvent.frame:RegisterEvent(event) - end - - local remember = true - if AceEvent_registry[event][self] then - remember = false - end - AceEvent_registry[event][self] = method - - local AceEvent_onceRegistry = AceEvent.onceRegistry - if once then - if not AceEvent_onceRegistry then - AceEvent.onceRegistry = {} - AceEvent_onceRegistry = AceEvent.onceRegistry - end - if not AceEvent_onceRegistry[event] then - AceEvent_onceRegistry[event] = {} - end - AceEvent_onceRegistry[event][self] = true - else - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then - AceEvent_onceRegistry[event][self] = nil - if not next(AceEvent_onceRegistry[event]) then - AceEvent_onceRegistry[event] = nil - end - end - end - - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - if throttleRate then - if not AceEvent_throttleRegistry then - AceEvent.throttleRegistry = {} - AceEvent_throttleRegistry = AceEvent.throttleRegistry - end - if not AceEvent_throttleRegistry[event] then - AceEvent_throttleRegistry[event] = {} - end - if AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - end - AceEvent_throttleRegistry[event][self] = setmetatable({}, weakKey) - local t = AceEvent_throttleRegistry[event][self] - t[RATE] = throttleRate - else - if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then - if AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - end - if not next(AceEvent_throttleRegistry[event]) then - AceEvent_throttleRegistry[event] = nil - end - end - end - - if remember then - AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event) - end -end - -local ALL_EVENTS - -function AceEvent:RegisterAllEvents(method) - if self == AceEvent then - AceEvent:argCheck(method, 1, "function") - self = method - else - AceEvent:argCheck(method, 1, "string", "function") - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register all events to method %q, it does not exist", method) - end - end - - local AceEvent_registry = AceEvent.registry - if not AceEvent_registry[ALL_EVENTS] then - AceEvent_registry[ALL_EVENTS] = {} - AceEvent.frame:RegisterAllEvents() - end - - AceEvent_registry[ALL_EVENTS][self] = method -end - -local memstack, timestack = {}, {} -local memdiff, timediff - -local stack = setmetatable({}, {__mode='k'}) -function AceEvent:TriggerEvent(event, ...) - local tmp = next(stack) or {} - stack[tmp] = nil - if type(event) ~= "string" then - DEFAULT_CHAT_FRAME:AddMessage(debugstack()) - end - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then - return - end - local lastEvent = AceEvent.currentEvent - AceEvent.currentEvent = event - - local AceEvent_onceRegistry = AceEvent.onceRegistry - local AceEvent_debugTable = AceEvent.debugTable - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then - for obj, method in pairs(AceEvent_onceRegistry[event]) do - tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil - end - local obj = next(tmp) - while obj do - local mem, time - if AceEvent_debugTable then - if not AceEvent_debugTable[event] then - AceEvent_debugTable[event] = {} - end - if not AceEvent_debugTable[event][obj] then - AceEvent_debugTable[event][obj] = { - mem = 0, - time = 0, - count = 0, - } - end - if memdiff then - table.insert(memstack, memdiff) - table.insert(timestack, timediff) - end - memdiff, timediff = 0, 0 - mem, time = gcinfo(), GetTime() - end - local method = tmp[obj] - AceEvent.UnregisterEvent(obj, event) - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err) end - end - if AceEvent_debugTable then - local dmem, dtime = memdiff, timediff - mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff - AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem - AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time - AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 - - memdiff, timediff = table.remove(memstack), table.remove(timestack) - if memdiff then - memdiff = memdiff + mem + dmem - timediff = timediff + time + dtime - end - end - tmp[obj] = nil - obj = next(tmp) - end - end - - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] - if AceEvent_registry[event] then - for obj, method in pairs(AceEvent_registry[event]) do - tmp[obj] = method - end - local obj = next(tmp) - while obj do - local method = tmp[obj] - local continue = false - if throttleTable and throttleTable[obj] then - local a1 = ... - if a1 == nil then - a1 = FAKE_NIL - end - if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then - throttleTable[obj][a1] = GetTime() - else - continue = true - end - end - if not continue then - local mem, time - if AceEvent_debugTable then - if not AceEvent_debugTable[event] then - AceEvent_debugTable[event] = {} - end - if not AceEvent_debugTable[event][obj] then - AceEvent_debugTable[event][obj] = { - mem = 0, - time = 0, - count = 0, - } - end - if memdiff then - table.insert(memstack, memdiff) - table.insert(timestack, timediff) - end - memdiff, timediff = 0, 0 - mem, time = gcinfo(), GetTime() - end - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err) end - end - if AceEvent_debugTable then - local dmem, dtime = memdiff, timediff - mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff - AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem - AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time - AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 - - memdiff, timediff = table.remove(memstack), table.remove(timestack) - if memdiff then - memdiff = memdiff + mem + dmem - timediff = timediff + time + dtime - end - end - end - tmp[obj] = nil - obj = next(tmp) - end - end - if AceEvent_registry[ALL_EVENTS] then - for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do - tmp[obj] = method - end - local obj = next(tmp) - while obj do - local method = tmp[obj] - local mem, time - if AceEvent_debugTable then - if not AceEvent_debugTable[event] then - AceEvent_debugTable[event] = {} - end - if not AceEvent_debugTable[event][obj] then - AceEvent_debugTable[event][obj] = {} - AceEvent_debugTable[event][obj].mem = 0 - AceEvent_debugTable[event][obj].time = 0 - AceEvent_debugTable[event][obj].count = 0 - end - if memdiff then - table.insert(memstack, memdiff) - table.insert(timestack, timediff) - end - memdiff, timediff = 0, 0 - mem, time = gcinfo(), GetTime() - end - if type(method) == "string" then - local obj_method = obj[method] - if obj_method then - obj_method(obj, ...) - local success, err = pcall(obj_method, obj, ...) - if not success then geterrorhandler()(err) end - end - elseif method then -- function - local success, err = pcall(method, ...) - if not success then geterrorhandler()(err) end - end - if AceEvent_debugTable then - local dmem, dtime = memdiff, timediff - mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff - AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem - AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time - AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1 - - memdiff, timediff = table.remove(memstack), table.remove(timestack) - if memdiff then - memdiff = memdiff + mem + dmem - timediff = timediff + time + dtime - end - end - tmp[obj] = nil - obj = next(tmp) - end - end - stack[tmp] = true - AceEvent.currentEvent = lastEvent -end - -local delayRegistry -local tmp = {} -local function OnUpdate() - local t = GetTime() - for k,v in pairs(delayRegistry) do - tmp[k] = true - end - for k in pairs(tmp) do - local v = delayRegistry[k] - if v then - local v_time = v.time - if not v_time then - delayRegistry[k] = nil - elseif v_time <= t then - local v_repeatDelay = v.repeatDelay - if v_repeatDelay then - -- use the event time, not the current time, else timing inaccuracies add up over time - v.time = v_time + v_repeatDelay - end - local event = v.event - local mem, time - if AceEvent_debugTable then - mem, time = gcinfo(), GetTime() - end - if type(event) == "function" then - local success, err = pcall(event, unpack(v)) - if not success then geterrorhandler()(err) end - else - AceEvent:TriggerEvent(event, unpack(v)) - end - if AceEvent_debugTable then - mem, time = gcinfo() - mem, GetTime() - time - v.mem = v.mem + mem - v.timeSpent = v.timeSpent + time - v.count = v.count + 1 - end - if not v_repeatDelay then - local x = delayRegistry[k] - if x and x.time == v_time then -- check if it was manually reset - delayRegistry[k] = nil - end - end - end - end - end - for k in pairs(tmp) do - tmp[k] = nil - end - if not next(delayRegistry) then - AceEvent.frame:Hide() - end -end - -local function ScheduleEvent(self, repeating, event, delay, ...) - local id - if type(event) == "string" or type(event) == "table" then - if type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - id, event, delay = event, delay, ... - AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(delay, 4, "number") - self:CancelScheduledEvent(id) - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - if not delayRegistry then - AceEvent.delayRegistry = {} - delayRegistry = AceEvent.delayRegistry - AceEvent.frame:SetScript("OnUpdate", OnUpdate) - end - local t - if type(id) == "table" then - for k in pairs(id) do - id[k] = nil - end - t = id - for i = 2, select('#', ...) do - t[i-1] = select(i, ...) - end - elseif id then - t = { select(2, ...) } - else - t = { ... } - end - t.event = event - t.time = GetTime() + delay - t.self = self - t.id = id or t - t.repeatDelay = repeating and delay - if AceEvent_debugTable then - t.mem = 0 - t.count = 0 - t.timeSpent = 0 - end - delayRegistry[t.id] = t - AceEvent.frame:Show() - return t.id -end - -function AceEvent:ScheduleEvent(event, delay, ...) - if type(event) == "string" or type(event) == "table" then - if type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(..., 4, "number") - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - return ScheduleEvent(self, false, event, delay, ...) -end - -function AceEvent:ScheduleRepeatingEvent(event, delay, ...) - if type(event) == "string" or type(event) == "table" then - if type(event) == "table" then - if not delayRegistry or not delayRegistry[event] then - AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.") - end - end - if type(delay) ~= "number" then - AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number") - AceEvent:argCheck(..., 4, "number") - end - else - AceEvent:argCheck(event, 2, "string", "function") - AceEvent:argCheck(delay, 3, "number") - end - - return ScheduleEvent(self, true, event, delay, ...) -end - -function AceEvent:CancelScheduledEvent(t) - AceEvent:argCheck(t, 2, "string", "table") - if delayRegistry then - local v = delayRegistry[t] - if v then - delayRegistry[t] = nil - if not next(delayRegistry) then - AceEvent.frame:Hide() - end - return true - end - end - return false -end - -function AceEvent:IsEventScheduled(t) - AceEvent:argCheck(t, 2, "string", "table") - if delayRegistry then - local v = delayRegistry[t] - if v then - return true, v.time - GetTime() - end - end - return false, nil -end - -function AceEvent:UnregisterEvent(event) - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if AceEvent_registry[event] and AceEvent_registry[event][self] then - AceEvent_registry[event][self] = nil - local AceEvent_onceRegistry = AceEvent.onceRegistry - if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then - AceEvent_onceRegistry[event][self] = nil - if not next(AceEvent_onceRegistry[event]) then - AceEvent_onceRegistry[event] = nil - end - end - local AceEvent_throttleRegistry = AceEvent.throttleRegistry - if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then - AceEvent_throttleRegistry[event][self] = nil - if not next(AceEvent_throttleRegistry[event]) then - AceEvent_throttleRegistry[event] = nil - end - end - if not next(AceEvent_registry[event]) then - AceEvent_registry[event] = nil - if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then - AceEvent.frame:UnregisterEvent(event) - end - end - else - if self == AceEvent then - error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2) - else - AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self) - end - end - AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) -end - -function AceEvent:UnregisterAllEvents() - local AceEvent_registry = AceEvent.registry - if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then - AceEvent_registry[ALL_EVENTS][self] = nil - if not next(AceEvent_registry[ALL_EVENTS]) then - AceEvent.frame:UnregisterAllEvents() - for k,v in pairs(AceEvent_registry) do - if k ~= ALL_EVENTS then - AceEvent.frame:RegisterEvent(k) - end - end - AceEvent_registry[ALL_EVENTS] = nil - end - end - local first = true - for event, data in pairs(AceEvent_registry) do - if first then - if AceEvent_registry.AceEvent_EventUnregistered then - event = "AceEvent_EventUnregistered" - else - first = false - end - end - local x = data[self] - data[self] = nil - if x and event ~= ALL_EVENTS then - if not next(data) then - if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then - AceEvent.frame:UnregisterEvent(event) - end - AceEvent_registry[event] = nil - end - AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event) - end - if first then - event = nil - end - end - if AceEvent.onceRegistry then - for event, data in pairs(AceEvent.onceRegistry) do - data[self] = nil - end - end -end - -function AceEvent:CancelAllScheduledEvents() - if delayRegistry then - for k,v in pairs(delayRegistry) do - if v.self == self then - delayRegistry[k] = nil - end - end - if not next(delayRegistry) then - AceEvent.frame:Hide() - end - end -end - -function AceEvent:IsEventRegistered(event) - AceEvent:argCheck(event, 2, "string") - local AceEvent_registry = AceEvent.registry - if self == AceEvent then - return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false - end - if AceEvent_registry[event] and AceEvent_registry[event][self] then - return true, AceEvent_registry[event][self] - end - return false, nil -end - -local bucketfunc -function AceEvent:RegisterBucketEvent(event, delay, method) - AceEvent:argCheck(event, 2, "string", "table") - if type(event) == "table" then - for k,v in pairs(event) do - if type(k) ~= "number" then - AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.") - elseif type(v) ~= "string" then - AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.") - end - end - end - AceEvent:argCheck(delay, 3, "number") - if AceEvent == self then - AceEvent:argCheck(method, 4, "function") - self = method - else - if type(event) == "string" then - AceEvent:argCheck(method, 4, "string", "function", "nil") - if not method then - method = event - end - else - AceEvent:argCheck(method, 4, "string", "function") - end - - if type(method) == "string" and type(self[method]) ~= "function" then - AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method) - end - end - if not AceEvent.buckets then - AceEvent.buckets = {} - end - if not AceEvent.buckets[event] then - AceEvent.buckets[event] = {} - end - if not AceEvent.buckets[event][self] then - AceEvent.buckets[event][self] = { - current = {}, - self = self - } - else - AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id) - end - local bucket = AceEvent.buckets[event][self] - bucket.method = method - - local func = function(arg1) - bucket.run = true - if arg1 then - bucket.current[arg1] = true - end - end - AceEvent.buckets[event][self].func = func - if type(event) == "string" then - AceEvent.RegisterEvent(self, event, func) - else - for _,v in ipairs(event) do - AceEvent.RegisterEvent(self, v, func) - end - end - if not bucketfunc then - bucketfunc = function(bucket) - local current = bucket.current - local method = bucket.method - local self = bucket.self - if bucket.run then - if type(method) == "string" then - self[method](self, current) - elseif method then -- function - method(current) - end - for k in pairs(current) do - current[k] = nil - k = nil - end - bucket.run = false - end - end - end - bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket) -end - -function AceEvent:IsBucketEventRegistered(event) - AceEvent:argCheck(event, 2, "string", "table") - return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self] -end - -function AceEvent:UnregisterBucketEvent(event) - AceEvent:argCheck(event, 2, "string", "table") - if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then - AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self) - end - - local bucket = AceEvent.buckets[event][self] - - if type(event) == "string" then - AceEvent.UnregisterEvent(self, event) - else - for _,v in ipairs(event) do - AceEvent.UnregisterEvent(self, v) - end - end - AceEvent:CancelScheduledEvent(bucket.id) - - AceEvent.buckets[event][self] = nil - if not next(AceEvent.buckets[event]) then - AceEvent.buckets[event] = nil - end -end - -function AceEvent:UnregisterAllBucketEvents() - if not AceEvent.buckets or not next(AceEvent.buckets) then - return - end - for k,v in pairs(AceEvent.buckets) do - if v == self then - AceEvent.UnregisterBucketEvent(self, k) - k = nil - end - end -end - -function AceEvent:OnEmbedDisable(target) - self.UnregisterAllEvents(target) - - self.CancelAllScheduledEvents(target) - - self.UnregisterAllBucketEvents(target) -end - -function AceEvent:EnableDebugging() - if not self.debugTable then - self.debugTable = {} - - if delayRegistry then - for k,v in pairs(self.delayRegistry) do - if not v.mem then - v.mem = 0 - v.count = 0 - v.timeSpent = 0 - end - end - end - end -end - -function AceEvent:IsFullyInitialized() - return self.postInit or false -end - -function AceEvent:IsPostPlayerLogin() - return self.playerLogin or false -end - -local function activate(self, oldLib, oldDeactivate) - AceEvent = self - - if oldLib then - self.onceRegistry = oldLib.onceRegistry - self.throttleRegistry = oldLib.throttleRegistry - self.delayRegistry = oldLib.delayRegistry - self.buckets = oldLib.buckets - self.registry = oldLib.registry - self.frame = oldLib.frame - self.debugTable = oldLib.debugTable - self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true - self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true - self.ALL_EVENTS = oldLib.ALL_EVENTS - self.FAKE_NIL = oldLib.FAKE_NIL - self.RATE = oldLib.RATE - end - if not self.registry then - self.registry = {} - end - if not self.frame then - self.frame = CreateFrame("Frame", "AceEvent20Frame") - end - if not self.ALL_EVENTS then - self.ALL_EVENTS = {} - end - if not self.FAKE_NIL then - self.FAKE_NIL = {} - end - if not self.RATE then - self.RATE = {} - end - ALL_EVENTS = self.ALL_EVENTS - FAKE_NIL = self.FAKE_NIL - RATE = self.RATE - local inPlw = false - local blacklist = { - UNIT_INVENTORY_CHANGED = true, - BAG_UPDATE = true, - ITEM_LOCK_CHANGED = true, - ACTIONBAR_SLOT_CHANGED = true, - } - self.frame:SetScript("OnEvent", function(_, event, ...) - if event == "PLAYER_ENTERING_WORLD" then - inPlw = false - elseif event == "PLAYER_LEAVING_WORLD" then - inPlw = true - end - if event and (not inPlw or not blacklist[event]) then - self:TriggerEvent(event, ...) - end - end) - if self.delayRegistry then - delayRegistry = self.delayRegistry - self.frame:SetScript("OnUpdate", OnUpdate) - end - - self:UnregisterAllEvents() - self:CancelAllScheduledEvents() - - registeringFromAceEvent = true - self:RegisterEvent("LOOT_OPENED", function() - SendAddonMessage("LOOT_OPENED", "", "RAID") - end) - registeringFromAceEvent = nil - - if not self.playerLogin then - registeringFromAceEvent = true - self:RegisterEvent("PLAYER_LOGIN", function() - self.playerLogin = true - end, true) - registeringFromAceEvent = nil - end - - if not self.postInit then - local isReload = true - local function func() - self.postInit = true - self:TriggerEvent("AceEvent_FullyInitialized") - if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then - self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") - end - if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then - self:UnregisterEvent("MEETINGSTONE_CHANGED") - end - if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then - self:UnregisterEvent("MINIMAP_ZONE_CHANGED") - end - if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then - self:UnregisterEvent("LANGUAGE_LIST_CHANGED") - end - end - registeringFromAceEvent = true - local f = function() - self.playerLogin = true - self:ScheduleEvent("AceEvent_FullyInitialized", func, 1) - end - self:RegisterEvent("MEETINGSTONE_CHANGED", f, true) - self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function() - self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05) - end) - self:RegisterEvent("LANGUAGE_LIST_CHANGED", function() - if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then - registeringFromAceEvent = true - self:UnregisterEvent("MEETINGSTONE_CHANGED") - self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true) - registeringFromAceEvent = nil - end - end) - self:ScheduleEvent("AceEvent_FullyInitialized", func, 10) - registeringFromAceEvent = nil - end - - self:activate(oldLib, oldDeactivate) - if oldLib then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)
--- a/libs/AceLibrary/AceLibrary.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,702 +0,0 @@ ---[[ -Name: AceLibrary -Revision: $Rev$ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Iriel (iriel@vigilance-committee.org) - Tekkub (tekkub@gmail.com) - Revision: $Rev$ -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceLibrary -SVN: http://svn.wowace.com/root/trunk/Ace2/AceLibrary -Description: Versioning library to handle other library instances, upgrading, - and proper access. - It also provides a base for libraries to work off of, providing - proper error tools. It is handy because all the errors occur in the - file that called it, not in the library file itself. -Dependencies: None -License: LGPL v2.1 -]] - -local ACELIBRARY_MAJOR = "AceLibrary" -local ACELIBRARY_MINOR = "$Revision: 20000 $" - -local _G = getfenv(0) -local previous = _G[ACELIBRARY_MAJOR] -if previous and not previous:IsNewVersion(ACELIBRARY_MAJOR, ACELIBRARY_MINOR) then return end - -local function safecall(func,...) - local success, err = pcall(func,...) - if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("\n(.-: )in.-\n") or "") .. err) end -end - --- @table AceLibrary --- @brief System to handle all versioning of libraries. -local AceLibrary = {} -local AceLibrary_mt = {} -setmetatable(AceLibrary, AceLibrary_mt) - -local function error(self, message, ...) - if type(self) ~= "table" then - return _G.error(("Bad argument #1 to `error' (table expected, got %s)"):format(type(self)), 2) - end - - local stack = debugstack() - if not message then - local _,_,second = stack:find("\n(.-)\n") - message = "error raised! " .. second - else - local arg = { ... } -- not worried about table creation, as errors don't happen often - - for i = 1, #arg do - arg[i] = tostring(arg[i]) - end - for i = 1, 10 do - table.insert(arg, "nil") - end - message = message:format(unpack(arg)) - end - - if getmetatable(self) and getmetatable(self).__tostring then - message = ("%s: %s"):format(tostring(self), message) - elseif type(rawget(self, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self:GetLibraryVersion()) then - message = ("%s: %s"):format(self:GetLibraryVersion(), message) - elseif type(rawget(self, 'class')) == "table" and type(rawget(self.class, 'GetLibraryVersion')) == "function" and AceLibrary:HasInstance(self.class:GetLibraryVersion()) then - message = ("%s: %s"):format(self.class:GetLibraryVersion(), message) - end - - local first = stack:gsub("\n.*", "") - local file = first:gsub(".*\\(.*).lua:%d+: .*", "%1") - file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - - - local i = 0 - for s in stack:gmatch("\n([^\n]*)") do - i = i + 1 - if not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then - file = s:gsub("^.*\\(.*).lua:%d+: .*", "%1") - file = file:gsub("([%(%)%.%*%+%-%[%]%?%^%$%%])", "%%%1") - break - end - end - local j = 0 - for s in stack:gmatch("\n([^\n]*)") do - j = j + 1 - if j > i and not s:find(file .. "%.lua:%d+:") and not s:find("%(tail call%)") then - return _G.error(message, j+1) - end - end - return _G.error(message, 2) -end - -local function assert(self, condition, message, ...) - if not condition then - if not message then - local stack = debugstack() - local _,_,second = stack:find("\n(.-)\n") - message = "assertion failed! " .. second - end - return error(self, message, ...) - end - return condition -end - -local function argCheck(self, arg, num, kind, kind2, kind3, kind4, kind5) - if type(num) ~= "number" then - return error(self, "Bad argument #3 to `argCheck' (number expected, got %s)", type(num)) - elseif type(kind) ~= "string" then - return error(self, "Bad argument #4 to `argCheck' (string expected, got %s)", type(kind)) - end - local errored = false - arg = type(arg) - if arg ~= kind and arg ~= kind2 and arg ~= kind3 and arg ~= kind4 and arg ~= kind5 then - local stack = debugstack() - local _,_,func = stack:find("`argCheck'.-([`<].-['>])") - if not func then - _,_,func = stack:find("([`<].-['>])") - end - if kind5 then - return error(self, "Bad argument #%s to %s (%s, %s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, kind5, arg) - elseif kind4 then - return error(self, "Bad argument #%s to %s (%s, %s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, kind4, arg) - elseif kind3 then - return error(self, "Bad argument #%s to %s (%s, %s, or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, kind3, arg) - elseif kind2 then - return error(self, "Bad argument #%s to %s (%s or %s expected, got %s)", tonumber(num) or 0/0, func, kind, kind2, arg) - else - return error(self, "Bad argument #%s to %s (%s expected, got %s)", tonumber(num) or 0/0, func, kind, arg) - end - end -end - -local pcall -do - local function check(self, ret, ...) - if not ret then - local s = ... - return error(self, (s:gsub(".-%.lua:%d-: ", ""))) - else - return ... - end - end - - function pcall(self, func, ...) - return check(self, _G.pcall(func, ...)) - end -end - -local recurse = {} -local function addToPositions(t, major) - if not AceLibrary.positions[t] or AceLibrary.positions[t] == major then - rawset(t, recurse, true) - AceLibrary.positions[t] = major - for k,v in pairs(t) do - if type(v) == "table" and not rawget(v, recurse) then - addToPositions(v, major) - end - if type(k) == "table" and not rawget(k, recurse) then - addToPositions(k, major) - end - end - local mt = getmetatable(t) - if mt and not rawget(mt, recurse) then - addToPositions(mt, major) - end - rawset(t, recurse, nil) - end -end - -local function svnRevisionToNumber(text) - if type(text) == "string" then - if text:find("^%$Revision: (%d+) %$$") then - return tonumber((text:gsub("^%$Revision: (%d+) %$$", "%1"))) - elseif text:find("^%$Rev: (%d+) %$$") then - return tonumber((text:gsub("^%$Rev: (%d+) %$$", "%1"))) - elseif text:find("^%$LastChangedRevision: (%d+) %$$") then - return tonumber((text:gsub("^%$LastChangedRevision: (%d+) %$$", "%1"))) - end - elseif type(text) == "number" then - return text - end - return nil -end - -local crawlReplace -do - local recurse = {} - local function func(t, to, from) - if recurse[t] then - return - end - recurse[t] = true - local mt = getmetatable(t) - setmetatable(t, nil) - rawset(t, to, rawget(t, from)) - rawset(t, from, nil) - for k,v in pairs(t) do - if v == from then - t[k] = to - elseif type(v) == "table" then - if not recurse[v] then - func(v, to, from) - end - end - - if type(k) == "table" then - if not recurse[k] then - func(k, to, from) - end - end - end - setmetatable(t, mt) - if mt then - if mt == from then - setmetatable(t, to) - elseif not recurse[mt] then - func(mt, to, from) - end - end - end - function crawlReplace(t, to, from) - func(t, to, from) - for k in pairs(recurse) do - recurse[k] = nil - end - end -end - --- @function destroyTable --- @brief remove all the contents of a table --- @param t table to destroy -local function destroyTable(t) - setmetatable(t, nil) - for k,v in pairs(t) do - t[k] = nil - end -end - -local function isFrame(frame) - return type(frame) == "table" and type(rawget(frame, 0)) == "userdata" and type(rawget(frame, 'IsFrameType')) == "function" and getmetatable(frame) and type(rawget(getmetatable(frame), '__index')) == "function" -end - --- @function copyTable --- @brief Create a shallow copy of a table and return it. --- @param from The table to copy from --- @return A shallow copy of the table -local function copyTable(from) - local to = {} - for k,v in pairs(from) do - to[k] = v - end - setmetatable(to, getmetatable(from)) - return to -end - --- @function deepTransfer --- @brief Fully transfer all data, keeping proper previous table --- backreferences stable. --- @param to The table with which data is to be injected into --- @param from The table whose data will be injected into the first --- @param saveFields If available, a shallow copy of the basic data is saved --- in here. --- @param list The account of table references --- @param list2 The current status on which tables have been traversed. -local deepTransfer -do - -- @function examine - -- @brief Take account of all the table references to be shared - -- between the to and from tables. - -- @param to The table with which data is to be injected into - -- @param from The table whose data will be injected into the first - -- @param list An account of the table references - local function examine(to, from, list, major) - list[from] = to - for k,v in pairs(from) do - if rawget(to, k) and type(from[k]) == "table" and type(to[k]) == "table" and not list[from[k]] then - if from[k] == to[k] then - list[from[k]] = to[k] - elseif AceLibrary.positions[from[v]] ~= major and AceLibrary.positions[from[v]] then - list[from[k]] = from[k] - elseif not list[from[k]] then - examine(to[k], from[k], list, major) - end - end - end - return list - end - - function deepTransfer(to, from, saveFields, major, list, list2) - setmetatable(to, nil) - if not list then - list = {} - list2 = {} - examine(to, from, list, major) - end - list2[to] = to - for k,v in pairs(to) do - if type(rawget(from, k)) ~= "table" or type(v) ~= "table" or isFrame(v) then - if saveFields then - saveFields[k] = v - end - to[k] = nil - elseif v ~= _G then - if saveFields then - saveFields[k] = copyTable(v) - end - end - end - for k in pairs(from) do - if rawget(to, k) and to[k] ~= from[k] and AceLibrary.positions[to[k]] == major and from[k] ~= _G then - if not list2[to[k]] then - deepTransfer(to[k], from[k], nil, major, list, list2) - end - to[k] = list[to[k]] or list2[to[k]] - else - rawset(to, k, from[k]) - end - end - setmetatable(to, getmetatable(from)) - local mt = getmetatable(to) - if mt then - if list[mt] then - setmetatable(to, list[mt]) - elseif mt.__index and list[mt.__index] then - mt.__index = list[mt.__index] - end - end - destroyTable(from) - end -end - --- @method TryToLoadStandalone --- @brief Attempt to find and load a standalone version of the requested library --- @param major A string representing the major version --- @return If library is found, return values from the call to LoadAddOn are returned --- If the library has been requested previously, nil is returned. -local function TryToLoadStandalone(major) - if not AceLibrary.scannedlibs then AceLibrary.scannedlibs = {} end - if AceLibrary.scannedlibs[major] then return end - - AceLibrary.scannedlibs[major] = true - - local name, _, _, enabled, loadable = GetAddOnInfo(major) - if loadable then - return LoadAddOn(name) - end - - for i=1,GetNumAddOns() do - if GetAddOnMetadata(i, "X-AceLibrary-"..major) then - local name, _, _, enabled, loadable = GetAddOnInfo(i) - if loadable then - return LoadAddOn(name) - end - end - end -end - --- @method IsNewVersion --- @brief Obtain whether the supplied version would be an upgrade to the --- current version. This allows for bypass code in library --- declaration. --- @param major A string representing the major version --- @param minor An integer or an svn revision string representing the minor version --- @return whether the supplied version would be newer than what is --- currently available. -function AceLibrary:IsNewVersion(major, minor) - argCheck(self, major, 2, "string") - TryToLoadStandalone(major) - - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `IsNewVersion'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 3, "number") - local data = self.libs[major] - if not data then - return true - end - return data.minor < minor -end - --- @method HasInstance --- @brief Returns whether an instance exists. This allows for optional support of a library. --- @param major A string representing the major version. --- @param minor (optional) An integer or an svn revision string representing the minor version. --- @return Whether an instance exists. -function AceLibrary:HasInstance(major, minor) - argCheck(self, major, 2, "string") - TryToLoadStandalone(major) - - if minor then - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `HasInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 3, "number") - if not self.libs[major] then - return - end - return self.libs[major].minor == minor - end - return self.libs[major] and true -end - --- @method GetInstance --- @brief Returns the library with the given major/minor version. --- @param major A string representing the major version. --- @param minor (optional) An integer or an svn revision string representing the minor version. --- @return The library with the given major/minor version. -function AceLibrary:GetInstance(major, minor) - argCheck(self, major, 2, "string") - TryToLoadStandalone(major) - - local data = self.libs[major] - if not data then - _G.error(("Cannot find a library instance of %s."):format(major), 2) - return - end - if minor then - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #3 to `GetInstance'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 2, "number") - if data.minor ~= minor then - _G.error(("Cannot find a library instance of %s, minor version %d."):format(major, minor), 2) - end - end - return data.instance -end - --- Syntax sugar. AceLibrary("FooBar-1.0") -AceLibrary_mt.__call = AceLibrary.GetInstance - -local donothing = function() end - -local AceEvent - --- @method Register --- @brief Registers a new version of a given library. --- @param newInstance the library to register --- @param major the major version of the library --- @param minor the minor version of the library --- @param activateFunc (optional) A function to be called when the library is --- fully activated. Takes the arguments --- (newInstance [, oldInstance, oldDeactivateFunc]). If --- oldInstance is given, you should probably call --- oldDeactivateFunc(oldInstance). --- @param deactivateFunc (optional) A function to be called by a newer library's --- activateFunc. --- @param externalFunc (optional) A function to be called whenever a new --- library is registered. -function AceLibrary:Register(newInstance, major, minor, activateFunc, deactivateFunc, externalFunc) - argCheck(self, newInstance, 2, "table") - argCheck(self, major, 3, "string") - if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == newInstance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end - if major ~= ACELIBRARY_MAJOR and not major:find("^[%a%-][%a%d%-]*%-%d+%.%d+$") then - _G.error(string.format("Bad argument #3 to `Register'. Must be in the form of \"Name-1.0\". %q is not appropriate", major), 2) - end - if type(minor) == "string" then - local m = svnRevisionToNumber(minor) - if m then - minor = m - else - _G.error(("Bad argument #4 to `Register'. Must be a number or SVN revision string. %q is not appropriate"):format(minor), 2) - end - end - argCheck(self, minor, 4, "number") - if math.floor(minor) ~= minor or minor < 0 then - error(self, "Bad argument #4 to `Register' (integer >= 0 expected, got %s)", minor) - end - argCheck(self, activateFunc, 5, "function", "nil") - argCheck(self, deactivateFunc, 6, "function", "nil") - argCheck(self, externalFunc, 7, "function", "nil") - if not deactivateFunc then - deactivateFunc = donothing - end - local data = self.libs[major] - if not data then - -- This is new - local instance = copyTable(newInstance) - crawlReplace(instance, instance, newInstance) - destroyTable(newInstance) - if AceLibrary == newInstance then - self = instance - AceLibrary = instance - end - self.libs[major] = { - instance = instance, - minor = minor, - deactivateFunc = deactivateFunc, - externalFunc = externalFunc, - } - rawset(instance, 'GetLibraryVersion', function(self) - return major, minor - end) - if not rawget(instance, 'error') then - rawset(instance, 'error', error) - end - if not rawget(instance, 'assert') then - rawset(instance, 'assert', assert) - end - if not rawget(instance, 'argCheck') then - rawset(instance, 'argCheck', argCheck) - end - if not rawget(instance, 'pcall') then - rawset(instance, 'pcall', pcall) - end - addToPositions(instance, major) - if activateFunc then - safecall(activateFunc, instance, nil, nil) -- no old version, so explicit nil - ---[[ if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == instance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end]] - end - - if externalFunc then - for k,data in pairs(self.libs) do - if k ~= major then - safecall(externalFunc, instance, k, data.instance) - end - end - end - - for k,data in pairs(self.libs) do - if k ~= major and data.externalFunc then - safecall(data.externalFunc, data.instance, major, instance) - end - end - if major == "AceEvent-2.0" then - AceEvent = instance - end - if AceEvent then - AceEvent.TriggerEvent(self, "AceLibrary_Register", major, instance) - end - - return instance - end - local instance = data.instance - if minor <= data.minor then - -- This one is already obsolete, raise an error. - _G.error(("Obsolete library registered. %s is already registered at version %d. You are trying to register version %d. Hint: if not AceLibrary:IsNewVersion(%q, %d) then return end"):format(major, data.minor, minor, major, minor), 2) - return - end - -- This is an update - local oldInstance = {} - - addToPositions(newInstance, major) - local isAceLibrary = (AceLibrary == newInstance) - local old_error, old_assert, old_argCheck, old_pcall - if isAceLibrary then - self = instance - AceLibrary = instance - - old_error = instance.error - old_assert = instance.assert - old_argCheck = instance.argCheck - old_pcall = instance.pcall - - self.error = error - self.assert = assert - self.argCheck = argCheck - self.pcall = pcall - end - deepTransfer(instance, newInstance, oldInstance, major) - crawlReplace(instance, instance, newInstance) - local oldDeactivateFunc = data.deactivateFunc - data.minor = minor - data.deactivateFunc = deactivateFunc - data.externalFunc = externalFunc - rawset(instance, 'GetLibraryVersion', function(self) - return major, minor - end) - if not rawget(instance, 'error') then - rawset(instance, 'error', error) - end - if not rawget(instance, 'assert') then - rawset(instance, 'assert', assert) - end - if not rawget(instance, 'argCheck') then - rawset(instance, 'argCheck', argCheck) - end - if not rawget(instance, 'pcall') then - rawset(instance, 'pcall', pcall) - end - if isAceLibrary then - for _,v in pairs(self.libs) do - local i = type(v) == "table" and v.instance - if type(i) == "table" then - if not rawget(i, 'error') or i.error == old_error then - rawset(i, 'error', error) - end - if not rawget(i, 'assert') or i.assert == old_assert then - rawset(i, 'assert', assert) - end - if not rawget(i, 'argCheck') or i.argCheck == old_argCheck then - rawset(i, 'argCheck', argCheck) - end - if not rawget(i, 'pcall') or i.pcall == old_pcall then - rawset(i, 'pcall', pcall) - end - end - end - end - if activateFunc then - safecall(activateFunc, instance, oldInstance, oldDeactivateFunc) - ---[[ if major ~= ACELIBRARY_MAJOR then - for k,v in pairs(_G) do - if v == instance then - geterrorhandler()((debugstack():match("(.-: )in.-\n") or "") .. ("Cannot register library %q. It is part of the global table in _G[%q]."):format(major, k)) - end - end - end]] - else - safecall(oldDeactivateFunc, oldInstance) - end - oldInstance = nil - - if externalFunc then - for k,data in pairs(self.libs) do - if k ~= major then - safecall(externalFunc, instance, k, data.instance) - end - end - end - - return instance -end - -local iter -function AceLibrary:IterateLibraries() - if not iter then - local function iter(t, k) - k = next(t, k) - if not k then - return nil - else - return k, t[k].instance - end - end - end - return iter, self.libs, nil -end - --- @function Activate --- @brief The activateFunc for AceLibrary itself. Called when --- AceLibrary properly registers. --- @param self Reference to AceLibrary --- @param oldLib (optional) Reference to an old version of AceLibrary --- @param oldDeactivate (optional) Function to deactivate the old lib -local function activate(self, oldLib, oldDeactivate) - AceLibrary = self - if not self.libs then - self.libs = oldLib and oldLib.libs or {} - self.scannedlibs = oldLib and oldLib.scannedlibs or {} - end - if not self.positions then - self.positions = oldLib and oldLib.positions or setmetatable({}, { __mode = "k" }) - end - - -- Expose the library in the global environment - _G[ACELIBRARY_MAJOR] = self - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -if not previous then - previous = AceLibrary -end -if not previous.libs then - previous.libs = {} -end -AceLibrary.libs = previous.libs -if not previous.positions then - previous.positions = setmetatable({}, { __mode = "k" }) -end -AceLibrary.positions = previous.positions -AceLibrary:Register(AceLibrary, ACELIBRARY_MAJOR, ACELIBRARY_MINOR, activate)
--- a/libs/AceLocale-2.2/AceLocale-2.2.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,552 +0,0 @@ ---[[ -Name: AceLocale-2.2 -Revision: $Rev$ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceLocale-2.2 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceLocale-2.2 -Description: Localization library for addons to use to handle proper - localization and internationalization. -Dependencies: AceLibrary -License: LGPL v2.1 -]] - -local MAJOR_VERSION = "AceLocale-2.2" -local MINOR_VERSION = "$Revision: 20000 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local AceLocale = {} - -local DEFAULT_LOCALE = "enUS" -local _G = getfenv(0) - -local BASE_TRANSLATIONS, DEBUGGING, TRANSLATIONS, BASE_LOCALE, TRANSLATION_TABLES, REVERSE_TRANSLATIONS, STRICTNESS, DYNAMIC_LOCALES, CURRENT_LOCALE, NAME - -local rawget = rawget -local rawset = rawset -local type = type - -local newRegistries = {} -local scheduleClear - -local lastSelf -local __index = function(self, key) - lastSelf = self - local value = (rawget(self, TRANSLATIONS) or AceLocale.prototype)[key] - rawset(self, key, value) - return value -end - -local __newindex = function(self, k, v) - if type(v) ~= "function" and type(k) ~= "table" then - AceLocale.error(self, "Cannot change the values of an AceLocale instance.") - end - rawset(self, k, v) -end - -local __tostring = function(self) - if type(rawget(self, 'GetLibraryVersion')) == "function" then - return self:GetLibraryVersion() - else - return "AceLocale(" .. self[NAME] .. ")" - end -end - -local function clearCache(self) - if not rawget(self, BASE_TRANSLATIONS) then - return - end - - local cache = self[BASE_TRANSLATIONS] - rawset(self, REVERSE_TRANSLATIONS, nil) - - for k in pairs(self) do - if rawget(cache, k) ~= nil then - self[k] = nil - end - end - rawset(self, 'tmp', true) - self.tmp = nil -end - -local function refixInstance(instance) - if getmetatable(instance) then - setmetatable(instance, nil) - end - local translations = instance[TRANSLATIONS] - if translations then - if getmetatable(translations) then - setmetatable(translations, nil) - end - local baseTranslations = instance[BASE_TRANSLATIONS] - if getmetatable(baseTranslations) then - setmetatable(baseTranslations, nil) - end - if translations == baseTranslations or instance[STRICTNESS] then - setmetatable(instance, { - __index = __index, - __newindex = __newindex, - __tostring = __tostring - }) - - setmetatable(translations, { - __index = AceLocale.prototype - }) - else - setmetatable(instance, { - __index = __index, - __newindex = __newindex, - __tostring = __tostring - }) - - setmetatable(translations, { - __index = baseTranslations, - }) - - setmetatable(baseTranslations, { - __index = AceLocale.prototype, - }) - end - else - setmetatable(instance, { - __index = __index, - __newindex = __newindex, - __tostring = __tostring, - }) - end - clearCache(instance) - newRegistries[instance] = true - scheduleClear() - return instance -end - -function AceLocale:new(name) - self:argCheck(name, 2, "string") - - if self.registry[name] and type(rawget(self.registry[name], 'GetLibraryVersion')) ~= "function" then - return self.registry[name] - end - - AceLocale.registry[name] = refixInstance({ - [STRICTNESS] = false, - [NAME] = name, - }) - newRegistries[AceLocale.registry[name]] = true - return AceLocale.registry[name] -end - -AceLocale.prototype = { class = AceLocale } - -function AceLocale.prototype:EnableDebugging() - if rawget(self, BASE_TRANSLATIONS) then - AceLocale.error(self, "Cannot enable debugging after a translation has been registered.") - end - rawset(self, DEBUGGING, true) -end - -function AceLocale.prototype:EnableDynamicLocales(override) - AceLocale.argCheck(self, override, 2, "boolean", "nil") - if not override and rawget(self, BASE_TRANSLATIONS) then - AceLocale.error(self, "Cannot enable dynamic locales after a translation has been registered.") - end - if not rawget(self, DYNAMIC_LOCALES) then - rawset(self, DYNAMIC_LOCALES, true) - if rawget(self, BASE_LOCALE) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - self[TRANSLATION_TABLES][self[BASE_LOCALE]] = self[BASE_TRANSLATIONS] - self[TRANSLATION_TABLES][self[CURRENT_LOCALE]] = self[TRANSLATIONS] - end - end -end - -function AceLocale.prototype:RegisterTranslations(locale, func) - AceLocale.argCheck(self, locale, 2, "string") - AceLocale.argCheck(self, func, 3, "function") - - if locale == rawget(self, BASE_LOCALE) then - AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) - end - - if rawget(self, BASE_TRANSLATIONS) and GetLocale() ~= locale then - if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - if self[TRANSLATION_TABLES][locale] then - AceLocale.error(self, "Cannot provide the same locale more than once. %q provided twice.", locale) - end - local t = func() - func = nil - if type(t) ~= "table" then - AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) - end - self[TRANSLATION_TABLES][locale] = t - t = nil - end - func = nil - return - end - local t = func() - func = nil - if type(t) ~= "table" then - AceLocale.error(self, "Bad argument #3 to `RegisterTranslations'. function did not return a table. (expected table, got %s)", type(t)) - end - - rawset(self, TRANSLATIONS, t) - if not rawget(self, BASE_TRANSLATIONS) then - rawset(self, BASE_TRANSLATIONS, t) - rawset(self, BASE_LOCALE, locale) - for key,value in pairs(t) do - if value == true then - t[key] = key - end - end - else - for key, value in pairs(self[TRANSLATIONS]) do - if not rawget(self[BASE_TRANSLATIONS], key) then - AceLocale.error(self, "Improper translation exists. %q is likely misspelled for locale %s.", key, locale) - end - if value == true then - AceLocale.error(self, "Can only accept true as a value on the base locale. %q is the base locale, %q is not.", rawget(self, BASE_LOCALE), locale) - end - end - end - rawset(self, CURRENT_LOCALE, locale) - if not rawget(self, 'reverse') then - rawset(self, 'reverse', setmetatable({}, { __index = function(self2, key) - local self = AceLocale.reverseToBase[self2] - if not rawget(self, REVERSE_TRANSLATIONS) then - self:GetReverseTranslation(key) - end - self.reverse = self[REVERSE_TRANSLATIONS] - return self.reverse[key] - end })) - AceLocale.reverseToBase[self.reverse] = self - end - refixInstance(self) - if rawget(self, DEBUGGING) or rawget(self, DYNAMIC_LOCALES) then - if not rawget(self, TRANSLATION_TABLES) then - rawset(self, TRANSLATION_TABLES, {}) - end - self[TRANSLATION_TABLES][locale] = t - end - t = nil -end - -function AceLocale.prototype:SetLocale(locale) - AceLocale.argCheck(self, locale, 2, "string", "boolean") - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `SetLocale' without first calling `EnableDynamicLocales'.") - end - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `SetLocale' without first calling `RegisterTranslations'.") - end - if locale == true then - locale = GetLocale() - if not self[TRANSLATION_TABLES][locale] then - locale = self[BASE_LOCALE] - end - end - - if self[CURRENT_LOCALE] == locale then - return - end - - if not self[TRANSLATION_TABLES][locale] then - AceLocale.error(self, "Locale %q not registered.", locale) - end - - self[TRANSLATIONS] = self[TRANSLATION_TABLES][locale] - self[CURRENT_LOCALE] = locale - refixInstance(self) -end - -function AceLocale.prototype:GetLocale() - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `GetLocale' without first calling `RegisterTranslations'.") - end - return self[CURRENT_LOCALE] -end - -local function iter(t, position) - return (next(t, position)) -end - -function AceLocale.prototype:IterateAvailableLocales() - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `EnableDynamicLocales'.") - end - if not rawget(self, TRANSLATION_TABLES) then - AceLocale.error(self, "Cannot call `IterateAvailableLocales' without first calling `RegisterTranslations'.") - end - return iter, self[TRANSLATION_TABLES], nil -end - -function AceLocale.prototype:HasLocale(locale) - if not rawget(self, DYNAMIC_LOCALES) then - AceLocale.error(self, "Cannot call `HasLocale' without first calling `EnableDynamicLocales'.") - end - AceLocale.argCheck(self, locale, 2, "string") - return rawget(self, TRANSLATION_TABLES) and self[TRANSLATION_TABLES][locale] ~= nil -end - -function AceLocale.prototype:SetStrictness(strict) - AceLocale.argCheck(self, strict, 2, "boolean") - local mt = getmetatable(self) - if not mt then - AceLocale.error(self, "Cannot call `SetStrictness' without a metatable.") - end - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered.") - end - rawset(self, STRICTNESS, strict) - refixInstance(self) -end - -local function initReverse(self) - rawset(self, REVERSE_TRANSLATIONS, setmetatable({}, { __index = function(_, key) - AceLocale.error(self, "Reverse translation for %q does not exist", key) - end })) - local alpha = self[TRANSLATIONS] - local bravo = self[REVERSE_TRANSLATIONS] - for base, localized in pairs(alpha) do - bravo[localized] = base - end -end - -function AceLocale.prototype:GetTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - return self[text] -end - -function AceLocale.prototype:GetStrictTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - local value = rawget(x, text) - if value == nil then - AceLocale.error(self, "Translation %q does not exist for locale %s", text, self[CURRENT_LOCALE]) - end - return value -end - -function AceLocale.prototype:GetReverseTranslation(text) - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - local translation = x[text] - if not translation then - AceLocale.error(self, "Reverse translation for %q does not exist", text) - end - return translation -end - -function AceLocale.prototype:GetIterator() - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - return next, x, nil -end - -function AceLocale.prototype:GetReverseIterator() - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - return next, x, nil -end - -function AceLocale.prototype:HasTranslation(text) - AceLocale.argCheck(self, text, 1, "string", "number") - local x = rawget(self, TRANSLATIONS) - if not x then - AceLocale.error(self, "No translations registered") - end - return rawget(x, text) and true -end - -function AceLocale.prototype:HasReverseTranslation(text) - local x = rawget(self, REVERSE_TRANSLATIONS) - if not x then - if not rawget(self, TRANSLATIONS) then - AceLocale.error(self, "No translations registered") - end - initReverse(self) - x = self[REVERSE_TRANSLATIONS] - end - return rawget(x, text) and true -end - -function AceLocale.prototype:Debug() - if not rawget(self, DEBUGGING) then - return - end - local words = {} - local locales = {"enUS", "deDE", "frFR", "koKR", "zhCN", "zhTW", "esES"} - local localizations = {} - DEFAULT_CHAT_FRAME:AddMessage("--- AceLocale Debug ---") - for _,locale in ipairs(locales) do - if not self[TRANSLATION_TABLES][locale] then - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q not found"):format(locale)) - else - localizations[locale] = self[TRANSLATION_TABLES][locale] - end - end - local localeDebug = {} - for locale, localization in pairs(localizations) do - localeDebug[locale] = {} - for word in pairs(localization) do - if type(localization[word]) == "table" then - if type(words[word]) ~= "table" then - words[word] = {} - end - for bit in pairs(localization[word]) do - if type(localization[word][bit]) == "string" then - words[word][bit] = true - end - end - elseif type(localization[word]) == "string" then - words[word] = true - end - end - end - for word in pairs(words) do - if type(words[word]) == "table" then - for bit in pairs(words[word]) do - for locale, localization in pairs(localizations) do - if not rawget(localization, word) or not localization[word][bit] then - localeDebug[locale][word .. "::" .. bit] = true - end - end - end - else - for locale, localization in pairs(localizations) do - if not rawget(localization, word) then - localeDebug[locale][word] = true - end - end - end - end - for locale, t in pairs(localeDebug) do - if not next(t) then - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q complete"):format(locale)) - else - DEFAULT_CHAT_FRAME:AddMessage(("Locale %q missing:"):format(locale)) - for word in pairs(t) do - DEFAULT_CHAT_FRAME:AddMessage((" %q"):format(word)) - end - end - end - DEFAULT_CHAT_FRAME:AddMessage("--- End AceLocale Debug ---") -end - -setmetatable(AceLocale.prototype, { - __index = function(self, k) - if type(k) ~= "table" and k ~= 0 and k ~= "GetLibraryVersion" and k ~= "error" and k ~= "assert" and k ~= "argCheck" and k ~= "pcall" then -- HACK: remove "GetLibraryVersion" and such later. - AceLocale.error(lastSelf or self, "Translation %q does not exist.", k) - end - return nil - end -}) - -local function activate(self, oldLib, oldDeactivate) - AceLocale = self - - self.frame = oldLib and oldLib.frame or CreateFrame("Frame") - self.registry = oldLib and oldLib.registry or {} - self.BASE_TRANSLATIONS = oldLib and oldLib.BASE_TRANSLATIONS or {} - self.DEBUGGING = oldLib and oldLib.DEBUGGING or {} - self.TRANSLATIONS = oldLib and oldLib.TRANSLATIONS or {} - self.BASE_LOCALE = oldLib and oldLib.BASE_LOCALE or {} - self.TRANSLATION_TABLES = oldLib and oldLib.TRANSLATION_TABLES or {} - self.REVERSE_TRANSLATIONS = oldLib and oldLib.REVERSE_TRANSLATIONS or {} - self.STRICTNESS = oldLib and oldLib.STRICTNESS or {} - self.NAME = oldLib and oldLib.NAME or {} - self.DYNAMIC_LOCALES = oldLib and oldLib.DYNAMIC_LOCALES or {} - self.CURRENT_LOCALE = oldLib and oldLib.CURRENT_LOCALE or {} - self.reverseToBase = oldLib and oldLib.reverseToBase or {} - - BASE_TRANSLATIONS = self.BASE_TRANSLATIONS - DEBUGGING = self.DEBUGGING - TRANSLATIONS = self.TRANSLATIONS - BASE_LOCALE = self.BASE_LOCALE - TRANSLATION_TABLES = self.TRANSLATION_TABLES - REVERSE_TRANSLATIONS = self.REVERSE_TRANSLATIONS - STRICTNESS = self.STRICTNESS - NAME = self.NAME - DYNAMIC_LOCALES = self.DYNAMIC_LOCALES - CURRENT_LOCALE = self.CURRENT_LOCALE - - - local GetTime = GetTime - local timeUntilClear = GetTime() + 5 - scheduleClear = function() - if next(newRegistries) then - self.frame:Show() - timeUntilClear = GetTime() + 5 - end - end - - if not self.registry then - self.registry = {} - else - for name, instance in pairs(self.registry) do - local name = name - local mt = getmetatable(instance) - setmetatable(instance, nil) - instance[NAME] = name - local strict - if instance[STRICTNESS] ~= nil then - strict = instance[STRICTNESS] - elseif instance[TRANSLATIONS] ~= instance[BASE_TRANSLATIONS] then - if getmetatable(instance[TRANSLATIONS]).__index == oldLib.prototype then - strict = true - end - end - instance[STRICTNESS] = strict and true or false - refixInstance(instance) - end - end - - self.frame:SetScript("OnEvent", scheduleClear) - self.frame:SetScript("OnUpdate", function() -- (this, elapsed) - if timeUntilClear - GetTime() <= 0 then - self.frame:Hide() - for k in pairs(newRegistries) do - clearCache(k) - newRegistries[k] = nil - k = nil - end - end - end) - self.frame:UnregisterAllEvents() - self.frame:RegisterEvent("ADDON_LOADED") - self.frame:RegisterEvent("PLAYER_ENTERING_WORLD") - self.frame:Show() - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceLocale, MAJOR_VERSION, MINOR_VERSION, activate)
--- a/libs/AceOO-2.0/AceOO-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,973 +0,0 @@ ---[[ -Name: AceOO-2.0 -Revision: $Rev: 18708 $ -Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team) -Inspired By: Ace 1.x by Turan (turan@gryphon.com) -Website: http://www.wowace.com/ -Documentation: http://www.wowace.com/index.php/AceOO-2.0 -SVN: http://svn.wowace.com/root/trunk/Ace2/AceOO-2.0 -Description: Library to provide an object-orientation framework. -Dependencies: AceLibrary -]] - -local MAJOR_VERSION = "AceOO-2.0" -local MINOR_VERSION = "$Revision: 18708 $" - --- This ensures the code is only executed if the libary doesn't already exist, or is a newer version -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local AceOO = { - error = AceLibrary.error, - argCheck = AceLibrary.argCheck -} - --- @function getuid --- @brief Obtain a unique string identifier for the object in question. --- @param t The object to obtain the uid for. --- @return The uid string. -local function pad(cap) - return string.rep('0', 8 - string.len(cap)) .. cap -end -local function getuid(t) - local mt = getmetatable(t) - setmetatable(t, nil) - local str = tostring(t) - setmetatable(t, mt) - local _,_,cap = string.find(str, '[^:]*: 0x(.*)$') - if cap then return pad(cap) end - _,_,cap = string.find(str, '[^:]*: (.*)$') - if cap then return pad(cap) end -end - -local function getlibrary(o) - if type(o) == "table" then - return o - elseif type(o) == "string" then - if not AceLibrary:HasInstance(o) then - AceOO:error("Library %q does not exist.", o) - end - return AceLibrary(o) - end -end - --- @function Factory --- @brief Construct a factory for the creation of objects. --- @param obj The object whose init method will be called on the new factory --- object. --- @param newobj The object whose init method will be called on the new --- objects that the Factory creates, to initialize them. --- @param (...) Arguments which will be passed to obj.init() in addition --- to the Factory object. --- @return The new factory which creates a newobj when its new method is called, --- or when it is called directly (__call metamethod). -local Factory -do - local arg = {} - local function new(obj, ...) - local t = {} - local uid = getuid(t) - for i = 1, select('#', ...) do - arg[i] = getlibrary(select(i, ...)) - end - obj:init(t, unpack(arg)) - for i = 1, select('#', ...) do - arg[i] = nil - end - t.uid = uid - return t - end - - local function createnew(self, ...) - local o = self.prototype - for i = 1, select('#', ...) do - arg[i] = getlibrary(select(i, ...)) - end - local x = new(o, unpack(arg)) - for i = 1, select('#', ...) do - arg[i] = nil - end - return x - end - - function Factory(obj, newobj, ...) - local t = new(obj, ...) - t.prototype = newobj - t.new = createnew - getmetatable(t).__call = t.new - return t - end -end - - -local function objtostring(self) - if self.ToString then - return self:ToString() - elseif self.GetLibraryVersion then - return (self:GetLibraryVersion()) - elseif self.super then - local s = "Sub-" .. tostring(self.super) - local first = true - if self.interfaces then - for interface in pairs(self.interfaces) do - if first then - s = s .. "(" .. tostring(interface) - first = false - else - s = s .. ", " .. tostring(interface) - end - end - end - if self.mixins then - for mixin in pairs(self.mixins) do - if first then - s = s .. tostring(mixin) - first = false - else - s = s .. ", " .. tostring(mixin) - end - end - end - if first then - if self.uid then - return s .. ":" .. self.uid - else - return s - end - else - return s .. ")" - end - else - return self.uid and 'Subclass:' .. self.uid or 'Subclass' - end -end - --- @table Object --- @brief Base of all objects, including Class. --- --- @method init --- @brief Initialize a new object. --- @param newobject The object to initialize --- @param class The class to make newobject inherit from -local Object -do - Object = {} - function Object:init(newobject, class) - local parent = class or self - if not rawget(newobject, 'uid') then - newobject.uid = getuid(newobject) - end - local mt = { - __index = parent, - __tostring = objtostring, - } - setmetatable(newobject, mt) - end - Object.uid = getuid(Object) - setmetatable(Object, { __tostring = function() return 'Object' end }) -end - -local Interface - -local function validateInterface(object, interface) - if not object.class and object.prototype then - object = object.prototype - end - for k,v in pairs(interface.interface) do - if tostring(type(object[k])) ~= v then - return false - end - end - if interface.superinterfaces then - for superinterface in pairs(interface.superinterfaces) do - if not validateInterface(object, superinterface) then - return false - end - end - end - if type(object.class) == "table" and rawequal(object.class.prototype, object) then - if not object.class.interfaces then - rawset(object.class, 'interfaces', {}) - end - object.class.interfaces[interface] = true - elseif type(object.class) == "table" and type(object.class.prototype) == "table" then - validateInterface(object.class.prototype, interface) - -- check if class is proper, thus preventing future checks. - end - return true -end - --- @function inherits --- @brief Return whether an Object or Class inherits from a given --- parent. --- @param object Object or Class to check --- @param parent Parent to test inheritance from --- @return whether an Object or Class inherits from a given --- parent. -local function inherits(object, parent) - object = getlibrary(object) - if type(parent) == "string" then - if not AceLibrary:HasInstance(parent) then - return false - else - parent = AceLibrary(parent) - end - end - AceOO:argCheck(parent, 2, "table") - if type(object) ~= "table" then - return false - end - local current - if object.class then - current = object.class - else - current = object - end - if type(current) ~= "table" then - return false - end - if rawequal(current, parent) then - return true - end - if parent.class then - while true do - if rawequal(current, Object) then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if rawequal(mixin, parent) then - return true - end - end - end - if current.interfaces then - for interface in pairs(current.interfaces) do - if rawequal(interface, parent) then - return true - end - end - end - current = current.super - if type(current) ~= "table" then - break - end - end - - local isInterface = false - local curr = parent.class - while true do - if rawequal(curr, Object) then - break - elseif rawequal(curr, Interface) then - isInterface = true - break - end - curr = curr.super - if type(curr) ~= "table" then - break - end - end - return isInterface and validateInterface(object, parent) - else - while true do - if rawequal(current, parent) then - return true - elseif rawequal(current, Object) then - return false - end - current = current.super - if type(current) ~= "table" then - return false - end - end - end -end - --- @table Class --- @brief An object factory which sets up inheritence and supports --- 'mixins'. --- --- @metamethod Class call --- @brief Call ClassFactory:new() to create a new class. --- --- @method Class new --- @brief Construct a new object. --- @param (...) Arguments to pass to the object init function. --- @return The new object. --- --- @method Class init --- @brief Initialize a new class. --- @param parent Superclass. --- @param (...) Mixins. --- --- @method Class ToString --- @return A string representing the object, in this case 'Class'. -local initStatus -local Class -local Mixin -local autoEmbed = false -local function traverseInterfaces(bit, total) - if bit.superinterfaces then - for interface in pairs(bit.superinterfaces) do - if not total[interface] then - total[interface] = true - traverseInterfaces(interface, total) - end - end - end -end -local class_new -do - Class = Factory(Object, setmetatable({}, {__index = Object}), Object) - Class.super = Object - - local function protostring(t) - return '<' .. tostring(t.class) .. ' prototype>' - end - local function classobjectstring(t) - if t.ToString then - return t:ToString() - elseif t.GetLibraryVersion then - return (t:GetLibraryVersion()) - else - return '<' .. tostring(t.class) .. ' instance>' - end - end - local function classobjectequal(self, other) - if type(self) == "table" and self.Equals then - return self:Equals(other) - elseif type(other) == "table" and other.Equals then - return other:Equals(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) == 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) == 0 - else - return rawequal(self, other) - end - end - local function classobjectlessthan(self, other) - if type(self) == "table" and self.IsLessThan then - return self:IsLessThan(other) - elseif type(other) == "table" and other.IsLessThanOrEqualTo then - return not other:IsLessThanOrEqualTo(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) < 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) > 0 - elseif type(other) == "table" and other.IsLessThan and other.Equals then - return other:Equals(self) or other:IsLessThan(self) - else - AceOO:error("cannot compare two objects") - end - end - local function classobjectlessthanequal(self, other) - if type(self) == "table" and self.IsLessThanOrEqualTo then - return self:IsLessThanOrEqualTo(other) - elseif type(other) == "table" and other.IsLessThan then - return not other:IsLessThan(self) - elseif type(self) == "table" and self.CompareTo then - return self:CompareTo(other) <= 0 - elseif type(other) == "table" and other.CompareTo then - return other:CompareTo(self) >= 0 - elseif type(self) == "table" and self.IsLessThan and self.Equals then - return self:Equals(other) or self:IsLessThan(other) - else - AceOO:error("cannot compare two incompatible objects") - end - end - local function classobjectadd(self, other) - if type(self) == "table" and self.Add then - return self:Add(other) - else - AceOO:error("cannot add two incompatible objects") - end - end - local function classobjectsub(self, other) - if type(self) == "table" and self.Subtract then - return self:Subtract(other) - else - AceOO:error("cannot subtract two incompatible objects") - end - end - local function classobjectunm(self, other) - if type(self) == "table" and self.UnaryNegation then - return self:UnaryNegation(other) - else - AceOO:error("attempt to negate an incompatible object") - end - end - local function classobjectmul(self, other) - if type(self) == "table" and self.Multiply then - return self:Multiply(other) - else - AceOO:error("cannot multiply two incompatible objects") - end - end - local function classobjectdiv(self, other) - if type(self) == "table" and self.Divide then - return self:Divide(other) - else - AceOO:error("cannot divide two incompatible objects") - end - end - local function classobjectpow(self, other) - if type(self) == "table" and self.Exponent then - return self:Exponent(other) - else - AceOO:error("cannot exponentiate two incompatible objects") - end - end - local function classobjectconcat(self, other) - if type(self) == "table" and self.Concatenate then - return self:Concatenate(other) - else - AceOO:error("cannot concatenate two incompatible objects") - end - end - function class_new(self, ...) - if self.virtual then - AceOO:error("Cannot instantiate a virtual class.") - end - - local o = self.prototype - local newobj = {} - if o.class and o.class.instancemeta then - setmetatable(newobj, o.class.instancemeta) - else - Object:init(newobj, o) - end - - if self.interfaces and not self.interfacesVerified then - -- Verify the interfaces - - for interface in pairs(self.interfaces) do - for field,kind in pairs(interface.interface) do - if tostring(type(newobj[field])) ~= kind then - AceOO:error("Class did not satisfy all interfaces. %q is required to be a %s. It is a %s", field, kind, tostring(type(newobj[field]))) - end - end - end - self.interfacesVerified = true - end - local tmp = initStatus - initStatus = newobj - newobj:init(...) - if initStatus then - initStatus = tmp - AceOO:error("Initialization not completed, be sure to call the superclass's init method.") - return - end - initStatus = tmp - return newobj - end - local classmeta = { - __tostring = objtostring, - __call = function(self, ...) - return self:new(...) - end, - } - function Class:init(newclass, parent, ...) - parent = parent or self - - local total - - if parent.class then - total = { parent, ... } - parent = self - else - total = { ... } - end - if not inherits(parent, Class) then - AceOO:error("Classes must inherit from a proper class") - end - if parent.sealed then - AceOO:error("Cannot inherit from a sealed class") - end - for i,v in ipairs(total) do - if inherits(v, Mixin) and v.class then - if v.__deprecated then - AceOO:error(v.__deprecated) - end - if not newclass.mixins then - newclass.mixins = {} - end - if newclass.mixins[v] then - AceOO:error("Cannot explicitly inherit from the same mixin twice") - end - newclass.mixins[v] = true - elseif inherits(v, Interface) and v.class then - if not newclass.interfaces then - newclass.interfaces = {} - end - if newclass.interfaces[v] then - AceOO:error("Cannot explicitly inherit from the same interface twice") - end - newclass.interfaces[v] = true - else - AceOO:error("Classes can only inherit from one or zero classes and any number of mixins or interfaces") - end - end - if parent.interfaces then - if not newclass.interfaces then - newclass.interfaces = {} - end - for interface in pairs(parent.interfaces) do - newclass.interfaces[interface] = true - end - end - for k in pairs(total) do - total[k] = nil - end - - newclass.super = parent - - newclass.prototype = setmetatable(total, { - __index = parent.prototype, - __tostring = protostring, - }) - total = nil - - newclass.instancemeta = { - __index = newclass.prototype, - __tostring = classobjectstring, - __eq = classobjectequal, - __lt = classobjectlessthan, - __le = classobjectlessthanequal, - __add = classobjectadd, - __sub = classobjectsub, - __unm = classobjectunm, - __mul = classobjectmul, - __div = classobjectdiv, - __pow = classobjectpow, - __concat = classobjectconcat, - } - - setmetatable(newclass, classmeta) - - newclass.new = class_new - - if newclass.mixins then - -- Fold in the mixins - local err, msg - for mixin in pairs(newclass.mixins) do - local ret - autoEmbed = true - ret, msg = pcall(mixin.embed, mixin, newclass.prototype) - autoEmbed = false - if not ret then - err = true - break - end - end - - if err then - local pt = newclass.prototype - for k,v in pairs(pt) do - pt[k] = nil - end - - -- method conflict - AceOO:error(msg) - end - end - - newclass.prototype.class = newclass - - if newclass.interfaces then - for interface in pairs(newclass.interfaces) do - traverseInterfaces(interface, newclass.interfaces) - end - end - if newclass.mixins then - for mixin in pairs(newclass.mixins) do - if mixin.interfaces then - if not newclass.interfaces then - newclass.interfaces = {} - end - for interface in pairs(mixin.interfaces) do - newclass.interfaces[interface] = true - end - end - end - end - end - function Class:ToString() - if type(self.GetLibraryVersion) == "function" then - return (self:GetLibraryVersion()) - else - return "Class" - end - end - - local tmp - function Class.prototype:init() - if rawequal(self, initStatus) then - initStatus = nil - else - AceOO:error("Improper self passed to init. You must do MyClass.super.prototype.init(self, ...)", 2) - end - self.uid = getuid(self) - local current = self.class - while true do - if current == Class then - break - end - if current.mixins then - for mixin in pairs(current.mixins) do - if type(mixin.OnInstanceInit) == "function" then - mixin:OnInstanceInit(self) - end - end - end - current = current.super - end - end -end - - --- @object ClassFactory --- @brief A factory for creating classes. Rarely used directly. -local ClassFactory = Factory(Object, Class, Object) - -function Class:new(...) - local x = ClassFactory:new(...) - if AceOO.classes then - AceOO.classes[x] = true - end - return x -end -getmetatable(Class).__call = Class.new - --- @class Mixin --- @brief A class to create mixin objects, which contain methods that get --- "mixed in" to class prototypes. --- --- @object Mixin prototype --- @brief The prototype that mixin objects inherit their methods from. --- --- @method Mixin prototype embed --- @brief Mix in the methods of our object which are listed in our interface --- to the supplied target table. --- --- @method Mixin prototype init --- @brief Initialize the mixin object. --- @param newobj The new object we're initializing. --- @param interface The interface we implement (the list of methods our --- prototype provides which should be mixed into the target --- table by embed). -do - Mixin = Class() - function Mixin:ToString() - if self.GetLibraryVersion then - return (self:GetLibraryVersion()) - else - return 'Mixin' - end - end - local function _Embed(state, field, target) - field = next(state.export, field) - if field == nil then - return - end - - if rawget(target, field) or (target[field] and target[field] ~= state[field]) then - AceOO:error("Method conflict in attempt to mixin. Field %q", field) - end - - target[field] = state[field] - - local ret,msg = pcall(_Embed, state, field, target) - if not ret then - -- Mix in the next method according to the defined interface. If that - -- fails due to a conflict, re-raise to back out the previous mixed - -- methods. - - target[field] = nil - AceOO:error(msg) - end - end - function Mixin.prototype:embed(target) - if self.__deprecated then - AceOO:error(self.__deprecated) - end - local mt = getmetatable(target) - setmetatable(target, nil) - local err, msg = pcall(_Embed, self, nil, target) - if not err then - setmetatable(target, mt) - AceOO:error(msg) - return - end - if type(self.embedList) == "table" then - self.embedList[target] = true - end - if type(target.class) ~= "table" then - target[self] = true - end - if not autoEmbed and type(self.OnManualEmbed) == "function" then - self:OnManualEmbed(target) - end - setmetatable(target, mt) - end - - function Mixin.prototype:activate(oldLib, oldDeactivate) - if oldLib and oldLib.embedList then - for target in pairs(oldLib.embedList) do - local mt = getmetatable(target) - setmetatable(target, nil) - for field in pairs(oldLib.export) do - target[field] = nil - end - setmetatable(target, mt) - end - self.embedList = oldLib.embedList - for target in pairs(self.embedList) do - self:embed(target) - end - else - self.embedList = setmetatable({}, {__mode="k"}) - end - end - - function Mixin.prototype:init(export, ...) - AceOO:argCheck(export, 2, "table") - for k,v in pairs(export) do - if type(k) ~= "number" then - AceOO:error("All keys to argument #2 must be numbers.") - elseif type(v) ~= "string" then - AceOO:error("All values to argument #2 must be strings.") - end - end - local num = #export - for i = 1, num do - local v = export[i] - export[i] = nil - export[v] = true - end - - local interfaces - if select('#', ...) >= 1 then - interfaces = { ... } - for i,v in ipairs(interfaces) do - v = getlibrary(v) - interfaces[i] = v - if not v.class or not inherits(v, Interface) then - AceOO:error("Mixins can inherit only from interfaces") - end - end - local num = #interfaces - for i = 1, num do - local v = interfaces[i] - interfaces[i] = nil - interfaces[v] = true - end - for interface in pairs(interfaces) do - traverseInterfaces(interface, interfaces) - end - for interface in pairs(interfaces) do - for field,kind in pairs(interface.interface) do - if kind ~= "nil" then - local good = false - for bit in pairs(export) do - if bit == field then - good = true - break - end - end - if not good then - AceOO:error("Mixin does not fully accommodate field %q", field) - end - end - end - end - end - self.super = Mixin.prototype - Mixin.super.prototype.init(self) - self.export = export - self.interfaces = interfaces - end -end - --- @class Interface --- @brief A class to create interfaces, which contain contracts that classes --- which inherit from this must comply with. --- --- @object Interface prototype --- @brief The prototype that interface objects must adhere to. --- --- @method Interface prototype init --- @brief Initialize the mixin object. --- @param interface The interface we contract (the hash of fields forced). --- @param (...) Superinterfaces -do - Interface = Class() - function Interface:ToString() - if self.GetLibraryVersion then - return (self:GetLibraryVersion()) - else - return 'Instance' - end - end - function Interface.prototype:init(interface, ...) - Interface.super.prototype.init(self) - AceOO:argCheck(interface, 2, "table") - for k,v in pairs(interface) do - if type(k) ~= "string" then - AceOO:error("All keys to argument #2 must be numbers.") - elseif type(v) ~= "string" then - AceOO:error("All values to argument #2 must be strings.") - elseif v ~= "nil" and v ~= "string" and v ~= "number" and v ~= "table" and v ~= "function" then - AceOO:error('All values to argument #2 must either be "nil", "string", "number", "table", or "function".') - end - end - if select('#', ...) >= 1 then - self.superinterfaces = { ... } - for i,v in ipairs(self.superinterfaces) do - v = getlibrary(v) - self.superinterfaces[i] = v - if not inherits(v, Interface) or not v.class then - AceOO:error('Cannot provide a non-Interface to inherit from') - end - end - local num = #self.superinterfaces - for i = 1, num do - local v = self.superinterfaces[i] - self.superinterfaces[i] = nil - self.superinterfaces[v] = true - end - end - self.interface = interface - end -end - --- @function Classpool --- @brief Obtain a read only class from our pool of classes, indexed by the --- superclass and mixins. --- @param sc The superclass of the class we want. --- @param (m1..m20) Mixins of the class we want's objects. --- @return A read only class from the class pool. -local Classpool -do - local pool = setmetatable({}, {__mode = 'v'}) - local function newindex(k, v) - AceOO:error('Attempt to modify a read-only class.') - end - local function protonewindex(k, v) - AceOO:error('Attempt to modify a read-only class prototype.') - end - local function ts(bit) - if type(bit) ~= "table" then - return tostring(bit) - elseif getmetatable(bit) and bit.__tostring then - return tostring(bit) - elseif type(bit.GetLibraryVersion) == "function" then - return bit:GetLibraryVersion() - else - return tostring(bit) - end - end - local t = {} - local function getcomplexuid(sc, ...) - if sc then - if sc.uid then - table.insert(t, sc.uid) - else - AceOO:error("%s is not an appropriate class/mixin", ts(sc)) - end - end - for i = 1, select('#', ...) do - local m = select(i, ...) - if m.uid then - table.insert(t, m.uid) - else - AceOO:error("%s is not an appropriate mixin", ts(m)) - end - end - table.sort(t) - local uid = table.concat(t, '') - local num = #t - for i = 1, num do - t[i] = nil - end - return uid - end - local classmeta - local arg = {} - function Classpool(superclass, ...) - local l = getlibrary - superclass = getlibrary(superclass) - arg = { ... } - for i, v in ipairs(arg) do - arg[i] = getlibrary(v) - end - if superclass then - if superclass.class then -- mixin - table.insert(arg, 1, superclass) - superclass = Class - end - else - superclass = Class - end - local key = getcomplexuid(superclass, unpack(arg)) - if not pool[key] then - local class = Class(superclass, unpack(arg)) - if not classmeta then - classmeta = {} - local mt = getmetatable(class) - for k,v in pairs(mt) do - classmeta[k] = v - end - classmeta.__newindex = newindex - end - -- Prevent the user from adding methods to this class. - -- NOTE: I'm not preventing modifications of existing class members, - -- but it's likely that only a truly malicious user will be doing so. - class.sealed = true - setmetatable(class, classmeta) - getmetatable(class.prototype).__newindex = protonewindex - pool[key] = class - end - return pool[key] - end -end - -AceOO.Factory = Factory -AceOO.Object = Object -AceOO.Class = Class -AceOO.Mixin = Mixin -AceOO.Interface = Interface -AceOO.Classpool = Classpool -AceOO.inherits = inherits - --- Library handling bits - -local function activate(self, oldLib, oldDeactivate) - AceOO = self - Factory = self.Factory - Object = self.Object - Class = self.Class - ClassFactory.prototype = Class - Mixin = self.Mixin - Interface = self.Interface - Classpool = self.Classpool - - if oldLib then - self.classes = oldLib.classes - end - if not self.classes then - self.classes = setmetatable({}, {__mode="k"}) - else - for class in pairs(self.classes) do - class.new = class_new - end - end - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(AceOO, MAJOR_VERSION, MINOR_VERSION, activate) -AceOO = AceLibrary(MAJOR_VERSION)
--- a/libs/Dewdrop-2.0/Dewdrop-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2751 +0,0 @@ ---[[ -Name: Dewdrop-2.0 -Revision: $Rev: 19976 $ -Author(s): ckknight (ckknight@gmail.com) -Website: http://ckknight.wowinterface.com/ -Documentation: http://wiki.wowace.com/index.php/Dewdrop-2.0 -SVN: http://svn.wowace.com/root/trunk/DewdropLib/Dewdrop-2.0 -Description: A library to provide a clean dropdown menu interface. -Dependencies: AceLibrary -]] - -local MAJOR_VERSION = "Dewdrop-2.0" -local MINOR_VERSION = "$Revision: 19976 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local Dewdrop = {} - -local CLOSE = "Close" -local CLOSE_DESC = "Close the menu." -local VALIDATION_ERROR = "Validation error." -local RESET_KEYBINDING_DESC = "Hit escape to clear the keybinding." - -if GetLocale() == "deDE" then --- VALIDATION_ERROR = "some message here..." -end - -local function new(...) - local t = {} - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t -end - -local tmp -do - local t = {} - function tmp(...) - for k in pairs(t) do - t[k] = nil - end - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t - end -end -local tmp2 -do - local t = {} - function tmp2(...) - for k in pairs(t) do - t[k] = nil - end - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t - end -end -local levels -local buttons - -local function GetScaledCursorPosition() - local x, y = GetCursorPosition() - local scale = UIParent:GetEffectiveScale() - return x / scale, y / scale -end - -local function StartCounting(self, levelNum) - for i = levelNum, #levels do - if levels[i] then - levels[i].count = 3 - end - end -end - -local function StopCounting(self, level) - for i = level, 1, -1 do - if levels[i] then - levels[i].count = nil - end - end -end - -local function OnUpdate(self, arg1) - for _,level in ipairs(levels) do - if level.count then - level.count = level.count - arg1 - if level.count < 0 then - level.count = nil - self:Close(level.num) - end - end - end -end - -local function CheckDualMonitor(self, frame) - local ratio = GetScreenWidth() / GetScreenHeight() - if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then - local offsetx - if GetCursorPosition() / GetScreenHeight() * 768 < GetScreenWidth() / 2 then - offsetx = GetScreenWidth() / 2 - frame:GetRight() - else - offsetx = GetScreenWidth() / 2 - frame:GetLeft() - end - local point, parent, relativePoint, x, y = frame:GetPoint(1) - frame:SetPoint(point, parent, relativePoint, (x or 0) + offsetx, y or 0) - end -end - -local function CheckSize(self, level) - if not level.buttons then - return - end - local height = 20 - for _, button in ipairs(level.buttons) do - height = height + button:GetHeight() - end - level:SetHeight(height) - local width = 160 - for _, button in ipairs(level.buttons) do - local extra = 1 - if button.hasArrow or button.hasColorSwatch then - extra = extra + 16 - end - if not button.notCheckable then - extra = extra + 24 - end - button.text:SetFont(STANDARD_TEXT_FONT, button.textHeight) - if button.text:GetWidth() + extra > width then - width = button.text:GetWidth() + extra - end - end - level:SetWidth(width + 20) - if level:GetLeft() and level:GetRight() and level:GetTop() and level:GetBottom() and (level:GetLeft() < 0 or level:GetRight() > GetScreenWidth() or level:GetTop() > GetScreenHeight() or level:GetBottom() < 0) then - level:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10) - end - end - end - local dirty = false - if not level:GetRight() then - self:Close() - return - end - if level:GetRight() > GetScreenWidth() and level.lastDirection == "RIGHT" then - level.lastDirection = "LEFT" - dirty = true - elseif level:GetLeft() < 0 and level.lastDirection == "LEFT" then - level.lastDirection = "RIGHT" - dirty = true - end - if level:GetTop() > GetScreenHeight() and level.lastVDirection == "UP" then - level.lastVDirection = "DOWN" - dirty = true - elseif level:GetBottom() < 0 and level.lastVDirection == "DOWN" then - level.lastVDirection = "UP" - dirty = true - end - if dirty then - level:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", level.parent or level:GetParent(), "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", level.parent or level:GetParent(), "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", level.parent or level:GetParent(), "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", level.parent or level:GetParent(), "BOTTOMLEFT", -5, -10) - end - end - end - if level:GetTop() > GetScreenHeight() then - local top = level:GetTop() - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:ClearAllPoints() - level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) + GetScreenHeight() - top) - elseif level:GetBottom() < 0 then - local bottom = level:GetBottom() - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:ClearAllPoints() - level:SetPoint(point, parent, relativePoint, x or 0, (y or 0) - bottom) - end - CheckDualMonitor(self, level) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end -end - -local Open -local OpenSlider -local OpenEditBox -local Refresh -local Clear -local function ReleaseButton(self, level, index) - if not level.buttons then - return - end - if not level.buttons[index] then - return - end - local button = level.buttons[index] - button:Hide() - if button.highlight then - button.highlight:Hide() - end --- button.arrow:SetVertexColor(1, 1, 1) --- button.arrow:SetHeight(16) --- button.arrow:SetWidth(16) - table.remove(level.buttons, index) - table.insert(buttons, button) - for k in pairs(button) do - if k ~= 0 and k ~= "text" and k ~= "check" and k ~= "arrow" and k ~= "colorSwatch" and k ~= "highlight" and k ~= "radioHighlight" then - button[k] = nil - end - end - return true -end - -local function Scroll(self, level, down) - if down then - if level:GetBottom() < 0 then - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:SetPoint(point, parent, relativePoint, x, y + 50) - if level:GetBottom() > 0 then - level:SetPoint(point, parent, relativePoint, x, y + 50 - level:GetBottom()) - end - end - else - if level:GetTop() > GetScreenHeight() then - local point, parent, relativePoint, x, y = level:GetPoint(1) - level:SetPoint(point, parent, relativePoint, x, y - 50) - if level:GetTop() < GetScreenHeight() then - level:SetPoint(point, parent, relativePoint, x, y - 50 + GetScreenHeight() - level:GetTop()) - end - end - end -end - -local sliderFrame -local editBoxFrame - -local function showGameTooltip(this) - if this.tooltipTitle or this.tooltipText then - GameTooltip_SetDefaultAnchor(GameTooltip, this) - local disabled = not this.isTitle and this.disabled - if this.tooltipTitle then - if disabled then - GameTooltip:SetText(this.tooltipTitle, 0.5, 0.5, 0.5, 1) - else - GameTooltip:SetText(this.tooltipTitle, 1, 1, 1, 1) - end - if this.tooltipText then - if disabled then - GameTooltip:AddLine(this.tooltipText, (NORMAL_FONT_COLOR.r + 0.5) / 2, (NORMAL_FONT_COLOR.g + 0.5) / 2, (NORMAL_FONT_COLOR.b + 0.5) / 2, 1) - else - GameTooltip:AddLine(this.tooltipText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1) - end - end - else - if disabled then - GameTooltip:SetText(this.tooltipText, 0.5, 0.5, 0.5, 1) - else - GameTooltip:SetText(this.tooltipText, 1, 1, 1, 1) - end - end - GameTooltip:Show() - end - if this.tooltipFunc then - GameTooltip:SetOwner(this, "ANCHOR_NONE") - GameTooltip:SetPoint("TOPLEFT", this, "TOPRIGHT", 5, 0) - this.tooltipFunc(this.tooltipArg1, this.tooltipArg2, this.tooltipArg3, this.tooltipArg4) - GameTooltip:Show() - end -end - -local numButtons = 0 -local function AcquireButton(self, level) - if not levels[level] then - return - end - level = levels[level] - if not level.buttons then - level.buttons = {} - end - local button - if #buttons == 0 then - numButtons = numButtons + 1 - button = CreateFrame("Button", "Dewdrop20Button" .. numButtons, nil) - button:SetFrameStrata("FULLSCREEN_DIALOG") - button:SetHeight(16) - local highlight = button:CreateTexture(nil, "BACKGROUND") - highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") - button.highlight = highlight - highlight:SetBlendMode("ADD") - highlight:SetAllPoints(button) - highlight:Hide() - local check = button:CreateTexture(nil, "ARTWORK") - button.check = check - check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - check:SetPoint("CENTER", button, "LEFT", 12, 0) - check:SetWidth(24) - check:SetHeight(24) - local radioHighlight = button:CreateTexture(nil, "ARTWORK") - button.radioHighlight = radioHighlight - radioHighlight:SetTexture("Interface\\Buttons\\UI-RadioButton") - radioHighlight:SetAllPoints(check) - radioHighlight:SetBlendMode("ADD") - radioHighlight:SetTexCoord(0.5, 0.75, 0, 1) - radioHighlight:Hide() - button:SetScript("OnEnter", function() - if (sliderFrame and sliderFrame:IsShown() and sliderFrame.mouseDown and sliderFrame.level == this.level.num + 1) or (editBoxFrame and editBoxFrame:IsShown() and editBoxFrame.mouseDown and editBoxFrame.level == this.level.num + 1) then - for i = 1, this.level.num do - Refresh(self, levels[i]) - end - return - end - self:Close(this.level.num + 1) - if not this.disabled then - if this.hasSlider then - OpenSlider(self, this) - elseif this.hasEditBox then - OpenEditBox(self, this) - elseif this.hasArrow then - Open(self, this, nil, this.level.num + 1, this.value) - end - end - if not this.level then -- button reclaimed - return - end - StopCounting(self, this.level.num + 1) - if not this.disabled then - highlight:Show() - if this.isRadio then - button.radioHighlight:Show() - end - end - showGameTooltip(this) - end) - button:SetScript("OnLeave", function() - if not this.selected then - highlight:Hide() - end - button.radioHighlight:Hide() - if this.level then - StartCounting(self, this.level.num) - end - GameTooltip:Hide() - end) - button:SetScript("OnClick", function() - if not this.disabled then - if this.hasColorSwatch then - local func = button.colorFunc - local a1,a2,a3,a4 = button.colorArg1, button.colorArg2, button.colorArg3, button.colorArg4 - local hasOpacity = this.hasOpacity - ColorPickerFrame.func = function() - if func then - local r,g,b = ColorPickerFrame:GetColorRGB() - local a = hasOpacity and 1 - OpacitySliderFrame:GetValue() or nil - if a1 == nil then - func(r, g, b, a) - elseif a2 == nil then - func(a1, r, g, b, a) - elseif a3 == nil then - func(a1, a2, r, g, b, a) - elseif a4 == nil then - func(a1, a2, a3, r, g, b, a) - else - func(a1, a2, a3, a4, r, g, b, a) - end - end - end - ColorPickerFrame.hasOpacity = this.hasOpacity - ColorPickerFrame.opacityFunc = ColorPickerFrame.func - ColorPickerFrame.opacity = 1 - this.opacity - ColorPickerFrame:SetColorRGB(this.r, this.g, this.b) - local r, g, b, a = this.r, this.g, this.b, this.opacity - ColorPickerFrame.cancelFunc = function() - if a1 == nil then - func(r, g, b, a) - elseif a2 == nil then - func(a1, r, g, b, a) - elseif a3 == nil then - func(a1, a2, r, g, b, a) - else - func(a1, a2, a3, r, g, b, a) - end - end - self:Close(1) - ShowUIPanel(ColorPickerFrame) - elseif this.func then - local level = button.level - if type(this.func) == "string" then - self:assert(type(this.arg1[this.func]) == "function", "Cannot call method " .. this.func) - this.arg1[this.func](this.arg1, this.arg2, this.arg3, this.arg4) - else - this.func(this.arg1, this.arg2, this.arg3, this.arg4) - end - if this.closeWhenClicked then - self:Close() - elseif level:IsShown() then - for i = 1, level.num do - Refresh(self, levels[i]) - end - end - elseif this.closeWhenClicked then - self:Close() - end - end - end) - local text = button:CreateFontString(nil, "ARTWORK") - button.text = text - text:SetFontObject(GameFontHighlightSmall) - button.text:SetFont(STANDARD_TEXT_FONT, UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT) - button:SetScript("OnMouseDown", function() - if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then - text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 1 or 25, -1) - end - end) - button:SetScript("OnMouseUp", function() - if not this.disabled and (this.func or this.colorFunc or this.closeWhenClicked) then - text:SetPoint("LEFT", button, "LEFT", this.notCheckable and 0 or 24, 0) - end - end) - local arrow = button:CreateTexture(nil, "ARTWORK") - button.arrow = arrow - arrow:SetPoint("LEFT", button, "RIGHT", -16, 0) - arrow:SetWidth(16) - arrow:SetHeight(16) - arrow:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow") - local colorSwatch = button:CreateTexture(nil, "OVERLAY") - button.colorSwatch = colorSwatch - colorSwatch:SetWidth(20) - colorSwatch:SetHeight(20) - colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch") - local texture = button:CreateTexture(nil, "OVERLAY") - colorSwatch.texture = texture - texture:SetTexture(1, 1, 1) - texture:SetWidth(11.5) - texture:SetHeight(11.5) - texture:Show() - texture:SetPoint("CENTER", colorSwatch, "CENTER") - colorSwatch:SetPoint("RIGHT", button, "RIGHT", 0, 0) - else - button = table.remove(buttons) - end - button:ClearAllPoints() - button:SetParent(level) - button:SetFrameStrata(level:GetFrameStrata()) - button:SetFrameLevel(level:GetFrameLevel() + 1) - button:SetPoint("LEFT", level, "LEFT", 10, 0) - button:SetPoint("RIGHT", level, "RIGHT", -10, 0) - if #level.buttons == 0 then - button:SetPoint("TOP", level, "TOP", 0, -10) - else - button:SetPoint("TOP", level.buttons[#level.buttons], "BOTTOM", 0, 0) - end - button.text:SetPoint("LEFT", button, "LEFT", 24, 0) - button:Show() - button.level = level - table.insert(level.buttons, button) - if not level.parented then - level.parented = true - level:ClearAllPoints() - if level.num == 1 then - if level.parent ~= UIParent then - level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT") - else - level:SetPoint("CENTER", level.parent, "CENTER") - end - else - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPLEFT", level.parent, "TOPRIGHT", 5, 10) - else - level:SetPoint("BOTTOMLEFT", level.parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - level:SetPoint("TOPRIGHT", level.parent, "TOPLEFT", -5, 10) - else - level:SetPoint("BOTTOMRIGHT", level.parent, "BOTTOMLEFT", -5, -10) - end - end - end - level:SetFrameStrata("FULLSCREEN_DIALOG") - end - button:SetAlpha(1) - return button -end - -local numLevels = 0 -local function AcquireLevel(self, level) - if not levels[level] then - for i = #levels + 1, level, -1 do - local i = i - numLevels = numLevels + 1 - local frame = CreateFrame("Button", "Dewdrop20Level" .. numLevels, nil) - if i == 1 then - local old_CloseSpecialWindows = CloseSpecialWindows - function CloseSpecialWindows() - local found = old_CloseSpecialWindows() - if levels[1]:IsShown() then - self:Close() - return 1 - end - return found - end - end - levels[i] = frame - frame.num = i - frame:SetParent(UIParent) - frame:SetFrameStrata("FULLSCREEN_DIALOG") - frame:Hide() - frame:SetWidth(180) - frame:SetHeight(10) - frame:SetFrameLevel(i * 3) - frame:SetScript("OnHide", function() - self:Close(level + 1) - end) - if frame.SetTopLevel then - frame:SetTopLevel(true) - end - frame:EnableMouse(true) - frame:EnableMouseWheel(true) - local backdrop = CreateFrame("Frame", nil, frame) - backdrop:SetAllPoints(frame) - backdrop:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - backdrop:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - backdrop:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - frame:SetScript("OnClick", function() - self:Close(i) - end) - frame:SetScript("OnEnter", function() - StopCounting(self, i) - end) - frame:SetScript("OnLeave", function() - StartCounting(self, i) - end) - frame:SetScript("OnMouseWheel", function() - Scroll(self, frame, arg1 < 0) - end) - if i == 1 then - frame:SetScript("OnUpdate", function() - OnUpdate(self, arg1) - end) - levels[1].lastDirection = "RIGHT" - levels[1].lastVDirection = "DOWN" - else - levels[i].lastDirection = levels[i - 1].lastDirection - levels[i].lastVDirection = levels[i - 1].lastVDirection - end - end - end - local fullscreenFrame = GetFullScreenFrame() - local l = levels[level] - local strata, framelevel = l:GetFrameStrata(), l:GetFrameLevel() - if fullscreenFrame then - l:SetParent(fullscreenFrame) - else - l:SetParent(UIParent) - end - l:SetFrameStrata(strata) - l:SetFrameLevel(framelevel) - l:SetAlpha(1) - return l -end - -local function checkValidate(validateFunc, func, arg1, arg2, arg3) - local text - if arg3 ~= nil then - text = arg3 - elseif arg2 ~= nil then - text = arg2 - else - text = arg1 - end - if not validateFunc(text) then - DEFAULT_CHAT_FRAME:AddMessage("|cffffff7fValidation error: [|r" .. tostring(text) .. "|cffffff7f]|r") - else - func(arg1, arg2, arg3) - end -end - -local function validateOptions(options, position, baseOptions, fromPass) - if not baseOptions then - baseOptions = options - end - if type(options) ~= "table" then - return "Options must be a table.", position - end - local kind = options.type - if type(kind) ~= "string" then - return '"type" must be a string.', position - elseif kind ~= "group" and kind ~= "range" and kind ~= "text" and kind ~= "execute" and kind ~= "toggle" and kind ~= "color" and kind ~= "header" then - return '"type" must either be "range", "text", "group", "toggle", "execute", "color", or "header".', position - end - if options.aliases then - if type(options.aliases) ~= "table" and type(options.aliases) ~= "string" then - return '"alias" must be a table or string', position - end - end - if not fromPass then - if kind == "execute" then - if type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - elseif kind == "range" or kind == "text" or kind == "toggle" then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if kind == "text" and options.get == false then - elseif type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif kind == "group" and options.pass then - if options.pass ~= true then - return '"pass" must be either nil, true, or false', position - end - if not options.func then - if type(options.set) ~= "string" and type(options.set) ~= "function" then - return '"set" must be a string or function', position - end - if type(options.get) ~= "string" and type(options.get) ~= "function" then - return '"get" must be a string or function', position - end - elseif type(options.func) ~= "string" and type(options.func) ~= "function" then - return '"func" must be a string or function', position - end - end - else - if kind == "group" then - return 'cannot have "type" = "group" as a subgroup of a passing group', position - end - end - if options ~= baseOptions then - if kind == "header" then - elseif type(options.desc) ~= "string" then - return '"desc" must be a string', position - elseif options.desc:len() == 0 then - return '"desc" cannot be a 0-length string', position - end - end - if options ~= baseOptions or kind == "range" or kind == "text" or kind == "toggle" or kind == "color" then - if options.type == "header" and not options.cmdName and not options.name then - elseif options.cmdName then - if type(options.cmdName) ~= "string" then - return '"cmdName" must be a string or nil', position - elseif options.cmdName:len() == 0 then - return '"cmdName" cannot be a 0-length string', position - end - if type(options.guiName) ~= "string" then - if not options.guiNameIsMap then - return '"guiName" must be a string or nil', position - end - elseif options.guiName:len() == 0 then - return '"guiName" cannot be a 0-length string', position - end - else - if type(options.name) ~= "string" then - return '"name" must be a string', position - elseif options.name:len() == 0 then - return '"name" cannot be a 0-length string', position - end - end - end - if options.guiNameIsMap then - if type(options.guiNameIsMap) ~= "boolean" then - return '"guiNameIsMap" must be a boolean or nil', position - elseif options.type ~= "toggle" then - return 'if "guiNameIsMap" is true, then "type" must be set to \'toggle\'', position - elseif type(options.map) ~= "table" then - return '"map" must be a table', position - end - end - if options.message and type(options.message) ~= "string" then - return '"message" must be a string or nil', position - end - if options.error and type(options.error) ~= "string" then - return '"error" must be a string or nil', position - end - if options.current and type(options.current) ~= "string" then - return '"current" must be a string or nil', position - end - if options.order then - if type(options.order) ~= "number" or (-1 < options.order and options.order < 0.999) then - return '"order" must be a non-zero number or nil', position - end - end - if options.disabled then - if type(options.disabled) ~= "function" and type(options.disabled) ~= "string" and options.disabled ~= true then - return '"disabled" must be a function, string, or boolean', position - end - end - if options.cmdHidden then - if type(options.cmdHidden) ~= "function" and type(options.cmdHidden) ~= "string" and options.cmdHidden ~= true then - return '"cmdHidden" must be a function, string, or boolean', position - end - end - if options.guiHidden then - if type(options.guiHidden) ~= "function" and type(options.guiHidden) ~= "string" and options.guiHidden ~= true then - return '"guiHidden" must be a function, string, or boolean', position - end - end - if options.hidden then - if type(options.hidden) ~= "function" and type(options.hidden) ~= "string" and options.hidden ~= true then - return '"hidden" must be a function, string, or boolean', position - end - end - if kind == "text" then - if type(options.validate) == "table" then - local t = options.validate - local iTable = nil - for k,v in pairs(t) do - if type(k) == "number" then - if iTable == nil then - iTable = true - elseif not iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - elseif k < 1 or k > #t then - return '"validate" numeric keys must be indexed properly. >= 1 and <= #t', position - end - else - if iTable == nil then - iTable = false - elseif iTable then - return '"validate" must either have all keys be indexed numbers or strings', position - end - end - if type(v) ~= "string" then - return '"validate" values must all be strings', position - end - end - elseif options.validate == "keybinding" then - -- no other checks - else - if type(options.usage) ~= "string" then - return '"usage" must be a string', position - elseif options.validate and type(options.validate) ~= "string" and type(options.validate) ~= "function" then - return '"validate" must be a string, function, or table', position - end - end - elseif kind == "range" then - if options.min or options.max then - if type(options.min) ~= "number" then - return '"min" must be a number', position - elseif type(options.max) ~= "number" then - return '"max" must be a number', position - elseif options.min >= options.max then - return '"min" must be less than "max"', position - end - end - if options.step then - if type(options.step) ~= "number" then - return '"step" must be a number', position - elseif options.step < 0 then - return '"step" must be nonnegative', position - end - end - if options.isPercent and options.isPercent ~= true then - return '"isPercent" must either be nil, true, or false', position - end - elseif kind == "toggle" then - if options.map then - if type(options.map) ~= "table" then - return '"map" must be a table', position - elseif type(options.map[true]) ~= "string" then - return '"map[true]" must be a string', position - elseif type(options.map[false]) ~= "string" then - return '"map[false]" must be a string', position - end - end - elseif kind == "color" then - if options.hasAlpha and options.hasAlpha ~= true then - return '"hasAlpha" must be nil, true, or false', position - end - elseif kind == "group" then - if options.pass and options.pass ~= true then - return '"pass" must be nil, true, or false', position - end - if type(options.args) ~= "table" then - return '"args" must be a table', position - end - for k,v in pairs(options.args) do - if type(k) ~= "string" then - return '"args" keys must be strings', position - elseif k:find("%s") then - return string.format('"args" keys must not include spaces. %q is not appropriate.', k), position - elseif k:len() == 0 then - return '"args" keys must not be 0-length strings.', position - end - if type(v) ~= "table" then - return '"args" values must be tables', position and position .. "." .. k or k - end - local newposition - if position then - newposition = position .. ".args." .. k - else - newposition = "args." .. k - end - local err, pos = validateOptions(v, newposition, baseOptions, options.pass) - if err then - return err, pos - end - end - end - if options.icon and type(options.icon) ~= "string" then - return'"icon" must be a string', position - end - if options.iconWidth or options.iconHeight then - if type(options.iconWidth) ~= "number" or type(options.iconHeight) ~= "number" then - return '"iconHeight" and "iconWidth" must be numbers', position - end - end - if options.iconCoordLeft or options.iconCoordRight or options.iconCoordTop or options.iconCoordBottom then - if type(options.iconCoordLeft) ~= "number" or type(options.iconCoordRight) ~= "number" or type(options.iconCoordTop) ~= "number" or type(options.iconCoordBottom) ~= "number" then - return '"iconCoordLeft", "iconCoordRight", "iconCoordTop", and "iconCoordBottom" must be numbers', position - end - end -end - -local validatedOptions - -local values -local mysort_args -local mysort -local othersort -local othersort_validate - -local baseFunc, currentLevel - -function Dewdrop:FeedAceOptionsTable(options, difference) - self:argCheck(options, 2, "table") - self:argCheck(difference, 3, "nil", "number") - self:assert(currentLevel, "Cannot call `FeedAceOptionsTable' outside of a Dewdrop declaration") - if not difference then - difference = 0 - end - if not validatedOptions then - validatedOptions = {} - end - if not validatedOptions[options] then - local err, position = validateOptions(options) - - if err then - if position then - Dewdrop:error(position .. ": " .. err) - else - Dewdrop:error(err) - end - end - - validatedOptions[options] = true - end - local level = levels[currentLevel] - self:assert(level, "Improper level given") - if not values then - values = {} - else - for k,v in pairs(values) do - values[k] = nil - end - end - - local current = level - while current do - if current.num == difference + 1 then - break - end - table.insert(values, current.value) - current = levels[current.num - 1] - end - - local realOptions = options - local handler = options.handler - local passTable - local passValue - while #values > 0 do - passTable = options.pass and current or nil - local value = table.remove(values) - options = options.args and options.args[value] - if not options then - return - end - handler = options.handler or handler - passValue = passTable and value or nil - end - - if options.type == "group" then - for k in pairs(options.args) do - table.insert(values, k) - end - if not mysort then - mysort = function(a, b) - local alpha, bravo = mysort_args[a], mysort_args[b] - local alpha_order = alpha.order or 100 - local bravo_order = bravo.order or 100 - local alpha_name = alpha.guiName or alpha.name - local bravo_name = bravo.guiName or bravo.name - if alpha_order == bravo_order then - if not alpha_name then - return true - elseif not bravo_name then - return false - else - return alpha_name:upper() < bravo_name:upper() - end - else - if alpha_order < 0 then - if bravo_order > 0 then - return false - end - else - if bravo_order < 0 then - return true - end - end - return alpha_order < bravo_order - end - end - end - mysort_args = options.args - table.sort(values, mysort) - mysort_args = nil - local hasBoth = #values >= 1 and (options.args[values[1]].order or 100) > 0 and (options.args[values[#values]].order or 100) < 0 - local last_order = 1 - for _,k in ipairs(values) do - local v = options.args[k] - local handler = v.handler or handler - if hasBoth and last_order > 0 and (v.order or 100) < 0 then - hasBoth = false - self:AddLine() - end - local hidden, disabled = v.guiHidden or v.hidden, v.disabled - if type(hidden) == "function" then - hidden = hidden() - elseif type(hidden) == "string" then - local f = hidden - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - hidden = handler[f](handler) - if neg then - hidden = not hidden - end - end - if not hidden then - if type(disabled) == "function" then - disabled = disabled() - elseif type(disabled) == "string" then - local f = disabled - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - disabled = handler[f](handler) - if neg then - disabled = not disabled - end - end - local name = (v.guiIconOnly and v.icon) and "" or (v.guiName or v.name) - local desc = v.desc - local iconHeight = v.iconHeight or 16 - local iconWidth = v.iconWidth or 16 - local iconCoordLeft = v.iconCoordLeft - local iconCoordRight = v.iconCoordRight - local iconCoordBottom = v.iconCoordBottom - local iconCoordTop = v.iconCoordTop - local tooltipTitle, tooltipText - tooltipTitle = name - if name ~= desc then - tooltipText = desc - end - if v.type == "toggle" then - local checked - local checked_arg - if type(v.get) == "function" then - checked = v.get(passValue) - checked_arg = checked - else - local f = v.get - local neg = f:match("^~(.-)$") - if neg then - f = neg - end - if not handler[f] then - Dewdrop:error("Handler %q not available", f) - end - checked = handler[f](handler, passValue) - checked_arg = checked - if neg then - checked = not checked - end - end - local func, arg1, arg2, arg3 - if type(v.set) == "function" then - func = v.set - if passValue ~= nil then - arg1 = passValue - arg2 = not checked_arg - else - arg1 = not checked_arg - end - else - if not handler[v.set] then - Dewdrop:error("Handler %q not available", v.set) - end - func = handler[v.set] - arg1 = handler - if passValue ~= nil then - arg2 = passValue - arg3 = not checked_arg - else - arg2 = not checked_arg - end - end - if v.guiNameIsMap then - checked = checked and true or false - name = tostring(v.map and v.map[checked]):gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") - checked = nil - end - self:AddLine( - 'text', name, - 'checked', checked, - 'isRadio', v.isRadio, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'arg3', arg3, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - elseif v.type == "execute" then - local func, arg1, arg2 - if type(v.func) == "function" then - func = v.func - arg1 = passValue - else - if not handler[v.func] then - Dewdrop:error("Handler %q not available", v.func) - end - func = handler[v.func] - arg1 = handler - arg2 = passValue - end - self:AddLine( - 'text', name, - 'checked', checked, - 'func', func, - 'arg1', arg1, - 'arg2', arg2, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "range" then - local sliderValue - if type(v.get) == "function" then - sliderValue = v.get(passValue) - else - if not handler[v.get] then - Dewdrop:error("Handler %q not available", v.get) - end - sliderValue = handler[v.get](handler, passValue) - end - local sliderFunc, sliderArg1, sliderArg2 - if type(v.set) == "function" then - sliderFunc = v.set - sliderArg1 = passValue - else - if not handler[v.set] then - Dewdrop:error("Handler %q not available", v.set) - end - sliderFunc = handler[v.set] - sliderArg1 = handler - sliderArg2 = passValue - end - self:AddLine( - 'text', name, - 'hasArrow', true, - 'hasSlider', true, - 'sliderMin', v.min or 0, - 'sliderMax', v.max or 1, - 'sliderStep', v.step or 0, - 'sliderIsPercent', v.isPercent or false, - 'sliderValue', sliderValue, - 'sliderFunc', sliderFunc, - 'sliderArg1', sliderArg1, - 'sliderArg2', sliderArg2, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "color" then - local r,g,b,a - if type(v.get) == "function" then - r,g,b,a = v.get(passValue) - else - if not handler[v.get] then - Dewdrop:error("Handler %q not available", v.get) - end - r,g,b,a = handler[v.get](handler, passValue) - end - local colorFunc, colorArg1, colorArg2 - if type(v.set) == "function" then - colorFunc = v.set - colorArg1 = passValue - else - if not handler[v.set] then - Dewdrop:error("Handler %q not available", v.set) - end - colorFunc = handler[v.set] - colorArg1 = handler - colorArg2 = passValue - end - self:AddLine( - 'text', name, - 'hasArrow', true, - 'hasColorSwatch', true, - 'r', r, - 'g', g, - 'b', b, - 'opacity', v.hasAlpha and a or nil, - 'hasOpacity', v.hasAlpha, - 'colorFunc', colorFunc, - 'colorArg1', colorArg1, - 'colorArg2', colorArg2, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - elseif v.type == "text" then - if type(v.validate) == "table" then - self:AddLine( - 'text', name, - 'hasArrow', true, - 'value', k, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - else - local editBoxText - if type(v.get) == "function" then - editBoxText = v.get(passValue) - elseif v.get == false then - editBoxText = nil - else - if not handler[v.get] then - Dewdrop:error("Handler %q not available", v.get) - end - editBoxText = handler[v.get](handler, passValue) - end - local editBoxFunc, editBoxArg1, editBoxArg2 - if type(v.set) == "function" then - editBoxFunc = v.set - editBoxArg1 = passValue - else - if not handler[v.set] then - Dewdrop:error("Handler %q not available", v.set) - end - editBoxFunc = handler[v.set] - editBoxArg1 = handler - editBoxArg2 = passValue - end - - local editBoxValidateFunc, editBoxValidateArg1 - - if v.validate and v.validate ~= "keybinding" then - if type(v.validate) == "function" then - editBoxValidateFunc = v.validate - else - if not handler[v.validate] then - Dewdrop:error("Handler %q not available", v.validate) - end - editBoxValidateFunc = handler[v.validate] - editBoxValidateArg1 = handler - end - elseif v.validate then - if tooltipText then - tooltipText = tooltipText .. "\n\n" .. RESET_KEYBINDING_DESC - else - tooltipText = RESET_KEYBINDING_DESC - end - end - - self:AddLine( - 'text', name, - 'hasArrow', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom, - 'hasEditBox', true, - 'editBoxText', editBoxText, - 'editBoxFunc', editBoxFunc, - 'editBoxArg1', editBoxArg1, - 'editBoxArg2', editBoxArg2, - 'editBoxValidateFunc', editBoxValidateFunc, - 'editBoxValidateArg1', editBoxValidateArg1, - 'editBoxIsKeybinding', v.validate == "keybinding", - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText - ) - end - elseif v.type == "group" then - self:AddLine( - 'text', name, - 'hasArrow', true, - 'value', k, - 'disabled', disabled, - 'tooltipTitle', tooltipTitle, - 'tooltipText', tooltipText, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - elseif v.type == "header" then - if name == "" or not name then - self:AddLine( - 'isTitle', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - else - self:AddLine( - 'text', name, - 'isTitle', true, - 'icon', v.icon, - 'iconHeight', iconHeight, - 'iconWidth', iconWidth, - 'iconCoordLeft', iconCoordLeft, - 'iconCoordRight', iconCoordRight, - 'iconCoordTop', iconCoordTop, - 'iconCoordBottom', iconCoordBottom - ) - end - end - end - last_order = v.order or 100 - end - elseif options.type == "text" and type(options.validate) == "table" then - local current - if type(options.get) == "function" then - current = options.get(passValue) - elseif options.get ~= false then - if not handler[options.get] then - Dewdrop:error("Handler %q not available", options.get) - end - current = handler[options.get](handler, passValue) - end - local indexed = true - for k,v in pairs(options.validate) do - if type(k) ~= "number" then - indexed = false - end - table.insert(values, k) - end - if not indexed then - if not othersort then - othersort = function(alpha, bravo) - return othersort_validate[alpha] < othersort_validate[bravo] - end - end - othersort_validate = options.validate - table.sort(values, othersort) - othersort_validate = nil - end - for _,k in ipairs(values) do - local v = options.validate[k] - if type(k) == "number" then - k = v - end - local func, arg1, arg2 - if type(options.set) == "function" then - func = options.set - if passValue ~= nil then - arg1 = passValue - arg2 = k - else - arg1 = k - end - else - if not handler[options.set] then - Dewdrop:error("Handler %q not available", options.set) - end - func = handler[options.set] - arg1 = handler - if passValue ~= nil then - arg2 = passValue - arg3 = k - else - arg2 = k - end - end - local checked = (k == current or (type(k) == "string" and type(current) == "string" and k:lower() == current:lower())) - self:AddLine( - 'text', v, - 'func', not checked and func or nil, - 'arg1', not checked and arg1 or nil, - 'arg2', not checked and arg2 or nil, - 'arg3', not checked and arg3 or nil, - 'isRadio', true, - 'checked', checked, - 'tooltipTitle', options.guiName or options.name, - 'tooltipText', v - ) - end - for k in pairs(values) do - values[k] = nil - end - else - return false - end - return true -end - -function Refresh(self, level) - if type(level) == "number" then - level = levels[level] - end - if not level then - return - end - if baseFunc then - Clear(self, level) - currentLevel = level.num - if type(baseFunc) == "table" then - if currentLevel == 1 then - local handler = baseFunc.handler - if handler then - local name = tostring(handler) - if not name:find('^table:') then - name = name:gsub("|c%x%x%x%x%x%x%x%x(.-)|r", "%1") - self:AddLine( - 'text', name, - 'isTitle', true - ) - end - end --- elseif level.parentText then --- self:AddLine( --- 'text', level.parentText, --- 'tooltipTitle', level.parentTooltipTitle, --- 'tooltipText', level.parentTooltipText, --- 'tooltipFunc', level.parentTooltipFunc, --- 'isTitle', true --- ) - end - self:FeedAceOptionsTable(baseFunc) - if currentLevel == 1 then - self:AddLine( - 'text', CLOSE, - 'tooltipTitle', CLOSE, - 'tooltipText', CLOSE_DESC, - 'closeWhenClicked', true - ) - end - else --- if level.parentText then --- self:AddLine( --- 'text', level.parentText, --- 'tooltipTitle', level.parentTooltipTitle, --- 'tooltipText', level.parentTooltipText, --- 'tooltipFunc', level.parentTooltipFunc, --- 'isTitle', true --- ) --- end - baseFunc(currentLevel, level.value, levels[level.num - 1] and levels[level.num - 1].value, levels[level.num - 2] and levels[level.num - 2].value, levels[level.num - 3] and levels[level.num - 3].value, levels[level.num - 4] and levels[level.num - 4].value) - end - currentLevel = nil - CheckSize(self, level) - end -end - -function Dewdrop:Refresh(level) - self:argCheck(level, 2, "number") - Refresh(self, levels[level]) -end - -function OpenSlider(self, parent) - if not sliderFrame then - sliderFrame = CreateFrame("Frame", nil, nil) - sliderFrame:SetWidth(80) - sliderFrame:SetHeight(170) - sliderFrame:SetScale(UIParent:GetScale()) - sliderFrame:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - sliderFrame:SetFrameStrata("FULLSCREEN_DIALOG") - if sliderFrame.SetTopLevel then - sliderFrame:SetTopLevel(true) - end - sliderFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - sliderFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - sliderFrame:EnableMouse(true) - sliderFrame:Hide() - sliderFrame:SetPoint("CENTER", UIParent, "CENTER") - local slider = CreateFrame("Slider", nil, sliderFrame) - sliderFrame.slider = slider - slider:SetOrientation("VERTICAL") - slider:SetMinMaxValues(0, 1) - slider:SetValueStep(0.01) - slider:SetValue(0.5) - slider:SetWidth(16) - slider:SetHeight(128) - slider:SetPoint("LEFT", sliderFrame, "LEFT", 15, 0) - slider:SetBackdrop(tmp( - 'bgFile', "Interface\\Buttons\\UI-SliderBar-Background", - 'edgeFile', "Interface\\Buttons\\UI-SliderBar-Border", - 'tile', true, - 'edgeSize', 8, - 'tileSize', 8, - 'insets', tmp2( - 'left', 3, - 'right', 3, - 'top', 3, - 'bottom', 3 - ) - )) - local texture = slider:CreateTexture() - slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical") - local text = slider:CreateFontString(nil, "ARTWORK") - sliderFrame.topText = text - text:SetFontObject(GameFontGreenSmall) - text:SetText("100%") - text:SetPoint("BOTTOM", slider, "TOP") - local text = slider:CreateFontString(nil, "ARTWORK") - sliderFrame.bottomText = text - text:SetFontObject(GameFontGreenSmall) - text:SetText("0%") - text:SetPoint("TOP", slider, "BOTTOM") - local text = slider:CreateFontString(nil, "ARTWORK") - sliderFrame.currentText = text - text:SetFontObject(GameFontHighlightSmall) - text:SetText("50%") - text:SetPoint("LEFT", slider, "RIGHT") - text:SetPoint("RIGHT", sliderFrame, "RIGHT", -6, 0) - text:SetJustifyH("CENTER") - local changed = false - local inside = false - slider:SetScript("OnValueChanged", function() - if sliderFrame.changing then - return - end - changed = true - local done = false - if sliderFrame.parent and sliderFrame.parent.sliderFunc then - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - local step = sliderFrame.parent.sliderStep or (max - min) / 100 - local a1,a2,a3,a4 = sliderFrame.parent.sliderArg1, sliderFrame.parent.sliderArg2, sliderFrame.parent.sliderArg3, sliderFrame.parent.sliderArg4 - local value = (1 - slider:GetValue()) * (max - min) + min - if step > 0 then - value = math.floor((value - min) / step + 0.5) * step + min - if value > max then - value = max - elseif value < min then - value = min - end - end - if value == sliderFrame.lastValue then - return - end - sliderFrame.lastValue = value - local text - if a1 == nil then - text = sliderFrame.parent.sliderFunc(value) - elseif a2 == nil then - text = sliderFrame.parent.sliderFunc(a1, value) - elseif a3 == nil then - text = sliderFrame.parent.sliderFunc(a1, a2, value) - elseif a4 == nil then - text = sliderFrame.parent.sliderFunc(a1, a2, a3, value) - else - text = sliderFrame.parent.sliderFunc(a1, a2, a3, a4, value) - end - if text then - sliderFrame.currentText:SetText(text) - done = true - end - end - if not done then - local min = sliderFrame.parent.sliderMin or 0 - local max = sliderFrame.parent.sliderMax or 1 - local step = sliderFrame.parent.sliderStep or (max - min) / 100 - local value = (1 - slider:GetValue()) * (max - min) + min - if step > 0 then - value = math.floor((value - min) / step + 0.5) * step + min - if value > max then - value = max - elseif value < min then - value = min - end - end - if sliderFrame.parent.sliderIsPercent then - sliderFrame.currentText:SetText(string.format("%.0f%%", value * 100)) - else - if step < 0.1 then - sliderFrame.currentText:SetText(string.format("%.2f", value)) - elseif step < 1 then - sliderFrame.currentText:SetText(string.format("%.1f", value)) - else - sliderFrame.currentText:SetText(string.format("%.0f", value)) - end - end - end - end) - sliderFrame:SetScript("OnEnter", function() - StopCounting(self, sliderFrame.level) - showGameTooltip(sliderFrame.parent) - end) - sliderFrame:SetScript("OnLeave", function() - StartCounting(self, sliderFrame.level) - GameTooltip:Hide() - end) - slider:SetScript("OnMouseDown", function() - sliderFrame.mouseDown = true - GameTooltip:Hide() - end) - slider:SetScript("OnMouseUp", function() - sliderFrame.mouseDown = false - if changed--[[ and not inside]] then - local parent = sliderFrame.parent - local sliderFunc = parent.sliderFunc - for i = 1, sliderFrame.level - 1 do - Refresh(self, levels[i]) - end - local newParent - for _,button in ipairs(levels[sliderFrame.level-1].buttons) do - if button.sliderFunc == sliderFunc then - newParent = button - break - end - end - if newParent then - OpenSlider(self, newParent) - else - sliderFrame:Hide() - end - end - if inside then - showGameTooltip(sliderFrame.parent) - end - end) - slider:SetScript("OnEnter", function() - inside = true - StopCounting(self, sliderFrame.level) - showGameTooltip(sliderFrame.parent) - end) - slider:SetScript("OnLeave", function() - inside = false - StartCounting(self, sliderFrame.level) - GameTooltip:Hide() - if changed and not sliderFrame.mouseDown then - local parent = sliderFrame.parent - local sliderFunc = parent.sliderFunc - for i = 1, sliderFrame.level - 1 do - Refresh(self, levels[i]) - end - local newParent - for _,button in ipairs(levels[sliderFrame.level-1].buttons) do - if button.sliderFunc == sliderFunc then - newParent = button - break - end - end - if newParent then - OpenSlider(self, newParent) - else - sliderFrame:Hide() - end - end - end) - end - sliderFrame.parent = parent - sliderFrame.level = parent.level.num + 1 - sliderFrame.parentValue = parent.level.value - sliderFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) - sliderFrame.slider:SetFrameLevel(sliderFrame:GetFrameLevel() + 1) - sliderFrame.changing = true - if not parent.sliderMin or not parent.sliderMax then - return - end - - if parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - - sliderFrame:SetClampedToScreen(false) - if not parent.sliderValue then - parent.sliderValue = (parent.sliderMin + parent.sliderMax) / 2 - end - sliderFrame.slider:SetValue(1 - (parent.sliderValue - parent.sliderMin) / (parent.sliderMax - parent.sliderMin)) - sliderFrame.changing = false - sliderFrame.bottomText:SetText(parent.sliderMinText or "0") - sliderFrame.topText:SetText(parent.sliderMaxText or "1") - local text - if parent.sliderFunc then - local a1,a2,a3,a4 = parent.sliderArg1, parent.sliderArg2, parent.sliderArg3, parent.sliderArg4 - if a1 == nil then - text = parent.sliderFunc(parent.sliderValue) - elseif a2 == nil then - text = parent.sliderFunc(a1, parent.sliderValue) - elseif a3 == nil then - text = parent.sliderFunc(a1, a2, parent.sliderValue) - elseif a4 == nil then - text = parent.sliderFunc(a1, a2, a3, parent.sliderValue) - else - text = parent.sliderFunc(a1, a2, a3, a4, parent.sliderValue) - end - end - if text then - sliderFrame.currentText:SetText(text) - elseif parent.sliderIsPercent then - sliderFrame.currentText:SetText(string.format("%.0f%%", parent.sliderValue * 100)) - else - sliderFrame.currentText:SetText(parent.sliderValue) - end - - sliderFrame.lastValue = parent.sliderValue - - local level = parent.level - sliderFrame:Show() - sliderFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - local dirty - if level.lastDirection == "RIGHT" then - if sliderFrame:GetRight() > GetScreenWidth() then - level.lastDirection = "LEFT" - dirty = true - end - elseif sliderFrame:GetLeft() < 0 then - level.lastDirection = "RIGHT" - dirty = true - end - if level.lastVDirection == "DOWN" then - if sliderFrame:GetBottom() < 0 then - level.lastVDirection = "UP" - dirty = true - end - elseif sliderFrame:GetTop() > GetScreenWidth() then - level.lastVDirection = "DOWN" - dirty = true - end - if dirty then - sliderFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - sliderFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - sliderFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - sliderFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - local left, bottom = sliderFrame:GetLeft(), sliderFrame:GetBottom() - sliderFrame:ClearAllPoints() - sliderFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end - sliderFrame:SetClampedToScreen(true) -end - -function OpenEditBox(self, parent) - if not editBoxFrame then - editBoxFrame = CreateFrame("Frame", nil, nil) - editBoxFrame:SetWidth(200) - editBoxFrame:SetHeight(40) - editBoxFrame:SetScale(UIParent:GetScale()) - editBoxFrame:SetBackdrop(tmp( - 'bgFile', "Interface\\Tooltips\\UI-Tooltip-Background", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'insets', tmp2( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ), - 'tileSize', 16, - 'edgeSize', 16 - )) - editBoxFrame:SetFrameStrata("FULLSCREEN_DIALOG") - if editBoxFrame.SetTopLevel then - editBoxFrame:SetTopLevel(true) - end - editBoxFrame:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b) - editBoxFrame:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b) - editBoxFrame:EnableMouse(true) - editBoxFrame:Hide() - editBoxFrame:SetPoint("CENTER", UIParent, "CENTER") - - local editBox = CreateFrame("EditBox", nil, editBoxFrame) - editBoxFrame.editBox = editBox - editBox:SetFontObject(ChatFontNormal) - editBox:SetWidth(160) - editBox:SetHeight(13) - editBox:SetPoint("CENTER", editBoxFrame, "CENTER", 0, 0) - - local left = editBox:CreateTexture(nil, "BACKGROUND") - left:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Left") - left:SetTexCoord(0, 100 / 256, 0, 1) - left:SetWidth(100) - left:SetHeight(32) - left:SetPoint("LEFT", editBox, "LEFT", -10, 0) - local right = editBox:CreateTexture(nil, "BACKGROUND") - right:SetTexture("Interface\\ChatFrame\\UI-ChatInputBorder-Right") - right:SetTexCoord(156/256, 1, 0, 1) - right:SetWidth(100) - right:SetHeight(32) - right:SetPoint("RIGHT", editBox, "RIGHT", 10, 0) - - editBox:SetScript("OnEnterPressed", function() - if editBoxFrame.parent and editBoxFrame.parent.editBoxValidateFunc then - local a1,a2,a3,a4 = editBoxFrame.parent.editBoxValidateArg1, editBoxFrame.parent.editBoxValidateArg2, editBoxFrame.parent.editBoxValidateArg3, editBoxFrame.parent.editBoxValidateArg4 - - local t = editBox.realText or editBox:GetText() or "" - local result - if a1 == nil then - result = editBoxFrame.parent.editBoxValidateFunc(t) - elseif a2 == nil then - result = editBoxFrame.parent.editBoxValidateFunc(a1, t) - elseif a3 == nil then - result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, t) - elseif a4 == nil then - result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, t) - else - result = editBoxFrame.parent.editBoxValidateFunc(a1, a2, a3, a4, t) - end - if not result then - UIErrorsFrame:AddMessage(VALIDATION_ERROR, 1, 0, 0) - return - end - end - if editBoxFrame.parent and editBoxFrame.parent.editBoxFunc then - local a1,a2,a3,a4 = editBoxFrame.parent.editBoxArg1, editBoxFrame.parent.editBoxArg2, editBoxFrame.parent.editBoxArg3, editBoxFrame.parent.editBoxArg4 - local t - if editBox.realText ~= "NONE" then - t = editBox.realText or editBox:GetText() or "" - end - if a1 == nil then - editBoxFrame.parent.editBoxFunc(t) - elseif a2 == nil then - editBoxFrame.parent.editBoxFunc(a1, t) - elseif a3 == nil then - editBoxFrame.parent.editBoxFunc(a1, a2, t) - elseif a4 == nil then - editBoxFrame.parent.editBoxFunc(a1, a2, a3, t) - else - editBoxFrame.parent.editBoxFunc(a1, a2, a3, a4, t) - end - end - self:Close(editBoxFrame.level) - for i = 1, editBoxFrame.level - 1 do - Refresh(self, levels[i]) - end - end) - editBox:SetScript("OnEscapePressed", function() - self:Close(editBoxFrame.level) - end) - local changing = false - local skipNext = false - - function editBox:SpecialSetText(text) - local oldText = editBox:GetText() or "" - if not text then - text = "" - end - if text ~= oldText then - changing = true - self:SetText(text) - changing = false - skipNext = true - end - end - - editBox:SetScript("OnTextChanged", function() - if skipNext then - skipNext = false - elseif not changing and editBoxFrame.parent and editBoxFrame.parent.editBoxChangeFunc then - local a1,a2,a3,a4 = editBoxFrame.parent.editBoxChangeArg1, editBoxFrame.parent.editBoxChangeArg2, editBoxFrame.parent.editBoxChangeArg3, editBoxFrame.parent.editBoxChangeArg4 - local t - if editBox.realText ~= "NONE" then - t = editBox.realText or editBox:GetText() or "" - end - local text - if a1 == nil then - text = editBoxFrame.parent.editBoxChangeFunc(t) - elseif a2 == nil then - text = editBoxFrame.parent.editBoxChangeFunc(a1, t) - elseif a3 == nil then - text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, t) - elseif a4 == nil then - text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, t) - else - text = editBoxFrame.parent.editBoxChangeFunc(a1, a2, a3, a4, t) - end - if text then - editBox:SpecialSetText(text) - end - end - end) - editBoxFrame:SetScript("OnEnter", function() - StopCounting(self, editBoxFrame.level) - showGameTooltip(editBoxFrame.parent) - end) - editBoxFrame:SetScript("OnLeave", function() - StartCounting(self, editBoxFrame.level) - GameTooltip:Hide() - end) - editBox:SetScript("OnEnter", function() - StopCounting(self, editBoxFrame.level) - showGameTooltip(editBoxFrame.parent) - end) - editBox:SetScript("OnLeave", function() - StartCounting(self, editBoxFrame.level) - GameTooltip:Hide() - end) - editBoxFrame:SetScript("OnKeyDown", function() - if not editBox.keybinding then - return - end - local arg1 = arg1 - local screenshotKey = GetBindingKey("SCREENSHOT") - if screenshotKey and arg1 == screenshotKey then - Screenshot() - return - end - - if arg1 == "LeftButton" then - arg1 = "BUTTON1" - elseif arg1 == "RightButton" then - arg1 = "BUTTON2" - elseif arg1 == "MiddleButton" then - arg1 = "BUTTON3" - elseif arg1 == "Button4" then - arg1 = "BUTTON4" - elseif arg1 == "Button5" then - arg1 = "BUTTON5" - end - if arg1 == "BUTTON1" or arg1 == "BUTTON2" or arg1 == "UNKNOWN" then - return - elseif arg1 == "SHIFT" or arg1 == "CTRL" or arg1 == "ALT" then - return - elseif arg1 == "ENTER" then - return editBox:GetScript("OnEnterPressed")() - elseif arg1 == "ESCAPE" then - if editBox.realText == "NONE" then - return editBox:GetScript("OnEscapePressed")() - else - editBox:SpecialSetText(NONE or "NONE") - editBox.realText = "NONE" - return - end - end - local s = GetBindingText(arg1, "KEY_") - local real = arg1 - if IsShiftKeyDown() then - s = "SHIFT-" .. s - real = "SHIFT-" .. real - end - if IsControlKeyDown() then - s = "CTRL-" .. s - real = "CTRL-" .. real - end - if IsAltKeyDown() then - s = "ALT-" .. s - real = "ALT-" .. real - end - if editBox:GetText() ~= s then - editBox:SpecialSetText(s) - editBox.realText = real - return editBox:GetScript("OnTextChanged")() - end - end) - editBoxFrame:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) - editBox:SetScript("OnMouseDown", editBoxFrame:GetScript("OnKeyDown")) - end - editBoxFrame.parent = parent - editBoxFrame.level = parent.level.num + 1 - editBoxFrame.parentValue = parent.level.value - editBoxFrame:SetFrameLevel(parent.level:GetFrameLevel() + 3) - editBoxFrame.editBox:SetFrameLevel(editBoxFrame:GetFrameLevel() + 1) - editBoxFrame.editBox.realText = nil - editBoxFrame:SetClampedToScreen(false) - - if parent.editBoxIsKeybinding then - local s = parent.editBoxText - editBoxFrame.editBox.realText = s - if s and s ~= "" then - local alpha,bravo = s:match("^(.+)%-(.+)$") - if not bravo then - alpha = nil - bravo = s - end - bravo = GetBindingText(bravo, "KEY_") - if alpha then - editBoxFrame.editBox:SpecialSetText(alpha:upper() .. "-" .. bravo) - else - editBoxFrame.editBox:SpecialSetText(bravo) - end - else - editBoxFrame.editBox:SpecialSetText(NONE or "NONE") - end - else - editBoxFrame.editBox:SpecialSetText(parent.editBoxText) - end - - editBoxFrame.editBox.keybinding = parent.editBoxIsKeybinding - editBoxFrame.editBox:EnableKeyboard(not parent.editBoxIsKeybinding) - editBoxFrame:EnableKeyboard(parent.editBoxIsKeybinding) - - if parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - - local level = parent.level - editBoxFrame:Show() - editBoxFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - local dirty - if level.lastDirection == "RIGHT" then - if editBoxFrame:GetRight() > GetScreenWidth() then - level.lastDirection = "LEFT" - dirty = true - end - elseif editBoxFrame:GetLeft() < 0 then - level.lastDirection = "RIGHT" - dirty = true - end - if level.lastVDirection == "DOWN" then - if editBoxFrame:GetBottom() < 0 then - level.lastVDirection = "UP" - dirty = true - end - elseif editBoxFrame:GetTop() > GetScreenWidth() then - level.lastVDirection = "DOWN" - dirty = true - end - if dirty then - editBoxFrame:ClearAllPoints() - if level.lastDirection == "RIGHT" then - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPLEFT", parent, "TOPRIGHT", 5, 10) - else - editBoxFrame:SetPoint("BOTTOMLEFT", parent, "BOTTOMRIGHT", 5, -10) - end - else - if level.lastVDirection == "DOWN" then - editBoxFrame:SetPoint("TOPRIGHT", parent, "TOPLEFT", -5, 10) - else - editBoxFrame:SetPoint("BOTTOMRIGHT", parent, "BOTTOMLEFT", -5, -10) - end - end - end - local left, bottom = editBoxFrame:GetLeft(), editBoxFrame:GetBottom() - editBoxFrame:ClearAllPoints() - editBoxFrame:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - if mod(level.num, 5) == 0 then - local left, bottom = level:GetLeft(), level:GetBottom() - level:ClearAllPoints() - level:SetPoint("BOTTOMLEFT", UIParent, "BOTTOMLEFT", left, bottom) - end - editBoxFrame:SetClampedToScreen(true) -end - -function Dewdrop:IsOpen(parent) - self:argCheck(parent, 2, "table", "nil") - return levels[1] and levels[1]:IsShown() and (not parent or parent == levels[1].parent or parent == levels[1]:GetParent()) -end - -function Dewdrop:GetOpenedParent() - return (levels[1] and levels[1]:IsShown()) and (levels[1].parent or levels[1]:GetParent()) -end - -function Open(self, parent, func, level, value, point, relativePoint, cursorX, cursorY) - self:Close(level) - if DewdropLib then - local d = DewdropLib:GetInstance('1.0') - local ret, val = pcall(d, IsOpen, d) - if ret and val then - DewdropLib:GetInstance('1.0'):Close() - end - end - parent:GetCenter() - local frame = AcquireLevel(self, level) - if level == 1 then - frame.lastDirection = "RIGHT" - frame.lastVDirection = "DOWN" - else - frame.lastDirection = levels[level - 1].lastDirection - frame.lastVDirection = levels[level - 1].lastVDirection - end - frame:SetClampedToScreen(false) - frame:SetFrameStrata("FULLSCREEN_DIALOG") - frame:ClearAllPoints() - frame.parent = parent - frame:SetPoint("LEFT", UIParent, "RIGHT", 10000, 0) - frame:Show() - if level == 1 then - baseFunc = func - end - levels[level].value = value --- levels[level].parentText = parent.text and parent.text:GetText() or nil --- levels[level].parentTooltipTitle = parent.tooltipTitle --- levels[level].parentTooltipText = parent.tooltipText --- levels[level].parentTooltipFunc = parent.tooltipFunc - if parent.arrow then --- parent.arrow:SetVertexColor(0.2, 0.6, 0) --- parent.arrow:SetHeight(24) --- parent.arrow:SetWidth(24) - parent.selected = true - parent.highlight:Show() - end - relativePoint = relativePoint or point - Refresh(self, levels[level]) - if point or (cursorX and cursorY) then - frame:ClearAllPoints() - if cursorX and cursorY then - local curX, curY = GetScaledCursorPosition() - if curY < GetScreenHeight() / 2 then - point, relativePoint = "BOTTOM", "BOTTOM" - else - point, relativePoint = "TOP", "TOP" - end - if curX < GetScreenWidth() / 2 then - point, relativePoint = point .. "LEFT", relativePoint .. "RIGHT" - else - point, relativePoint = point .. "RIGHT", relativePoint .. "LEFT" - end - end - frame:SetPoint(point, parent, relativePoint) - if cursorX and cursorY then - local left = frame:GetLeft() - local width = frame:GetWidth() - local bottom = frame:GetBottom() - local height = frame:GetHeight() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "BOTTOM" or point == "TOP" then - if curX < GetScreenWidth() / 2 then - point = point .. "LEFT" - else - point = point .. "RIGHT" - end - elseif point == "CENTER" then - if curX < GetScreenWidth() / 2 then - point = "LEFT" - else - point = "RIGHT" - end - end - local xOffset, yOffset = 0, 0 - if curY > GetScreenHeight() / 2 then - yOffset = -height - end - if curX > GetScreenWidth() / 2 then - xOffset = -width - end - frame:SetPoint(point, parent, relativePoint, curX - left + xOffset, curY - bottom + yOffset) - if level == 1 then - frame.lastDirection = "RIGHT" - end - elseif cursorX then - local left = frame:GetLeft() - local width = frame:GetWidth() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "BOTTOM" or point == "TOP" then - if curX < GetScreenWidth() / 2 then - point = point .. "LEFT" - else - point = point .. "RIGHT" - end - elseif point == "CENTER" then - if curX < GetScreenWidth() / 2 then - point = "LEFT" - else - point = "RIGHT" - end - end - frame:SetPoint(point, parent, relativePoint, curX - left - width / 2, 0) - if level == 1 then - frame.lastDirection = "RIGHT" - end - elseif cursorY then - local bottom = frame:GetBottom() - local height = frame:GetHeight() - local curX, curY = GetScaledCursorPosition() - frame:ClearAllPoints() - relativePoint = relativePoint or point - if point == "LEFT" or point == "RIGHT" then - if curX < GetScreenHeight() / 2 then - point = point .. "BOTTOM" - else - point = point .. "TOP" - end - elseif point == "CENTER" then - if curX < GetScreenHeight() / 2 then - point = "BOTTOM" - else - point = "TOP" - end - end - frame:SetPoint(point, parent, relativePoint, 0, curY - bottom - height / 2) - if level == 1 then - frame.lastDirection = "DOWN" - end - end - if (strsub(point, 1, 3) ~= strsub(relativePoint, 1, 3)) then - if frame:GetBottom() < 0 then - local point, parent, relativePoint, x, y = frame:GetPoint(1) - local change = GetScreenHeight() - frame:GetTop() - local otherChange = -frame:GetBottom() - if otherChange < change then - change = otherChange - end - frame:SetPoint(point, parent, relativePoint, x, y + change) - elseif frame:GetTop() > GetScreenHeight() then - local point, parent, relativePoint, x, y = frame:GetPoint(1) - local change = GetScreenHeight() - frame:GetTop() - local otherChange = -frame:GetBottom() - if otherChange < change then - change = otherChange - end - frame:SetPoint(point, parent, relativePoint, x, y + change) - end - end - end - CheckDualMonitor(self, frame) - frame:SetClampedToScreen(true) - StartCounting(self, level) -end - -function Dewdrop:IsRegistered(parent) - self:argCheck(parent, 2, "table") - return not not self.registry[parent] -end - -function Dewdrop:Register(parent, ...) - self:argCheck(parent, 2, "table") - if self.registry[parent] then - self:Unregister(parent) - end - local info = new(...) - if type(info.children) == "table" then - local err, position = validateOptions(info.children) - - if err then - if position then - Dewdrop:error(position .. ": " .. err) - else - Dewdrop:error(err) - end - end - end - self.registry[parent] = info - if not info.dontHook and not self.onceRegistered[parent] then - if parent:HasScript("OnMouseUp") then - local script = parent:GetScript("OnMouseUp") - parent:SetScript("OnMouseUp", function() - if script then - script() - end - if arg1 == "RightButton" and self.registry[parent] then - if self:IsOpen(parent) then - self:Close() - else - self:Open(parent) - end - end - end) - end - if parent:HasScript("OnMouseDown") then - local script = parent:GetScript("OnMouseDown") - parent:SetScript("OnMouseDown", function() - if script then - script() - end - if self.registry[parent] then - self:Close() - end - end) - end - end - self.onceRegistered[parent] = true -end - -function Dewdrop:Unregister(parent) - self:argCheck(parent, 2, "table") - self.registry[parent] = nil -end - -function Dewdrop:Open(parent, ...) - self:argCheck(parent, 2, "table") - local info - local k1 = ... - if type(k1) == "table" and k1[0] and k1.IsFrameType and self.registry[k1] then - info = tmp() - for k,v in pairs(self.registry[k1]) do - info[k] = v - end - else - info = tmp(...) - if self.registry[parent] then - for k,v in pairs(self.registry[parent]) do - if info[k] == nil then - info[k] = v - end - end - end - end - local point = info.point - local relativePoint = info.relativePoint - local cursorX = info.cursorX - local cursorY = info.cursorY - if type(point) == "function" then - local b - point, b = point(parent) - if b then - relativePoint = b - end - end - if type(relativePoint) == "function" then - relativePoint = relativePoint(parent) - end - Open(self, parent, info.children, 1, nil, point, relativePoint, cursorX, cursorY) -end - -function Clear(self, level) - if level then - if level.buttons then - for i = #level.buttons, 1, -1 do - ReleaseButton(self, level, i) - end - end - end -end - -function Dewdrop:Close(level) - if DropDownList1:IsShown() then - DropDownList1:Hide() - end - if DewdropLib then - local d = DewdropLib:GetInstance('1.0') - local ret, val = pcall(d, IsOpen, d) - if ret and val then - DewdropLib:GetInstance('1.0'):Close() - end - end - self:argCheck(level, 2, "number", "nil") - if not level then - level = 1 - end - if level == 1 and levels[level] then - levels[level].parented = false - end - if level > 1 and levels[level-1].buttons then - local buttons = levels[level-1].buttons - for _,button in ipairs(buttons) do --- button.arrow:SetWidth(16) --- button.arrow:SetHeight(16) - button.selected = nil - button.highlight:Hide() --- button.arrow:SetVertexColor(1, 1, 1) - end - end - if sliderFrame and sliderFrame.level >= level then - sliderFrame:Hide() - end - if editBoxFrame and editBoxFrame.level >= level then - editBoxFrame:Hide() - end - for i = level, #levels do - Clear(self, levels[level]) - levels[i]:Hide() - levels[i]:ClearAllPoints() - levels[i]:SetPoint("CENTER", UIParent, "CENTER") - levels[i].value = nil - end -end - -function Dewdrop:AddLine(...) - local info = tmp(...) - local level = info.level or currentLevel - info.level = nil - local button = AcquireButton(self, level) - if not next(info) then - info.disabled = true - end - button.disabled = info.isTitle or info.notClickable or info.disabled - button.isTitle = info.isTitle - button.notClickable = info.notClickable - if button.isTitle then - button.text:SetFontObject(GameFontNormalSmall) - elseif button.notClickable then - button.text:SetFontObject(GameFontHighlightSmall) - elseif button.disabled then - button.text:SetFontObject(GameFontDisableSmall) - else - button.text:SetFontObject(GameFontHighlightSmall) - end - if info.disabled then - button.arrow:SetDesaturated(true) - button.check:SetDesaturated(true) - else - button.arrow:SetDesaturated(false) - button.check:SetDesaturated(false) - end - if info.textR and info.textG and info.textB then - button.textR = info.textR - button.textG = info.textG - button.textB = info.textB - button.text:SetTextColor(button.textR, button.textG, button.textB) - else - button.text:SetTextColor(button.text:GetFontObject():GetTextColor()) - end - button.notCheckable = info.notCheckable - button.text:SetPoint("LEFT", button, "LEFT", button.notCheckable and 0 or 24, 0) - button.checked = not info.notCheckable and info.checked - button.isRadio = not info.notCheckable and info.isRadio - if info.isRadio then - button.check:Show() - button.check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") - if button.checked then - button.check:SetTexCoord(0.25, 0.5, 0, 1) - button.check:SetVertexColor(1, 1, 1, 1) - else - button.check:SetTexCoord(0, 0.25, 0, 1) - button.check:SetVertexColor(1, 1, 1, 0.5) - end - button.radioHighlight:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") - button.check:SetWidth(16) - button.check:SetHeight(16) - elseif info.icon then - button.check:Show() - button.check:SetTexture(info.icon) - if info.iconWidth and info.iconHeight then - button.check:SetWidth(info.iconWidth) - button.check:SetHeight(info.iconHeight) - else - button.check:SetWidth(16) - button.check:SetHeight(16) - end - if info.iconCoordLeft and info.iconCoordRight and info.iconCoordTop and info.iconCoordBottom then - button.check:SetTexCoord(info.iconCoordLeft, info.iconCoordRight, info.iconCoordTop, info.iconCoordBottom) - elseif info.icon:find("^Interface\\Icons\\") then - button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - button.check:SetTexCoord(0, 1, 0, 1) - end - button.check:SetVertexColor(1, 1, 1, 1) - else - if button.checked then - if info.checkIcon then - button.check:SetWidth(16) - button.check:SetHeight(16) - button.check:SetTexture(info.checkIcon) - if info.checkIcon:find("^Interface\\Icons\\") then - button.check:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - button.check:SetTexCoord(0, 1, 0, 1) - end - else - button.check:SetWidth(24) - button.check:SetHeight(24) - button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - button.check:SetTexCoord(0, 1, 0, 1) - end - button.check:SetVertexColor(1, 1, 1, 1) - else - button.check:SetVertexColor(1, 1, 1, 0) - end - end - if not button.disabled then - button.func = info.func - end - button.hasColorSwatch = info.hasColorSwatch - if button.hasColorSwatch then - button.colorSwatch:Show() - button.colorSwatch.texture:Show() - button.r = info.r or 1 - button.g = info.g or 1 - button.b = info.b or 1 - button.colorSwatch.texture:SetTexture(button.r, button.g, button.b) - button.checked = false - button.func = nil - button.colorFunc = info.colorFunc - button.colorArg1 = info.colorArg1 - button.colorArg2 = info.colorArg2 - button.colorArg3 = info.colorArg3 - button.colorArg4 = info.colorArg4 - button.hasOpacity = info.hasOpacity - button.opacity = info.opacity or 1 - else - button.colorSwatch:Hide() - button.colorSwatch.texture:Hide() - end - button.hasArrow = not button.hasColorSwatch and (info.value or info.hasSlider or info.hasEditBox) and info.hasArrow - if button.hasArrow then - button.arrow:SetAlpha(1) - if info.hasSlider then - button.hasSlider = true - button.sliderMin = info.sliderMin or 0 - button.sliderMax = info.sliderMax or 1 - button.sliderStep = info.sliderStep or 0 - button.sliderIsPercent = info.sliderIsPercent and true or false - button.sliderMinText = info.sliderMinText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMin * 100) or button.sliderMin - button.sliderMaxText = info.sliderMaxText or button.sliderIsPercent and string.format("%.0f%%", button.sliderMax * 100) or button.sliderMax - button.sliderFunc = info.sliderFunc - button.sliderValue = info.sliderValue - button.sliderArg1 = info.sliderArg1 - button.sliderArg2 = info.sliderArg2 - button.sliderArg3 = info.sliderArg3 - button.sliderArg4 = info.sliderArg4 - elseif info.hasEditBox then - button.hasEditBox = true - button.editBoxText = info.editBoxText or "" - button.editBoxFunc = info.editBoxFunc - button.editBoxArg1 = info.editBoxArg1 - button.editBoxArg2 = info.editBoxArg2 - button.editBoxArg3 = info.editBoxArg3 - button.editBoxArg4 = info.editBoxArg4 - button.editBoxChangeFunc = info.editBoxChangeFunc - button.editBoxChangeArg1 = info.editBoxChangeArg1 - button.editBoxChangeArg2 = info.editBoxChangeArg2 - button.editBoxChangeArg3 = info.editBoxChangeArg3 - button.editBoxChangeArg4 = info.editBoxChangeArg4 - button.editBoxValidateFunc = info.editBoxValidateFunc - button.editBoxValidateArg1 = info.editBoxValidateArg1 - button.editBoxValidateArg2 = info.editBoxValidateArg2 - button.editBoxValidateArg3 = info.editBoxValidateArg3 - button.editBoxValidateArg4 = info.editBoxValidateArg4 - button.editBoxIsKeybinding = info.editBoxIsKeybinding - else - button.value = info.value - local l = levels[level+1] - if l and info.value == l.value then --- button.arrow:SetWidth(24) --- button.arrow:SetHeight(24) - button.selected = true - button.highlight:Show() - end - end - else - button.arrow:SetAlpha(0) - end - button.arg1 = info.arg1 - button.arg2 = info.arg2 - button.arg3 = info.arg3 - button.arg4 = info.arg4 - button.closeWhenClicked = info.closeWhenClicked - button.textHeight = info.textHeight or UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT or 10 - local font,_ = button.text:GetFont() - button.text:SetFont(STANDARD_TEXT_FONT or "Fonts\\FRIZQT__.TTF", button.textHeight) - button:SetHeight(button.textHeight + 6) - button.text:SetPoint("RIGHT", button.arrow, (button.hasColorSwatch or button.hasArrow) and "LEFT" or "RIGHT") - button.text:SetJustifyH(info.justifyH or "LEFT") - button.text:SetText(info.text) - button.tooltipTitle = info.tooltipTitle - button.tooltipText = info.tooltipText - button.tooltipFunc = info.tooltipFunc - button.tooltipArg1 = info.tooltipArg1 - button.tooltipArg2 = info.tooltipArg2 - button.tooltipArg3 = info.tooltipArg3 - button.tooltipArg4 = info.tooltipArg4 - if not button.tooltipTitle and not button.tooltipText and not button.tooltipFunc and not info.isTitle then - button.tooltipTitle = info.text - end - if type(button.func) == "string" then - self:assert(type(button.arg1) == "table", "Cannot call method " .. button.func .. " on a non-table") - self:assert(type(button.arg1[button.func]) == "function", "Method " .. button.func .. " nonexistant.") - end -end - -function Dewdrop:InjectAceOptionsTable(handler, options) - self:argCheck(handler, 2, "table") - self:argCheck(options, 3, "table") - if tostring(options.type):lower() ~= "group" then - self:error('Cannot inject into options table argument #3 if its type is not "group"') - end - if options.handler ~= nil and options.handler ~= handler then - self:error("Cannot inject into options table argument #3 if it has a different handler than argument #2") - end - options.handler = handler - local class = handler.class - if not AceLibrary:HasInstance("AceOO-2.0") or not class then - self:error("Cannot retrieve AceOptions tables from a non-object argument #2") - end - while class and class ~= AceLibrary("AceOO-2.0").Class do - if type(class.GetAceOptionsDataTable) == "function" then - local t = class:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - local mixins = class.mixins - if mixins then - for mixin in pairs(mixins) do - if type(mixin.GetAceOptionsDataTable) == "function" then - local t = mixin:GetAceOptionsDataTable(handler) - for k,v in pairs(t) do - if type(options.args) ~= "table" then - options.args = {} - end - if options.args[k] == nil then - options.args[k] = v - end - end - end - end - end - class = class.super - end - return options -end - -local function activate(self, oldLib, oldDeactivate) - Dewdrop = self - if oldLib and oldLib.registry then - self.registry = oldLib.registry - self.onceRegistered = oldLib.onceRegistered - else - self.registry = {} - self.onceRegistered = {} - - local WorldFrame_OnMouseDown = WorldFrame:GetScript("OnMouseDown") - local WorldFrame_OnMouseUp = WorldFrame:GetScript("OnMouseUp") - local oldX, oldY, clickTime - WorldFrame:SetScript("OnMouseDown", function() - oldX,oldY = GetCursorPosition() - clickTime = GetTime() - if WorldFrame_OnMouseDown then - WorldFrame_OnMouseDown() - end - end) - - WorldFrame:SetScript("OnMouseUp", function() - local x,y = GetCursorPosition() - if not oldX or not oldY or not x or not y or not clickTime then - self:Close() - if WorldFrame_OnMouseUp then - WorldFrame_OnMouseUp() - end - return - end - local d = math.abs(x - oldX) + math.abs(y - oldY) - if d <= 5 and GetTime() - clickTime < 0.5 then - self:Close() - end - if WorldFrame_OnMouseUp then - WorldFrame_OnMouseUp() - end - end) - - if hooksecurefunc then - hooksecurefunc(DropDownList1, "Show", function() - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - end) - else - local DropDownList1_Show = DropDownList1.Show - function DropDownList1.Show(DropDownList1) - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - DropDownList1_Show(DropDownList1) - end - end - - if hooksecurefunc then - hooksecurefunc("HideDropDownMenu", function() - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - end) - else - local old_HideDropDownMenu = HideDropDownMenu - function HideDropDownMenu(num) - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - old_HideDropDownMenu(num) - end - end - - if hooksecurefunc then - hooksecurefunc("CloseDropDownMenus", function() - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - end) - else - local old_CloseDropDownMenus = CloseDropDownMenus - function CloseDropDownMenus(num) - if levels[1] and levels[1]:IsVisible() then - self:Close() - end - old_CloseDropDownMenus(num) - end - end - end - levels = {} - buttons = {} - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(Dewdrop, MAJOR_VERSION, MINOR_VERSION, activate)
--- a/libs/FuBarPlugin-2.0/FuBarPlugin-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1521 +0,0 @@ ---[[ -Name: FuBarPlugin-2.0 -Revision: $Rev: 19941 $ -Author: Cameron Kenneth Knight (ckknight@gmail.com) -Website: http://wiki.wowace.com/index.php/FuBarPlugin-2.0 -Documentation: http://wiki.wowace.com/index.php/FuBarPlugin-2.0 -SVN: svn://svn.wowace.com/root/branches/FuBar/FuBarPlugin-2.0/FuBarPlugin-2.0/ -Description: Plugin for FuBar. -Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, Tablet-2.0, Dewdrop-2.0 -]] - -local MAJOR_VERSION = "FuBarPlugin-2.0" -local MINIMAPCONTAINER_MAJOR_VERSION = "FuBarPlugin-MinimapContainer-2.0" -local MINOR_VERSION = "$Revision: 19941 $" - --- This ensures the code is only executed if the libary doesn't already exist, or is a newer version -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end - -local AceEvent = AceLibrary:HasInstance("AceEvent-2.0") and AceLibrary("AceEvent-2.0") -local Tablet = AceLibrary:HasInstance("Tablet-2.0") and AceLibrary("Tablet-2.0") -local Dewdrop = AceLibrary:HasInstance("Dewdrop-2.0") and AceLibrary("Dewdrop-2.0") - -local epsilon = 1e-5 -local _G = getfenv(0) - -local SHOW_ICON = "Show icon" -local SHOW_ICON_DESC = "Show the plugins icon on the panel." -local SHOW_TEXT = "Show text" -local SHOW_TEXT_DESC = "Show the plugins text on the panel." -local SHOW_COLORED_TEXT = "Show colored text" -local SHOW_COLORED_TEXT_DESC = "Allow the plugin to color its text." -local DETACH_TOOLTIP = "Detach tooltip" -local DETACH_TOOLTIP_DESC = "Detach the tooltip from the panel." -local LOCK_TOOLTIP = "Lock tooltip" -local LOCK_TOOLTIP_DESC = "Lock the tooltips position. When the tooltip is locked, you must use Alt to access it with your mouse." -local POSITION = "Position" -local POSITION_DESC = "Position the plugin on the panel." -local POSITION_LEFT = "Left" -local POSITION_RIGHT = "Right" -local POSITION_CENTER = "Center" -local ATTACH_TO_MINIMAP = "Attach to minimap" -local ATTACH_TO_MINIMAP_DESC = "Attach the plugin to the minimap instead of the panel." -local HIDE_FUBAR_PLUGIN = "Hide plugin" -local HIDE_FUBAR_PLUGIN_CMD = "Hidden" -local HIDE_FUBAR_PLUGIN_DESC = "Hide the plugin from the panel or minimap, leaving the addon running." -local OTHER = "Other" -local CLOSE = "Close" -local CLOSE_DESC = "Close the menu." - -if GetLocale() == "koKR" then - SHOW_ICON = "아이콘 표시" - SHOW_ICON_DESC = "패널에 플러그인 아이콘을 표시합니다." - SHOW_TEXT = "텍스트 표시" - SHOW_TEXT_DESC = "페널에 플러그인 텍스트를 표시합니다." - SHOW_COLORED_TEXT = "색상화된 텍스트 표시" - SHOW_COLORED_TEXT_DESC = "플러그인의 텍스트 색상을 허용합니다." - DETACH_TOOLTIP = "툴팁 분리" - DETACH_TOOLTIP_DESC = "패널에서 툴팁을 분리 합니다." - LOCK_TOOLTIP = "툴팁 고정" - LOCK_TOOLTIP_DESC = "툴팁 위치를 고정합니다." - POSITION = "위치" - POSITION_DESC = "패널에서 플러그인의 위치를 설정합니다." - POSITION_LEFT = "왼쪽" - POSITION_RIGHT = "오른쪽" - POSITION_CENTER = "가운데" - ATTACH_TO_MINIMAP = "미니맵에 표시" - ATTACH_TO_MINIMAP_DESC = "플러그인을 패널 대신 미니맵에 표시합니다." - HIDE_FUBAR_PLUGIN = "FuBar 플러그인 숨기기" - HIDE_FUBAR_PLUGIN_CMD = "숨겨짐" - HIDE_FUBAR_PLUGIN_DESC = "패널에서 플러그인을 숨깁니다." - OTHER = "기타" - CLOSE = "닫기" - CLOSE_DESC = "메뉴 닫기." -elseif GetLocale() == "deDE" then - SHOW_ICON = "Zeige Icon" - SHOW_ICON_DESC = "Zeige das Plugin-Icon auf der Leiste." - SHOW_TEXT = "Zeige Text" - SHOW_TEXT_DESC = "Zeige den Plugin-Text auf der Leiste." - SHOW_COLORED_TEXT = "Zeige gef\195\164rbten Text" - SHOW_COLORED_TEXT_DESC = "Dem Plugin erlauben sein Text zu f\195\164rben." - DETACH_TOOLTIP = "Tooltip l\195\182sen" - DETACH_TOOLTIP_DESC = "Tooltip von der Leiste l\195\182sen." - LOCK_TOOLTIP = "Tooltip sperren" - LOCK_TOOLTIP_DESC = "Tooltip an der Position sperren." - POSITION = "Position" - POSITION_DESC = "Positioniert das Plugin auf der Leiste." - POSITION_LEFT = "Links" - POSITION_RIGHT = "Rechts" - POSITION_CENTER = "Mitte" - ATTACH_TO_MINIMAP = "An der Minimap anbringen" - ATTACH_TO_MINIMAP_DESC = "Bringt das Plugin an der Minimap anstelle der Leiste an." - HIDE_FUBAR_PLUGIN = "Versteckt das FuBar Plugin" - HIDE_FUBAR_PLUGIN_CMD = "Verstecken" - HIDE_FUBAR_PLUGIN_DESC = "Versteckt das Plugin von der Leiste." -elseif GetLocale() == "frFR" then - SHOW_ICON = "Afficher l'ic\195\180ne" - SHOW_ICON_DESC = "Afficher l'ic\195\180ne du plugin sur le panneau." - SHOW_TEXT = "Afficher le texte" - SHOW_TEXT_DESC = "Afficher le texte du plugin sur le panneau." - SHOW_COLORED_TEXT = "Afficher la couleur du texte" - SHOW_COLORED_TEXT_DESC = "Permet au plugin de colorer le texte." - DETACH_TOOLTIP = "D\195\169tacher le tooltip" - DETACH_TOOLTIP_DESC = "Permet de d\195\169tacher le tooltip du panneau." - LOCK_TOOLTIP = "Bloquer le tooltip" - LOCK_TOOLTIP_DESC = "Permet de bloquer le tooltip \195\160 sa position actuelle. Une fois le tooltip bloqu\195\169, vous devez utiliser la touche Alt pour le d\195\169placer avec votre souris." - POSITION = "Position" - POSITION_DESC = "Permet de changer la position du plugin dans le panneau." - POSITION_LEFT = "Gauche" - POSITION_RIGHT = "Droite" - POSITION_CENTER = "Centre" - ATTACH_TO_MINIMAP = "Attacher \195\160 la minicarte" - ATTACH_TO_MINIMAP_DESC = "Attache l'ic\195\180ne du plugin \195\160 la minicarte." - HIDE_FUBAR_PLUGIN = "Masquer le plugin" - HIDE_FUBAR_PLUGIN_CMD = "Masqu\195\169" - HIDE_FUBAR_PLUGIN_DESC = "Permet de masquer compl\195\168tement le plugin du panneau, mais laisse l'addon fonctionner." - OTHER = "Autre" - CLOSE = "Fermer" - CLOSE_DESC = "Ferme le menu." -elseif GetLocale() == "zhCN" then - SHOW_ICON = "显示图标" - SHOW_ICON_DESC = "在面板上显示插件图标." - SHOW_TEXT = "显示文字" - SHOW_TEXT_DESC = "在面板上显示文字标题." - SHOW_COLORED_TEXT = "显示彩色文字" - SHOW_COLORED_TEXT_DESC = "允许插件显示彩色文字." - DETACH_TOOLTIP = "独立提示信息" - DETACH_TOOLTIP_DESC = "从面板上独立提示信息." - LOCK_TOOLTIP = "锁定提示信息" - LOCK_TOOLTIP_DESC = "锁定提示信息位置." - POSITION = "位置" - POSITION_DESC = "插件在面板上的位置." - POSITION_LEFT = "居左" - POSITION_RIGHT = "居右" - POSITION_CENTER = "居中" - ATTACH_TO_MINIMAP = "依附在小地图" - ATTACH_TO_MINIMAP_DESC = "插件图标依附在小地图而不显示在面板上." - HIDE_FUBAR_PLUGIN = "隐藏FuBar插件" - HIDE_FUBAR_PLUGIN_CMD = "Hidden" - HIDE_FUBAR_PLUGIN_DESC = "在面板上隐藏该插件." -elseif GetLocale() == "zhTW" then - SHOW_ICON = "顯示圖示" - SHOW_ICON_DESC = "在面板上顯示插件圖示。" - SHOW_TEXT = "顯示文字" - SHOW_TEXT_DESC = "在面板上顯示文字標題。" - SHOW_COLORED_TEXT = "顯示彩色文字" - SHOW_COLORED_TEXT_DESC = "允許插件顯示彩色文字。" - DETACH_TOOLTIP = "獨立提示訊息" - DETACH_TOOLTIP_DESC = "從面板上獨立提示訊息。" - LOCK_TOOLTIP = "鎖定提示訊息" - LOCK_TOOLTIP_DESC = "鎖定提示訊息位置。" - POSITION = "位置" - POSITION_DESC = "插件在面板上的位置。" - POSITION_LEFT = "靠左" - POSITION_RIGHT = "靠右" - POSITION_CENTER = "置中" - ATTACH_TO_MINIMAP = "依附在小地圖" - ATTACH_TO_MINIMAP_DESC = "插件圖標依附在小地圖而不顯示在面板上。" - HIDE_FUBAR_PLUGIN = "隱藏FuBar插件" - HIDE_FUBAR_PLUGIN_CMD = "Hidden" - HIDE_FUBAR_PLUGIN_DESC = "在面板上隱藏該插件." -end - -local FuBarPlugin = AceLibrary("AceOO-2.0").Mixin { - "GetTitle", - "GetName", - "GetCategory", - "SetFontSize", - "GetFrame", - "Show", - "Hide", - "GetPanel", - "IsTextColored", - "ToggleTextColored", - "IsMinimapAttached", - "ToggleMinimapAttached", - "Update", - "UpdateDisplay", - "UpdateData", - "UpdateText", - "UpdateTooltip", - "SetIcon", - "GetIcon", - "CheckWidth", - "SetText", - "GetText", - "IsIconShown", - "ToggleIconShown", - "ShowIcon", - "HideIcon", - "IsTextShown", - "ToggleTextShown", - "ShowText", - "HideText", - "IsTooltipDetached", - "ToggleTooltipDetached", - "DetachTooltip", - "ReattachTooltip", - "GetDefaultPosition", - "SetPanel", - "IsLoadOnDemand", - "IsDisabled", - "CreateBasicPluginFrame", - "CreatePluginChildFrame", - "OpenMenu", - "AddImpliedMenuOptions", - } - -local good = nil -local function CheckFuBar() - if not good then - good = FuBar and tonumber(string.sub(FuBar.version, 1, 3)) and tonumber(string.sub(FuBar.version, 1, 3)) >= 2 and true - end - return good -end - -function FuBarPlugin:GetTitle() - local name = self.title or self.name - FuBarPlugin:assert(name, "You must provide self.title or self.name") - local _,_,title = string.find(name, "FuBar %- (.-)%s*$") - if not title then - title = name - end - return (string.gsub(string.gsub(title, "|c%x%x%x%x%x%x%x%x", ""), "|r", "")) -end - -function FuBarPlugin:GetName() - return self.name -end - -function FuBarPlugin:GetCategory() - return self.category or OTHER -end - -function FuBarPlugin:GetFrame() - return self.frame -end - -function FuBarPlugin:GetPanel() - return self.panel -end - -function FuBarPlugin:IsTextColored() - return not self.db or not self.db.profile or not self.db.profile.uncolored -end - -function FuBarPlugin:ToggleTextColored() - FuBarPlugin:assert(self.db, "Cannot change text color if self.db is not available. (" .. self:GetTitle() .. ")") - self.db.profile.uncolored = not self.db.profile.uncolored or nil - self:UpdateText() -end - -function FuBarPlugin:ToggleMinimapAttached() - if CheckFuBar() and not self.cannotAttachToMinimap then - local value = self:IsMinimapAttached() - if value then - if self.panel then - self.panel:RemovePlugin(self) - end - FuBar:GetPanel(1):AddPlugin(self, nil, self.defaultPosition) - else - if self.panel then - self.panel:RemovePlugin(self) - end - AceLibrary(MINIMAPCONTAINER_MAJOR_VERSION):AddPlugin(self) - end - end - Dewdrop:Close() -end - -function FuBarPlugin:IsMinimapAttached() - if not CheckFuBar() then - return true - end - return self.panel == AceLibrary(MINIMAPCONTAINER_MAJOR_VERSION) -end - -function FuBarPlugin:Update() - self:UpdateData() - self:UpdateText() - self:UpdateTooltip() -end - -function FuBarPlugin:UpdateDisplay() - self:UpdateText() - self:UpdateTooltip() -end - -function FuBarPlugin:UpdateData() - if type(self.OnDataUpdate) == "function" then - if not self:IsDisabled() then - self:OnDataUpdate() - end - end -end - -function FuBarPlugin:UpdateText() - if type(self.OnTextUpdate) == "function" then - if not self:IsDisabled() then - self:OnTextUpdate() - end - elseif self:IsTextShown() then - self:SetText(self:GetTitle()) - end -end - -function FuBarPlugin:RegisterTablet() - if not Tablet:IsRegistered(self.frame) then - if self.db and self.db.profile and not self.db.profile.detachedTooltip then - self.db.profile.detachedTooltip = {} - end - Tablet:Register(self.frame, - 'children', function() - Tablet:SetTitle(self:GetTitle()) - if type(self.OnTooltipUpdate) == "function" then - if not self:IsDisabled() then - self:OnTooltipUpdate() - end - end - end, - 'clickable', self.clickableTooltip, - 'data', CheckFuBar() and FuBar.db.profile.tooltip or self.db and self.db.profile.detachedTooltip or {}, - 'detachedData', self.db and self.db.profile.detachedTooltip or {}, - 'point', function(frame) - if frame:GetTop() > GetScreenHeight() / 2 then - local x = frame:GetCenter() - if x < GetScreenWidth() / 3 then - return "TOPLEFT", "BOTTOMLEFT" - elseif x < GetScreenWidth() * 2 / 3 then - return "TOP", "BOTTOM" - else - return "TOPRIGHT", "BOTTOMRIGHT" - end - else - local x = frame:GetCenter() - if x < GetScreenWidth() / 3 then - return "BOTTOMLEFT", "TOPLEFT" - elseif x < GetScreenWidth() * 2 / 3 then - return "BOTTOM", "TOP" - else - return "BOTTOMRIGHT", "TOPRIGHT" - end - end - end, - 'menu', self.OnMenuRequest and function(level, value, valueN_1, valueN_2, valueN_3, valueN_4) - if level == 1 then - local name = tostring(self) - if not string.find(name, '^table:') then - name = string.gsub(name, "|c%x%x%x%x%x%x%x%x(.-)|r", "%1") - Dewdrop:AddLine( - 'text', name, - 'isTitle', true - ) - end - end - if type(self.OnMenuRequest) == "function" then - self:OnMenuRequest(level, value, true, valueN_1, valueN_2, valueN_3, valueN_4) - elseif type(self.OnMenuRequest) == "table" then - Dewdrop:FeedAceOptionsTable(self.OnMenuRequest) - end - end, - 'hideWhenEmpty', self.tooltipHiddenWhenEmpty - ) - end -end - -function FuBarPlugin:UpdateTooltip() - FuBarPlugin.RegisterTablet(self) - if self:IsMinimapAttached() and not self:IsTooltipDetached() and self.minimapFrame then - Tablet:Refresh(self.minimapFrame) - else - Tablet:Refresh(self.frame) - end -end - -function FuBarPlugin:OnProfileEnable() - self:Update() -end - -function FuBarPlugin:Show(panelId) - if self.frame:IsShown() or (self.minimapFrame and self.minimapFrame:IsShown()) then - return - end - if panelId ~= false then - if self.db then - self.db.profile.hidden = nil - end - end - if self.IsActive and not self:IsActive() then - self.panelIdTmp = panelId - self:ToggleActive() - self.panelIdTmp = nil - if self.db then - self.db.profile.disabled = nil - end - elseif not self.db or not self.db.profile.hidden then - if panelId == 0 or not CheckFuBar() then - AceLibrary(MINIMAPCONTAINER_MAJOR_VERSION):AddPlugin(self) - else - FuBar:ShowPlugin(self, panelId or self.panelIdTmp) - end - if not self.userDefinedFrame then - if not self:IsTextShown() then - self.textFrame:SetText("") - self.textFrame:SetWidth(epsilon) - self.textFrame:Hide() - end - if not self:IsIconShown() then - self.iconFrame:SetWidth(epsilon) - self.iconFrame:Hide() - end - end - self:Update() - end -end - -function FuBarPlugin:Hide(check) - if not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) then - return - end - if self.hideWithoutStandby and self.db and check ~= false then - self.db.profile.hidden = true - end - if not self.hideWithoutStandby then - if self.db and not self.overrideTooltip and not self.cannotDetachTooltip and self:IsTooltipDetached() and self.db.profile.detachedTooltip and self.db.profile.detachedTooltip.detached then - self:ReattachTooltip() - self.db.profile.detachedTooltip.detached = true - end - if self.IsActive and self:IsActive() and self.ToggleActive and (not CheckFuBar() or not FuBar:IsChangingProfile()) then - self:ToggleActive() - end - end - if self.panel then - self.panel:RemovePlugin(self) - end - self.frame:Hide() - if self.minimapFrame then - self.minimapFrame:Hide() - end - - if Dewdrop:IsOpen(self.frame) or (self.minimapFrame and Dewdrop:IsOpen(self.minimapFrame)) then - Dewdrop:Close() - end -end - -function FuBarPlugin:SetIcon(path) - if not path then - return - end - FuBarPlugin:argCheck(path, 2, "string", "boolean") - FuBarPlugin:assert(self.hasIcon, "Cannot set icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")") - if not self.iconFrame then - return - end - if type(path) ~= "string" then - path = format("Interface\\AddOns\\%s\\icon", self.folderName) - elseif not string.find(path, '^Interface[\\/]') then - path = format("Interface\\AddOns\\%s\\%s", self.folderName, path) - end - if string.sub(path, 1, 16) == "Interface\\Icons\\" then - self.iconFrame:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - self.iconFrame:SetTexCoord(0, 1, 0, 1) - end - self.iconFrame:SetTexture(path) - if self.minimapIcon then - if string.sub(path, 1, 16) == "Interface\\Icons\\" then - self.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - self.minimapIcon:SetTexCoord(0, 1, 0, 1) - end - self.minimapIcon:SetTexture(path) - end -end - -function FuBarPlugin:GetIcon() - if self.hasIcon then - return self.iconFrame:GetTexture() - end -end - -function FuBarPlugin:CheckWidth(force) - FuBarPlugin:argCheck(force, 2, "boolean", "nil") - if (self.iconFrame and self.iconFrame:IsShown()) or (self.textFrame and self.textFrame:IsShown()) then - if (self.db and self.db.profile and not self:IsIconShown()) or not self.hasIcon then - self.iconFrame:SetWidth(epsilon) - end - local width - if not self.hasNoText then - self.textFrame:SetHeight(0) - self.textFrame:SetWidth(500) - width = self.textFrame:GetStringWidth() + 1 - self.textFrame:SetWidth(width) - self.textFrame:SetHeight(self.textFrame:GetHeight()) - end - if self.hasNoText or not self.textFrame:IsShown() then - self.frame:SetWidth(self.iconFrame:GetWidth()) - if self.panel and self.panel:GetPluginSide(self) == "CENTER" then - self.panel:UpdateCenteredPosition() - end - elseif force or not self.textWidth or self.textWidth < width or self.textWidth - 8 > width then - self.textWidth = width - self.textFrame:SetWidth(width) - if self.iconFrame and self.iconFrame:IsShown() then - self.frame:SetWidth(width + self.iconFrame:GetWidth()) - else - self.frame:SetWidth(width) - end - if self.panel and self.panel:GetPluginSide(self) == "CENTER" then - self.panel:UpdateCenteredPosition() - end - end - end -end - -function FuBarPlugin:SetText(text) - if not self.textFrame then - return - end - FuBarPlugin:assert(not self.hasNoText, "Cannot set text if self.hasNoText has been set. (" .. self:GetTitle() .. ")") - FuBarPlugin:argCheck(text, 2, "string", "number") - if text == "" then - if self.hasIcon then - self:ShowIcon() - else - text = self:GetTitle() - end - end - if not self:IsTextColored() then - text = string.gsub(string.gsub(text, "|c%x%x%x%x%x%x%x%x", ""), "|r", "") - end - self.textFrame:SetText(text) - self:CheckWidth() -end - -function FuBarPlugin:GetText() - FuBarPlugin:assert(self.textFrame, "Cannot get text without a self.textFrame (" .. self:GetTitle() .. ")") - if not self.hasNoText then - return self.textFrame:GetText() or "" - end -end - -function FuBarPlugin:IsIconShown() - if not self.hasIcon then - return false - elseif self.hasNoText then - return true - elseif not self.db then - return true - elseif self.db and self.db.profile.showIcon == nil then - return true - else - return (self.db and (self.db.profile.showIcon == 1 or self.db.profile.showIcon == true)) and true or false - end -end - -function FuBarPlugin:ToggleIconShown() - FuBarPlugin:assert(self.iconFrame, "Cannot toggle icon without a self.iconFrame (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.hasIcon, "Cannot show icon unless self.hasIcon is set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(not self.hasNoText, "Cannot hide icon if self.hasNoText is set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.textFrame, "Cannot hide icon if self.textFrame is not set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.iconFrame, "Cannot hide icon if self.iconFrame is not set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.db, "Cannot hide icon if self.db is not available. (" .. self:GetTitle() .. ")") - local value = not self:IsIconShown() - self.db.profile.showIcon = value - if value then - if not self:IsTextShown() and self.textFrame:IsShown() and self.textFrame:GetText() == self:GetTitle() then - self.textFrame:Hide() - self.textFrame:SetText("") - end - self.iconFrame:Show() - self.iconFrame:SetWidth(self.iconFrame:GetHeight()) - else - if not self.textFrame:IsShown() or not self.textFrame:GetText() then - self.textFrame:Show() - self.textFrame:SetText(self:GetTitle()) - end - self.iconFrame:Hide() - self.iconFrame:SetWidth(epsilon) - end - self:CheckWidth(true) - return value -end - -function FuBarPlugin:ShowIcon() - if not self:IsIconShown() then - self:ToggleIconShown() - end -end - -function FuBarPlugin:HideIcon() - if self:IsIconShown() then - self:ToggleIconShown() - end -end - -function FuBarPlugin:IsTextShown() - if self.hasNoText then - return false - elseif not self.hasIcon then - return true - elseif not self.db then - return true - elseif self.db and self.db.profile.showText == nil then - return true - else - return (self.db and (self.db.profile.showText == 1 or self.db.profile.showText == true)) and true or false - end -end - -function FuBarPlugin:ToggleTextShown() - FuBarPlugin:assert(not self.cannotHideText, "Cannot hide text unless self.cannotHideText is unset. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.hasIcon, "Cannot show text unless self.hasIcon is set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(not self.hasNoText, "Cannot hide text if self.hasNoText is set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.textFrame, "Cannot hide text if self.textFrame is not set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.iconFrame, "Cannot hide text if self.iconFrame is not set. (" .. self:GetTitle() .. ")") - FuBarPlugin:assert(self.db, "Cannot hide text if self.db is not available. (" .. self:GetTitle() .. ")") - local value = not self:IsTextShown() - self.db.profile.showText = value - if value then - self.textFrame:Show() - self:UpdateText() - else - self.textFrame:SetText("") - self.textFrame:SetWidth(epsilon) - self.textFrame:Hide() - if not self:IsIconShown() then - DropDownList1:Hide() - end - self:ShowIcon() - end - self:CheckWidth(true) - return value -end - -function FuBarPlugin:ShowText() - if not self:IsTextShown() then - self:ToggleTextShown() - end -end - -function FuBarPlugin:HideText() - if self:IsTextShown() then - self:ToggleTextShown() - end -end - -function FuBarPlugin:IsTooltipDetached() - FuBarPlugin.RegisterTablet(self) - return not Tablet:IsAttached(self.frame) -end - -function FuBarPlugin:ToggleTooltipDetached() - FuBarPlugin.RegisterTablet(self) - if self:IsTooltipDetached() then - Tablet:Attach(self.frame) - else - Tablet:Detach(self.frame) - end - if Dewdrop then Dewdrop:Close() end -end - -function FuBarPlugin:DetachTooltip() - FuBarPlugin.RegisterTablet(self) - Tablet:Detach(self.frame) -end - -function FuBarPlugin:ReattachTooltip() - FuBarPlugin.RegisterTablet(self) - Tablet:Attach(self.frame) -end - -function FuBarPlugin:GetDefaultPosition() - return self.defaultPosition or "LEFT" -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 - -function FuBarPlugin:SetPanel(panel) - if panel then - FuBarPlugin:assert(IsCorrectPanel(panel), "Bad argument #2 to `SetPanel'. Panel does not have the correct API.") - end - self.panel = panel -end - -function FuBarPlugin:SetFontSize(size) - FuBarPlugin:assert(not self.userDefinedFrame, (self.name and self.name .. ": " or "") .. "You must provide a SetFontSize(size) method if you provide your own frame.") - if self.hasIcon then - FuBarPlugin:assert(self.iconFrame, (self.name and self.name .. ": " or "") .. "No iconFrame found") - self.iconFrame:SetWidth(size + 3) - self.iconFrame:SetHeight(size + 3) - end - if not self.hasNoText then - FuBarPlugin:assert(self.textFrame, (self.name and self.name .. ": " or "") .. "No textFrame found") - local font, _, flags = self.textFrame:GetFont() - self.textFrame:SetFont(font, size, flags) - end - self:CheckWidth() -end - -function FuBarPlugin:IsLoadOnDemand() - return IsAddOnLoadOnDemand(self.folderName) -end - -function FuBarPlugin:IsDisabled() - return self.IsActive and not self:IsActive() or false -end - -function FuBarPlugin:OnInstanceInit(target) - if not AceEvent then - self:error(MAJOR_VERSION .. " requires AceEvent-2.0.") - elseif not Tablet then - self:error(MAJOR_VERSION .. " requires Tablet-2.0.") - elseif not Dewdrop then - self:error(MAJOR_VERSION .. " requires Dewdrop-2.0.") - end - self.registry[target] = true - - local _,_,folderName = string.find(debugstack(6, 1, 0), "\\AddOns\\(.*)\\") - target.folderName = folderName - self.folderNames[target] = folderName -end - -local frame_OnClick, frame_OnDoubleClick, frame_OnMouseDown, frame_OnMouseUp, frame_OnReceiveDrag - -function FuBarPlugin:CreateBasicPluginFrame(name) - local frame = CreateFrame("Button", name, UIParent) - frame:SetFrameStrata("HIGH") - frame:SetFrameLevel(7) - frame:EnableMouse(true) - frame:EnableMouseWheel(true) - frame:SetMovable(true) - frame:SetWidth(150) - frame:SetHeight(24) - frame:SetPoint("CENTER", UIParent, "CENTER") - frame.self = self - if not frame_OnClick then - function frame_OnClick() - if type(this.self.OnClick) == "function" then - this.self:OnClick(arg1) - end - end - end - frame:SetScript("OnClick", frame_OnClick) - if not frame_OnDoubleClick then - function frame_OnDoubleClick() - if type(this.self.OnDoubleClick) == "function" then - this.self:OnDoubleClick(arg1) - end - end - end - frame:SetScript("OnDoubleClick", frame_OnDoubleClick) - if not frame_OnMouseDown then - function frame_OnMouseDown() - if arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then - this.self:OpenMenu() - return - else - HideDropDownMenu(1) - if type(this.self.OnMouseDown) == "function" then - this.self:OnMouseDown(arg1) - end - end - end - end - frame:SetScript("OnMouseDown", frame_OnMouseDown) - if not frame_OnMouseUp then - function frame_OnMouseUp() - if type(this.self.OnMouseUp) == "function" then - this.self:OnMouseUp(arg1) - end - end - end - frame:SetScript("OnMouseUp", frame_OnMouseUp) - if not frame_OnReceiveDrag then - function frame_OnReceiveDrag() - if type(this.self.OnReceiveDrag) == "function" then - this.self:OnReceiveDrag() - end - end - end - frame:SetScript("OnReceiveDrag", frame_OnReceiveDrag) - return frame -end - -local child_OnEnter, child_OnLeave, child_OnClick, child_OnDoubleClick, child_OnMouseDown, child_OnMouseUp, child_OnReceiveDrag -function FuBarPlugin:CreatePluginChildFrame(frameType, name, parent) - FuBarPlugin:assert(self.frame, (self.name and self.name .. ": " or "") .. "You must have self.frame declared in order to add child frames") - FuBarPlugin:argCheck(frameType, 1, "string") - local child = CreateFrame(frameType, name, parent) - if parent then - child:SetFrameLevel(parent:GetFrameLevel() + 2) - end - child.self = self - if not child_OnEnter then - function child_OnEnter(...) - if this.self.frame:GetScript("OnEnter") then - this.self.frame:GetScript("OnEnter")(...) - end - end - end - child:SetScript("OnEnter", child_OnEnter) - if not child_OnLeave then - function child_OnLeave(...) - if this.self.frame:GetScript("OnLeave") then - this.self.frame:GetScript("OnLeave")(...) - end - end - end - child:SetScript("OnLeave", child_OnLeave) - if child:HasScript("OnClick") then - if not child_OnClick then - function child_OnClick(...) - if this.self.frame:HasScript("OnClick") and this.self.frame:GetScript("OnClick") then - this.self.frame:GetScript("OnClick")(...) - end - end - end - child:SetScript("OnClick", child_OnClick) - end - if child:HasScript("OnDoubleClick") then - if not child_OnDoubleClick then - function child_OnDoubleClick(...) - if this.self.frame:HasScript("OnDoubleClick") and this.self.frame:GetScript("OnDoubleClick") then - this.self.frame:GetScript("OnDoubleClick")(...) - end - end - end - child:SetScript("OnDoubleClick", child_OnDoubleClick) - end - if not child_OnMouseDown then - function child_OnMouseDown(...) - if this.self.frame:HasScript("OnMouseDown") and this.self.frame:GetScript("OnMouseDown") then - this.self.frame:GetScript("OnMouseDown")(...) - end - end - end - child:SetScript("OnMouseDown", child_OnMouseDown) - if not child_OnMouseUp then - function child_OnMouseUp(...) - if this.self.frame:HasScript("OnMouseUp") and this.self.frame:GetScript("OnMouseUp") then - this.self.frame:GetScript("OnMouseUp")(...) - end - end - end - child:SetScript("OnMouseUp", child_OnMouseUp) - if not child_OnReceiveDrag then - function child_OnReceiveDrag(this) - if this.self.frame:HasScript("OnReceiveDrag") and this.self.frame:GetScript("OnReceiveDrag") then - this.self.frame:GetScript("OnReceiveDrag")() - end - end - end - child:SetScript("OnReceiveDrag", child_OnReceiveDrag) - return child -end - -function FuBarPlugin:OpenMenu(frame) - if not frame then - frame = self:GetFrame() - end - if not frame or not self:GetFrame() or Dewdrop:IsOpen(frame) then - Dewdrop:Close() - return - end - Tablet:Close() - - if not Dewdrop:IsRegistered(self:GetFrame()) then - if type(self.OnMenuRequest) == "table" and (not self.OnMenuRequest.handler or self.OnMenuRequest.handler == self) and self.OnMenuRequest.type == "group" then - Dewdrop:InjectAceOptionsTable(self, self.OnMenuRequest) - if self.OnMenuRequest.args and CheckFuBar() and not self.independentProfile then - self.OnMenuRequest.args.profile = nil - end - end - Dewdrop:Register(self:GetFrame(), - 'children', type(self.OnMenuRequest) == "table" and self.OnMenuRequest or function(level, value, valueN_1, valueN_2, valueN_3, valueN_4) - if level == 1 then - Dewdrop:AddLine( - 'text', self:GetTitle(), - 'isTitle', true - ) - end - - if level == 1 then - if self.OnMenuRequest then - self:OnMenuRequest(level, value, false, valueN_1, valueN_2, valueN_3, valueN_4) - end - - if not self.overrideMenu then - if self.MenuSettings then - Dewdrop:AddLine() - end - self:AddImpliedMenuOptions() - end - else - if not self.overrideMenu and self:AddImpliedMenuOptions() then - else - if self.OnMenuRequest then - self:OnMenuRequest(level, value, false, valueN_1, valueN_2, valueN_3, valueN_4) - end - end - end - if level == 1 then - Dewdrop:AddLine( - 'text', CLOSE, - 'tooltipTitle', CLOSE, - 'tooltipText', CLOSE_DESC, - 'func', Dewdrop.Close, - 'arg1', Dewdrop - ) - end - end, - 'point', function(frame) - local x, y = frame:GetCenter() - local leftRight - if x < GetScreenWidth() / 2 then - leftRight = "LEFT" - else - leftRight = "RIGHT" - end - if y < GetScreenHeight() / 2 then - return "BOTTOM" .. leftRight, "TOP" .. leftRight - else - return "TOP" .. leftRight, "BOTTOM" .. leftRight - end - end, - 'dontHook', true - ) - end - if frame == self:GetFrame() then - Dewdrop:Open(self:GetFrame()) - else - Dewdrop:Open(frame, self:GetFrame()) - end -end - -local impliedMenuOptions -function FuBarPlugin:AddImpliedMenuOptions(level) - FuBarPlugin:argCheck(level, 2, "number", "nil") - if not impliedMenuOptions then - impliedMenuOptions = {} - end - if not impliedMenuOptions[self] then - impliedMenuOptions[self] = { type = 'group', args = {} } - Dewdrop:InjectAceOptionsTable(self, impliedMenuOptions[self]) - if impliedMenuOptions[self].args and CheckFuBar() and not self.independentProfile then - impliedMenuOptions[self].args.profile = nil - end - end - return Dewdrop:FeedAceOptionsTable(impliedMenuOptions[self], level and level - 1) -end - -function FuBarPlugin.OnEmbedInitialize(FuBarPlugin, self) - if not self.frame then - local name = "FuBarPlugin" .. self:GetTitle() .. "Frame" - local frame = _G[name] - if not frame or not _G[name .. "Text"] or not _G[name .. "Icon"] then - frame = self:CreateBasicPluginFrame(name) - - local icon = frame:CreateTexture(name .. "Icon", "ARTWORK") - icon:SetWidth(16) - icon:SetHeight(16) - icon:SetPoint("LEFT", frame, "LEFT") - - local text = frame:CreateFontString(name .. "Text", "ARTWORK") - text:SetWidth(134) - text:SetHeight(24) - text:SetPoint("LEFT", icon, "RIGHT", 0, 1) - text:SetFontObject(GameFontNormal) - end - self.frame = frame - self.textFrame = _G[name .. "Text"] - self.iconFrame = _G[name .. "Icon"] - else - self.userDefinedFrame = true - end - - self.frame.plugin = self - self.frame:SetParent(UIParent) - self.frame:SetPoint("RIGHT", UIParent, "LEFT", -5, 0) - self.frame:Hide() - - if self.hasIcon then - self:SetIcon(self.hasIcon) - end - - if CheckFuBar() then - FuBar:RegisterPlugin(self) - end -end - -local CheckShow = function(self, panelId) - if not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) then - self:Show(panelId) - Dewdrop:Refresh(2) - end -end - -local recheckPlugins -function FuBarPlugin.OnEmbedEnable(FuBarPlugin, self) - if not self.userDefinedFrame then - if self:IsIconShown() then - self.iconFrame:Show() - else - self.iconFrame:Hide() - end - end - self:CheckWidth(true) - - if not self.hideWithoutStandby or (self.db and not self.db.profile.hidden) then - if FuBarPlugin.enabledPlugins[self] then - CheckShow(self, self.panelIdTmp) - else - FuBarPlugin:ScheduleEvent(CheckShow, 0, self, self.panelIdTmp) - end - end - FuBarPlugin.enabledPlugins[self] = true - - if not self.overrideTooltip and not self.cannotDetachTooltip and self.db and self.db.profile.detachedTooltip and self.db.profile.detachedTooltip.detached then - FuBarPlugin:ScheduleEvent(self.DetachTooltip, 0, self) - end - - if self:IsLoadOnDemand() and CheckFuBar() then - if not FuBar.db.profile.loadOnDemand then - FuBar.db.profile.loadOnDemand = {} - end - if not FuBar.db.profile.loadOnDemand[self.folderName] then - FuBar.db.profile.loadOnDemand[self.folderName] = {} - end - FuBar.db.profile.loadOnDemand[self.folderName].disabled = nil - end - - if CheckFuBar() and AceLibrary:HasInstance("AceConsole-2.0") then - if not recheckPlugins then - local AceConsole = AceLibrary("AceConsole-2.0") - local AceOO = AceLibrary("AceOO-2.0") - function recheckPlugins() - for k,v in pairs(AceConsole.registry) do - if type(v) == "table" and v.args and AceOO.inherits(v.handler, FuBarPlugin) and not v.independentProfile then - v.args.profile = nil - end - end - end - end - FuBarPlugin:ScheduleEvent(recheckPlugins, 0) - end -end - -function FuBarPlugin.OnEmbedDisable(FuBarPlugin, self) - self:Hide(false) - - if self:IsLoadOnDemand() and CheckFuBar() then - if not FuBar.db.profile.loadOnDemand then - FuBar.db.profile.loadOnDemand = {} - end - if not FuBar.db.profile.loadOnDemand[self.folderName] then - FuBar.db.profile.loadOnDemand[self.folderName] = {} - end - FuBar.db.profile.loadOnDemand[self.folderName].disabled = true - end -end - -function FuBarPlugin.OnEmbedProfileEnable(FuBarPlugin, self) - self:Update() - if self.db and self.db.profile then - if not self.db.profile.detachedTooltip then - self.db.profile.detachedTooltip = {} - end - if Tablet.registry[self.frame] then - Tablet:UpdateDetachedData(self.frame, self.db.profile.detachedTooltip) - else - FuBarPlugin.RegisterTablet(self) - end - end -end - -function FuBarPlugin.GetAceOptionsDataTable(FuBarPlugin, self) - return { - icon = { - type = "toggle", - name = SHOW_ICON, - desc = SHOW_ICON_DESC, - set = "ToggleIconShown", - get = "IsIconShown", - hidden = function() - return not self.hasIcon or self.hasNoText or self:IsDisabled() or self:IsMinimapAttached() or not self.db - end, - order = -13.7, - handler = self, - }, - text = { - type = "toggle", - name = SHOW_TEXT, - desc = SHOW_TEXT_DESC, - set = "ToggleTextShown", - get = "IsTextShown", - hidden = function() - return self.cannotHideText or not self.hasIcon or self.hasNoText or self:IsDisabled() or self:IsMinimapAttached() or not self.db - end, - order = -13.6, - handler = self, - }, - colorText = { - type = "toggle", - name = SHOW_COLORED_TEXT, - desc = SHOW_COLORED_TEXT_DESC, - set = "ToggleTextColored", - get = "IsTextColored", - hidden = function() - return self.userDefinedFrame or self.hasNoText or self.hasNoColor or self:IsDisabled() or self:IsMinimapAttached() or not self.db - end, - order = -13.5, - handler = self, - }, - detachTooltip = { - type = "toggle", - name = DETACH_TOOLTIP, - desc = DETACH_TOOLTIP_DESC, - get = "IsTooltipDetached", - set = "ToggleTooltipDetached", - hidden = function() - return self.overrideTooltip or self.cannotDetachTooltip or self:IsDisabled() - end, - order = -13.4, - handler = self, - }, - lockTooltip = { - type = "toggle", - name = LOCK_TOOLTIP, - desc = LOCK_TOOLTIP_DESC, - get = function() - return Tablet:IsLocked(self.frame) - end, - set = function() - return Tablet:ToggleLocked(self.frame) - end, - disabled = function() - return not self:IsTooltipDetached() - end, - hidden = function() - return self.overrideTooltip or self.cannotDetachTooltip or self:IsDisabled() - end, - order = -13.3, - handler = self, - }, - position = { - type = "text", - name = POSITION, - desc = POSITION_DESC, - validate = { - LEFT = POSITION_LEFT, - CENTER = POSITION_CENTER, - RIGHT = POSITION_RIGHT - }, - get = function() - return self.panel and self.panel:GetPluginSide(self) - end, - set = function(value) - if self.panel then - self.panel:SetPluginSide(self, value) - end - end, - hidden = function() - return self:IsMinimapAttached() or self:IsDisabled() or not self.panel - end, - order = -13.2, - handler = self, - }, - minimapAttach = { - type = "toggle", - name = ATTACH_TO_MINIMAP, - desc = ATTACH_TO_MINIMAP_DESC, - get = "IsMinimapAttached", - set = "ToggleMinimapAttached", - hidden = function() - return (self.cannotAttachToMinimap and not self:IsMinimapAttached()) or not CheckFuBar() or self:IsDisabled() - end, - order = -13.1, - handler = self, - }, - hide = { - type = "toggle", - cmdName = HIDE_FUBAR_PLUGIN_CMD, - guiName = HIDE_FUBAR_PLUGIN, - desc = HIDE_FUBAR_PLUGIN_DESC, - get = function() - return not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) - end, - set = function() - if not self.frame:IsShown() and (not self.minimapFrame or not self.minimapFrame:IsShown()) then - self:Show() - else - self:Hide() - end - end, - hidden = function() - return not self.hideWithoutStandby or self:IsDisabled() - end, - order = -13, - handler = self, - }, - } -end - -local function activate(self, oldLib, oldDeactivate) - FuBarPlugin = self - - if oldLib then - self.registry = oldLib.registry - self.folderNames = oldLib.folderNames - self.enabledPlugins = oldLib.enabledPlugins - end - - if not self.registry then - self.registry = {} - end - if not self.folderNames then - self.folderNames = {} - end - if not self.enabledPlugins then - self.enabledPlugins = {} - end - - FuBarPlugin.activate(self, oldLib, oldDeactivate) - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -local function external(self, major, instance) - if major == "AceEvent-2.0" then - AceEvent = instance - - AceEvent:embed(self) - elseif major == "Tablet-2.0" then - Tablet = instance - elseif major == "Dewdrop-2.0" then - Dewdrop = instance - end -end - -AceLibrary:Register(FuBarPlugin, MAJOR_VERSION, MINOR_VERSION, activate, nil, external) - -local MinimapContainer = {} - -local function IsMinimapSquare() - return IsAddOnLoaded("CornerMinimap") or IsAddOnLoaded("SquareMinimap") or IsAddOnLoaded("Squeenix") or (IsAddOnLoaded("simpleMinimap") and simpleMinimap_Skins and simpleMinimap_Skins:GetShape() == "square") -end - -function MinimapContainer:AddPlugin(plugin) - if CheckFuBar() and FuBar:IsChangingProfile() then - return - end - if plugin.panel ~= nil then - plugin.panel:RemovePlugin(plugin) - end - plugin.panel = self - if not plugin.minimapFrame then - local frame = CreateFrame("Button", plugin.frame:GetName() .. "MinimapButton", Minimap) - plugin.minimapFrame = frame - AceLibrary(MAJOR_VERSION).RegisterTablet(plugin) - Tablet:Register(frame, plugin.frame) - frame.plugin = plugin - frame:SetWidth(31) - frame:SetHeight(31) - frame:SetFrameStrata("BACKGROUND") - frame:SetFrameLevel(4) - frame:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight") - local icon = frame:CreateTexture(frame:GetName() .. "Icon", "BACKGROUND") - plugin.minimapIcon = icon - local path = plugin:GetIcon() or (plugin.iconFrame and plugin.iconFrame:GetTexture()) or "Interface\\Icons\\INV_Misc_QuestionMark" - icon:SetTexture(path) - if string.sub(path, 1, 16) == "Interface\\Icons\\" then - icon:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - icon:SetTexCoord(0, 1, 0, 1) - end - icon:SetWidth(20) - icon:SetHeight(20) - icon:SetPoint("TOPLEFT", frame, "TOPLEFT", 7, -5) - local overlay = frame:CreateTexture(frame:GetName() .. "Overlay","OVERLAY") -overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder") - overlay:SetWidth(53) - overlay:SetHeight(53) - overlay:SetPoint("TOPLEFT",frame,"TOPLEFT") - frame:EnableMouse(true) - frame:RegisterForClicks("LeftButtonUp") - frame.plugin = plugin - frame:SetScript("OnClick", function() - if type(plugin.OnClick) == "function" then - if not this.dragged then - plugin:OnClick(arg1) - end - end - end) - frame:SetScript("OnDoubleClick", function() - if type(plugin.OnDoubleClick) == "function" then - plugin:OnDoubleClick(arg1) - end - end) - frame:SetScript("OnReceiveDrag", function() - if type(plugin.OnReceiveDrag) == "function" then - if not this.dragged then - plugin:OnReceiveDrag() - end - end - end) - frame:SetScript("OnMouseDown", function() - this.dragged = false - if arg1 == "LeftButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then - HideDropDownMenu(1) - if type(plugin.OnMouseDown) == "function" then - plugin:OnMouseDown(arg1) - end - elseif arg1 == "RightButton" and not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() then - plugin:OpenMenu(frame) - else - HideDropDownMenu(1) - if type(plugin.OnMouseDown) == "function" then - plugin:OnMouseDown(arg1) - end - end - if plugin.OnClick or plugin.OnMouseDown or plugin.OnMouseUp or plugin.OnDoubleClick then - if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then - plugin.minimapIcon:SetTexCoord(0.14, 0.86, 0.14, 0.86) - else - plugin.minimapIcon:SetTexCoord(0.1, 0.9, 0.1, 0.9) - end - end - end) - frame:SetScript("OnMouseUp", function() - if not this.dragged and type(plugin.OnMouseUp) == "function" then - plugin:OnMouseUp(arg1) - end - if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then - plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - plugin.minimapIcon:SetTexCoord(0, 1, 0, 1) - end - end) - frame:RegisterForDrag("LeftButton") - frame:SetScript("OnDragStart", self.OnDragStart) - frame:SetScript("OnDragStop", self.OnDragStop) - end - plugin.frame:Hide() - plugin.minimapFrame:Show() - self:ReadjustLocation(plugin) - table.insert(self.plugins, plugin) - local exists = false - return true -end - -function MinimapContainer:RemovePlugin(index) - if CheckFuBar() and FuBar:IsChangingProfile() then - return - end - if type(index) == "table" then - index = self:IndexOfPlugin(index) - if not index then - return - end - end - local t = self.plugins - local plugin = t[index] - assert(plugin.panel == self, "Plugin has improper panel field") - plugin:SetPanel(nil) - table.remove(t, index) - return true -end - -function MinimapContainer:ReadjustLocation(plugin) - local frame = plugin.minimapFrame - if plugin.db and plugin.db.profile.minimapPositionWild then - frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", plugin.db.profile.minimapPositionX, plugin.db.profile.minimapPositionY) - elseif not plugin.db and plugin.minimapPositionWild then - frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", plugin.minimapPositionX, plugin.minimapPositionY) - else - local position - if plugin.db then - position = plugin.db.profile.minimapPosition or plugin.defaultMinimapPosition or math.random(1, 360) - else - position = plugin.minimapPosition or plugin.defaultMinimapPosition or math.random(1, 360) - end - local angle = math.rad(position or 0) - local x,y - if not IsMinimapSquare() then - x = math.cos(angle) * 80 - y = math.sin(angle) * 80 - else - x = 110 * math.cos(angle) - y = 110 * math.sin(angle) - x = math.max(-82, math.min(x, 84)) - y = math.max(-86, math.min(y, 82)) - end - frame:SetPoint("CENTER", Minimap, "CENTER", x, y) - end -end - -function MinimapContainer:GetPlugin(index) - return self.plugins[index] -end - -function MinimapContainer:GetNumPlugins() - return table.getn(self.plugins) -end - -function MinimapContainer:IndexOfPlugin(plugin) - for i,p in ipairs(self.plugins) do - if p == plugin then - return i, "MINIMAP" - end - end -end - -function MinimapContainer:HasPlugin(plugin) - return self:IndexOfPlugin(plugin) ~= nil -end - -function MinimapContainer:GetPluginSide(plugin) - local index = self:IndexOfPlugin(plugin) - assert(index, "Plugin not in panel") - return "MINIMAP" -end - -function MinimapContainer.OnDragStart() - this.dragged = true - this:LockHighlight() - this:SetScript("OnUpdate", MinimapContainer.OnUpdate) - if string.sub(this.plugin.minimapIcon:GetTexture(), 1, 16) == "Interface\\Icons\\" then - this.plugin.minimapIcon:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - this.plugin.minimapIcon:SetTexCoord(0, 1, 0, 1) - end -end - -function MinimapContainer.OnDragStop() - this:SetScript("OnUpdate", nil) - this:UnlockHighlight() -end - -function MinimapContainer.OnUpdate() - if not IsAltKeyDown() then - local mx, my = Minimap:GetCenter() - local px, py = GetCursorPosition() - local scale = UIParent:GetEffectiveScale() - px, py = px / scale, py / scale - local position = math.deg(math.atan2(py - my, px - mx)) - if position <= 0 then - position = position + 360 - elseif position > 360 then - position = position - 360 - end - if this.plugin.db then - this.plugin.db.profile.minimapPosition = position - this.plugin.db.profile.minimapPositionX = nil - this.plugin.db.profile.minimapPositionY = nil - this.plugin.db.profile.minimapPositionWild = nil - else - this.plugin.minimapPosition = position - this.plugin.minimapPositionX = nil - this.plugin.minimapPositionY = nil - this.plugin.minimapPositionWild = nil - end - else - local px, py = GetCursorPosition() - local scale = UIParent:GetEffectiveScale() - px, py = px / scale, py / scale - if this.plugin.db then - this.plugin.db.profile.minimapPositionX = px - this.plugin.db.profile.minimapPositionY = py - this.plugin.db.profile.minimapPosition = nil - this.plugin.db.profile.minimapPositionWild = true - else - this.plugin.minimapPositionX = px - this.plugin.minimapPositionY = py - this.plugin.minimapPosition = nil - this.plugin.minimapPositionWild = true - end - end - MinimapContainer:ReadjustLocation(this.plugin) -end - -local function activate(self, oldLib, oldDeactivate) - MinimapContainer = self - - if oldLib then - self.plugins = oldLib.plugins - end - - if not self.plugins then - self.plugins = {} - end - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(MinimapContainer, MINIMAPCONTAINER_MAJOR_VERSION, MINOR_VERSION, activate)
--- a/libs/ReAnchor-1.0/ReAnchor-1.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,355 +0,0 @@ ---[[ -Name: ReAnchor-1.0 -Revision: $Rev: 1 $ -Author: Flick -Website: -Documentation: -SVN: -Description: Provides drag-placement facilities for frames -License: MIT -Dependencies: AceLibrary, AceOO-2.0 -]] - - -local version_major, version_minor = "ReAnchor-1.0", "$Rev: 1 $" - -if not AceLibrary then error(version_major .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(version_major, version_minor) then return end -if not AceLibrary:HasInstance("AceOO-2.0") then error(version_major .. " requires AceOO-2.0") end - --- local constants -local AceOO = AceLibrary("AceOO-2.0") - -local edges = { "BOTTOM", "TOP", "LEFT", "RIGHT" } - -local pointsOnEdge = { - BOTTOM = { "BOTTOM", "BOTTOMLEFT", "BOTTOMRIGHT", }, - TOP = { "TOP", "TOPLEFT", "TOPRIGHT", }, - RIGHT = { "RIGHT", "BOTTOMRIGHT", "TOPRIGHT", }, - LEFT = { "LEFT", "BOTTOMLEFT", "TOPLEFT", }, -} - -local edgeSelector = { - BOTTOM = 1, -- select x of x,y - TOP = 1, -- select x of x,y - LEFT = 2, -- select y of x,y - RIGHT = 2, -- select y of x,y -} - -local oppositePoints = { - BOTTOMLEFT = "TOPRIGHT", - BOTTOM = "TOP", - BOTTOMRIGHT = "TOPLEFT", - RIGHT = "LEFT", - TOPRIGHT = "BOTTOMLEFT", - TOP = "BOTTOM", - TOPLEFT = "BOTTOMRIGHT", - LEFT = "RIGHT", - CENTER = "CENTER", -} - -local insidePointOffsetFuncs = { - BOTTOMLEFT = function(x, y) return x, y end, - BOTTOM = function(x, y) return 0, y end, - BOTTOMRIGHT = function(x, y) return -x, y end, - RIGHT = function(x, y) return -x, 0 end, - TOPRIGHT = function(x, y) return -x, -y end, - TOP = function(x, y) return 0, -y end, - TOPLEFT = function(x, y) return x, -y end, - LEFT = function(x, y) return x, 0 end, - CENTER = function(x, y) return 0, 0 end, -} - -local pointCoordFuncs = { - BOTTOMLEFT = function(f) return f:GetLeft(), f:GetBottom() end, - BOTTOM = function(f) return nil, f:GetBottom() end, - BOTTOMRIGHT = function(f) return f:GetRight(), f:GetBottom() end, - RIGHT = function(f) return f:GetRight(), nil end, - TOPRIGHT = function(f) return f:GetRight(), f:GetTop() end, - TOP = function(f) return nil, f:GetTop() end, - TOPLEFT = function(f) return f:GetLeft(), f:GetTop() end, - LEFT = function(f) return f:GetLeft(), nil end, - CENTER = function(f) return f:GetCenter() end, -} - -local edgeBoundsFuncs = { - BOTTOM = function(f) return f:GetLeft(), f:GetRight() end, - LEFT = function(f) return f:GetBottom(), f:GetTop() end -} -edgeBoundsFuncs.TOP = edgeBoundsFuncs.BOTTOM -edgeBoundsFuncs.RIGHT = edgeBoundsFuncs.LEFT - - --- local utility functions - --- Returns absolute coordinates x,y of the named point 'p' of frame 'f' -local function GetPointCoords( f, p ) - local x, y = pointCoordFuncs[p](f) - if not(x and y) then - local cx, cy = f:GetCenter() - x = x or cx - y = y or cy - end - return x, y -end - - --- Returns true if frame 'f1' can be anchored to frame 'f2' -local function CheckAnchorable( f1, f2 ) - -- can't anchor a frame to itself or to nil - if f1 == f2 or f2 == nil then - return false - end - - -- can always anchor to UIParent - if f2 == UIParent then - return true - end - - -- also can't do circular anchoring of frames - -- walk the anchor chain, which generally shouldn't be that expensive - -- (who nests draggables that deep anyway?) - for i = 1, f2:GetNumPoints() do - local _, f = f2:GetPoint(i) - return CheckAnchorable(f1,f) - end - - return true -end - --- Returns true if frames f1 and f2 specified edges overlap -local function CheckEdgeOverlap( f1, f2, e ) - local l1, u1 = edgeBoundsFuncs[e](f1) - local l2, u2 = edgeBoundsFuncs[e](f2) - return l1 <= l2 and l2 <= u1 or l2 <= l1 and l1 <= u2 -end - --- Returns true if point p1 on frame f1 overlaps edge e2 on frame f2 -local function CheckPointEdgeOverlap( f1, p1, f2, e2 ) - local l, u = edgeBoundsFuncs[e2](f2) - local x, y = GetPointCoords(f1,p1) - x = select(edgeSelector[e2], x, y) - return l <= x and x <= u -end - --- Returns the distance between corresponding edges. It is --- assumed that the passed in edges e1 and e2 are the same or opposites -local function GetEdgeDistance( f1, f2, e1, e2 ) - local x1, y1 = pointCoordFuncs[e1](f1) - local x2, y2 = pointCoordFuncs[e2](f2) - return math.abs((x1 or y1) - (x2 or y2)) -end - --- Returns interior offsets (specified absolutely) from a point -local function GetInteriorOffsetsToPoint(p, x, y) - return insidePointOffsetFuncs[p](x,y) -end - --- creates a snap indicator square -local function createSnapIndicator() - local f = CreateFrame("Frame",nil,UIParent) - f:SetFrameStrata("HIGH") - local t = f:CreateTexture(nil,"OVERLAY") - t:SetBlendMode("ADD") - t:SetTexture(1,0.82,0,0.8) - t:SetPoint("CENTER") - f:SetWidth(8) - f:SetHeight(8) - f:Show() - return f -end - --- local objects -local snapIndicator1 -local snapIndicator2 - - - - - - --- ReAnchor is a Mixin which provides some anchoring and --- placement methods for frames. --- An object with the ReAnchor mixin must support the --- IAnchorable interface (implicitly or explicitly). --- The mixin methods also require arguments to support --- that interface. - --- In the method prototypes, 'IRObjs' is used to refer to a --- table of objects which support the IAnchorable interface. - - -local ReAnchor = AceOO.Mixin { - "GetClosestVisibleEdge", - "GetClosestVisiblePoint", - "GetClosestPointSnapped", - "DisplaySnapIndicator", - "HideSnapIndicator", -} - ---------------------------------------------------------- --- Constants and classes that are not exported via mixin ---------------------------------------------------------- -ReAnchor.IAnchorable = AceOO.Interface { - GetFrame = "function", - GetAnchorage = "function", -- return ReAnchor.anchorInside or .anchorOutside -} - -ReAnchor.anchorInside = { inside = true } -ReAnchor.anchorOutside = { outside = true } - - - --------------------- --- Mixin methods --------------------- - --- returns: --- (1) o : the closest IRObj --- (2) e1 : the point (edge) on self:GetFrame() --- (3) e2 : the point (edge) on o:GetFrame() -function ReAnchor:GetClosestVisibleEdge( IRObjs ) - local f1 = self:GetFrame() - local r, o, e1, e2 - for _, o2 in pairs(IRObjs) do - local f2 = o2:GetFrame() - local a = o2:GetAnchorage() - if f2:IsVisible() and CheckAnchorable(f1,f2) then - for _, e in pairs(edges) do - local opp = a.inside and e or oppositePoints[e] - if CheckEdgeOverlap(f1,f2,e) then - local d = GetEdgeDistance(f1, f2, e, opp) - if not r or d < r then - r, o, e1, e2 = d, o2, e, opp - end - end - end - end - end - return o, e1, e2 -end - --- returns: --- (1) o: the closest IRObj --- (1) p: the point on self:GetFrame() --- (2) rp: the relativePoint on o:GetFrame() --- (3) x: x offset --- (4) y: y offset --- such that self:GetFrame():SetPoint(p,o:GetFrame(),rp,x,y) preserves the current location -function ReAnchor:GetClosestVisiblePoint( IRObjs ) - local f1 = self:GetFrame() - local o, e1, e2 = self:GetClosestVisibleEdge( IRObjs ) - local f2 = o:GetFrame() - local rsq, p, rp, x, y - -- iterate pointsOnEdge in order and use < to prefer edge centers to corners - for _, p1 in ipairs(pointsOnEdge[e1]) do - if CheckPointEdgeOverlap(f1,p1,f2,e2) then - local p2 = o:GetAnchorage().outside and oppositePoints[p1] or p1 - local x1, y1 = GetPointCoords(f1,p1) - local x2, y2 = GetPointCoords(f2,p2) - local dx = x1 - x2 - local dy = y1 - y2 - local rsq2 = dx*dx + dy*dy - if not rsq or rsq2 < rsq then - rsq, p, rp, x, y = rsq2, p1, p2, dx, dy - end - end - end - return o, p, rp, x, y -end - - --- Calls self:GetClosestVisiblePoint() and then snaps to the specified --- offsets if within the given range in x and y (as appropriate) --- Return semantic is the same as GetClosestVisiblePoint(). Returns nil --- if no snap can be done. -function ReAnchor:GetClosestPointSnapped(IRObjs, r, xOff, yOff) - local f1 = self:GetFrame() - local o, p, rp, x, y = self:GetClosestVisiblePoint(IRObjs) - local s = false - - if r then - local sx, sy = GetInteriorOffsetsToPoint(p, xOff or 0, yOff or 0) - local xx, yy = pointCoordFuncs[p](f1) - if xx and yy then - if math.abs(x) <= r then - x = sx - s = true - end - if math.abs(y) <= r then - y = sy - s = true - end - elseif xx then - if math.abs(x) <= r then - x = sx - s = true - if math.abs(y) <= r then - y = sy - end - end - elseif yy then - if math.abs(y) <= r then - y = sy - s = true - if math.abs(x) <= r then - x = sx - end - end - end - end - - if s then - return o, p, rp, x, y - end -end - - - --- shows anchor-indicators on the associated frame and the target frame --- when a snap is warranted. -function ReAnchor:DisplaySnapIndicator( IRObjs, r, xOff, yOff ) - local o, p, rp, x, y, snap = self:GetClosestPointSnapped(IRObjs, r, xOff, yOff) - local si1 = snapIndicator1 - local si2 = snapIndicator2 - if o then - si1:ClearAllPoints() - si2:ClearAllPoints() - si1:SetPoint("CENTER", self:GetFrame(), p, 0, 0) - local xx, yy = pointCoordFuncs[rp](o:GetFrame()) - x = math.abs(x) <=r and xx and 0 or x - y = math.abs(y) <=r and yy and 0 or y - si2:SetPoint("CENTER", o:GetFrame(), rp, x, y) - si1:Show() - si2:Show() - else - if si1:IsVisible() then - si1:Hide() - si2:Hide() - end - end -end - - -function ReAnchor:HideSnapIndicator() - if snapIndicator1:IsVisible() then - snapIndicator1:Hide() - snapIndicator2:Hide() - end -end - - - --- library setup - -local function activate( self, oldLib, oldDeactivate ) - snapIndicator1 = createSnapIndicator() - snapIndicator2 = createSnapIndicator() - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(ReAnchor, version_major, version_minor, activate) -ReAnchor = nil
--- a/libs/ReBound-1.0/ReBound-1.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,539 +0,0 @@ ---[[ -Name: ReBound-1.0 -Revision: $Rev: 3 $ -Author: Flick -Website: -Documentation: -SVN: -Description: A library to assist with click-binding -License: MIT -Dependencies: AceLibrary, AceEvent-2.0, AceLocale-2.2, AceOO-2.0, AceConsole-2.0 -]] - - -local version_major, version_minor = "ReBound-1.0", "$Rev: 3 $" - -if not AceLibrary then error(version_major .. " requires AceLibrary.") end -if not AceLibrary:IsNewVersion(version_major, version_minor) then return end -for _, lib in pairs({ "AceEvent-2.0", "AceLocale-2.2", "AceOO-2.0", "AceConsole-2.0" }) do - if not AceLibrary:HasInstance(lib) then error(version_major .. " requires "..lib) end -end - -local L = AceLibrary("AceLocale-2.2"):new("ReBound") - --- localization -L:RegisterTranslations( "enUS", function() - return { - ["none"] = true, - ["Click"] = true, - ["Right-click"] = true, - ["Shift-click"] = true, - ["Shift-right-click"] = true, - ["Right Click"] = true, - ["to select for binding"] = true, - ["to select for alternate (right-click) binding"] = true, - ["to clear binding"] = true, - ["to clear alternate (right-click) binding"] = true, - ["Press a key to assign binding"] = true, - ["is now unbound"] = true, - } -end ) - - - -local kbValidate = AceLibrary("AceConsole-2.0").keybindingValidateFunc - -local colorGreen = "|cff00ff00" -local colorOrange = "|cffffcc00" -local colorOff = "|r" - -local mouseButtonConvert = { - LeftButton = "BUTTON1", - RightButton = "BUTTON2", - MiddleButton = "BUTTON3", - Button4 = "BUTTON4", - Button5 = "BUTTON5" -} - --- TODO: localize -local keybindAbbreviations = { - [KEY_BACKSPACE] = "BkSp", - [KEY_BUTTON3] = "M-3", - [KEY_BUTTON4] = "M-4", - [KEY_BUTTON5] = "M-5", - [KEY_DOWN] = "Down", - [KEY_ESCAPE] = "Esc", - [KEY_INSERT] = "Ins", - [KEY_LEFT] = "Left", - [KEY_MOUSEWHEELDOWN] = "M-Down", - [KEY_MOUSEWHEELUP] = "M-Up", - [KEY_NUMLOCK] = "NumLk", - [KEY_NUMPAD0] = "Np0", - [KEY_NUMPAD1] = "Np1", - [KEY_NUMPAD2] = "Np2", - [KEY_NUMPAD3] = "Np3", - [KEY_NUMPAD4] = "Np4", - [KEY_NUMPAD5] = "Np5", - [KEY_NUMPAD6] = "Np6", - [KEY_NUMPAD7] = "Np7", - [KEY_NUMPAD8] = "Np8", - [KEY_NUMPAD9] = "Np9", - [KEY_NUMPADDECIMAL] = "Np.", - [KEY_NUMPADDIVIDE] = "Np/", - [KEY_NUMPADMINUS] = "Np-", - [KEY_NUMPADMULTIPLY] = "Np*", - [KEY_NUMPADPLUS] = "Np+", - [KEY_PAGEDOWN] = "PgDn", - [KEY_PAGEUP] = "PgUp", - [KEY_PRINTSCREEN] = "PrScr", - [KEY_RIGHT] = "Right", - [KEY_SCROLLLOCK] = "ScrLk", - [KEY_SPACE] = "Sp", - [KEY_UP] = "Up", -} - - -local ReBound = AceLibrary("AceOO-2.0").Class("AceEvent-2.0") - ---[[ - ReBound publishes the following events: - - -- temporary bindings (prior to SaveBindings() being called) - REBOUND_BIND_TEMP (id, key, targetFrameName, mouseButton) - REBOUND_UNBIND_TEMP (id, key) - - -- permanent bindings (fired all at once when SaveBindings() is called) - REBOUND_BIND (id, key, targetFrameName, mouseButton) - REBOUND_UNBIND (id, key) - - These events are published in response to click actions ONLY. This means - that if a key is unbound from a click-binding frame, and bound to some - other action, then REBOUND_UNBIND(id,key) will be fired. -]] - - ---[[ - Calls to new() which share ids will return an existing object with that id, similar - to AceLocale-2.2. -]] -ReBound.instances = { } -local super_new = ReBound.new -function ReBound:new( id ) - local instances = self.instances - instances[id] = instances[id] or super_new(self,id) - return instances[id] -end - - ---[[ - Class object constructor - - arguments: - id : the ID that will be provided in events. This can be absolutely - anything, but a string is recommended. -]] -local super_init = ReBound.super.prototype.init -function ReBound.prototype:init( id ) - super_init(self) - - self.id = id - self.frames = { } - self.pending = { } - self.bindings = { } -end - - - - ---[[ - Arguments: - key: A string representation of a key, suitable for passing to SetBinding. - target: The frame with an OnClick handler to which the click-binding should be attached - [button]: The mouse button to emulate. Default is "LeftButton". - [silent]: boolean - whether to suppress messages about keys being unbound. - - Returns: - nothing. - - Notes: - This does not save the bindings. -]] -function ReBound.prototype:SetBinding( key, target, button ) - if not key then error("ReBound:SetBinding() requires a key argument.") end - if not target then error("ReBound:SetBinding() requires a binding target argument") end - if key and not kbValidate(key) then error("ReBound:SetBinding(): invalid key code "..tostring(key)) end - - button = button or "LeftButton" - - -- prevent setting a binding that's already set - local current = { self:GetBinding(target,button) } - for _, b in pairs(current) do - if b == key then - return - end - end - - -- clear the old binding for the key. This isn't strictly necessary, but it allows us to collect - -- notification of the unbinding in one place (ClearBinding). - self:ClearBinding( key, nil, nil, silent ) - - -- clear the old binding for the target and button (silently) - self:ClearBinding( nil, target, button, true ) - - -- set the new binding - SetBindingClick(key, target:GetName(), button) - - -- store the temporary binding as "pending" for later notification - table.insert(self.pending, key) - - -- notify listeners, e.g. for displaying the setting - self:TriggerEvent("REBOUND_BIND_TEMP", self.id, key, target:GetName(), button) -end - - ---[[ - Arguments: - [key]: A string representation of a key, suitable for passing to SetBinding. This can be nil if target is specified. - [target]: The frame with a click keybinding to search for a key. - [button]: The mouse button to emulate. Default is "LeftButton". Only used with [target]. - [silent]: if true, omits printout. - - Returns: - nothing. - - Notes: - If key is provided, then the binding for that key is cleared. If key is not provided and target is provided, then - all the bindings attached to the click-binding for that target are cleared. - - This does NOT save the bindings. Call SaveBindings() to commit the bindings to disk. -]] -function ReBound.prototype:ClearBinding( key, target, button, silent ) - if not target and not key then error("ReBound:ClearBinding() requires a key or click-binding target argument") end - button = button or "LeftButton" - - local keys = key and { key } or { self:GetBinding(target,button) } - for _, k in ipairs(keys) do - -- Print a notification message - if k and not silent then - local action = GetBindingAction(k) - if action then - local name = GetBindingText(action,"BINDING_NAME_") - local keyTxt = GetBindingText(k,"KEY_") - -- make click-bindings look prettier - local f, b = name:match("CLICK (.+)\:(.+)") - if f then - name = f - if b ~= "LeftButton" then - if b == "RightButton" then b = L["Right Click"] end - name = f .."-"..b - end - end - if name and #name > 0 then - UIErrorsFrame:AddMessage(name.." ("..colorGreen..keyTxt..colorOff..") "..L["is now unbound"].."!") - end - end - end - SetBinding(k,nil) - table.insert(self.pending,k) - self:TriggerEvent("REBOUND_UNBIND_TEMP", self.id, k) - end -end - - ---[[ - Gets the keys currently click-bound to a frame. - - Arguments: - target: target frame to query - [button]: mouse button to emulate ("LeftButton", "RightButton") - - Returns: - key1, key2, key3, etc, as strings. -]] -function ReBound.prototype:GetBinding( target, button ) - if not target then error("ReBound:GetBinding() requires a target frame argument") end - button = button or "LeftButton" - return GetBindingKey("CLICK "..target:GetName()..":"..button) -end - - ---[[ - Gets the localized, abbreviated key cap text for the primary binding on a target. - Abbreviations are more aggressive than the standard Blizzard abbreviation - (which just shortens modifier keys) - - Arguments: - target: target frame to query - [abbrev]: boolean flag to abbreviate the result - [button]: mouse button to emulate ("LeftButton", "RightButton") - - Returns: - abbreviated, localized key label -]] -function ReBound.prototype:GetBindingText( target, abbrev, button ) - local key = self:GetBinding(target,button) - local txt = key and GetBindingText(key, "KEY_", abbrev and 1) or "" - - if txt and abbrev then - -- further abbreviate some key names - txt = string.gsub(txt, "[^%-]+$", keybindAbbreviations) - -- the above does not handle "num pad -" - txt = string.gsub(txt, KEY_NUMPADMINUS, keybindAbbreviations) - end - return txt -end - - ---[[ - Publishes permanent binding notification events. -]] -local function PublishBindings(self) - for _, key in ipairs(self.pending) do - local action = GetBindingAction(key) - local frame, button - if action then - frame, button = action:match("CLICK (.+)\:(.+)") - end - if frame == nil then - self:TriggerEvent("REBOUND_UNBIND", self.id, key) - else - self:TriggerEvent("REBOUND_BIND", self.id, key, frame, button) - end - end - self.pending = { } -end - - ---[[ - Saves the bindings using the current scheme. Also publishes events indicating that the - bindings have been saved/cleared permanently. -]] -function ReBound.prototype:SaveBindings() - SaveBindings(GetCurrentBindingSet()) -- will trigger an UPDATE_BINDINGS event. - PublishBindings(self) -end - - ---[[ - Reverts the bindings to the ones previously saved. Also publishes events indicating that the - bindings have been reverted. -]] -function ReBound.prototype:RevertBindings() - LoadBindings(GetCurrentBindingSet()) -- should trigger an UPDATE_BINDINGS event. - PublishBindings(self) -end - - ---[[ - Clears all bindings associated with registered frames. This is useful, for example, when switching profiles - and the keybinding data is stored in the profile. -]] -function ReBound.prototype:ClearRegisteredBindings() - for f, _ in pairs(self.frames) do - self:ClearBinding(nil,f,"LeftButton",true) - self:ClearBinding(nil,f,"RightButton",true) - end -end - - ---[[ - Registers a target frame by creating a click-binding frame and putting that frame in the list of - registered frames, which can then be all shown/hidden as one unit. - - Arguments: - target = the frame whose OnClick handler should be the target of keybinding - - Returns: - A clickbinder frame. -]] -function ReBound.prototype:Register( target ) - local f = self:CreateClickBindingFrame(target) - self.frames[target] = f - return f -end - - ---[[ - Unregisters a target frame by removing it from the internal list. Does nothing to the clickbinding frame. - - Arguments: - target = the frame whose OnClick handler should no longer be managed. do NOT pass the clickbinding frame. - - Returns: - nothing. -]] -function ReBound.prototype:Unregister( target ) - self.frames[target] = nil -end - - ---[[ - Unregisters all registered frames. -]] -function ReBound.prototype:UnregisterAll() - self.frames = { } -end - - - ---[[ - Shows all the registered click binding frames. -]] -function ReBound.prototype:ShowRegisteredFrames() - if InCombatLockdown() then - -- can't set bindings while in combat, so don't bother showing them - UIErrorsFrame:AddMessage(ERR_NOT_IN_COMBAT) - else - for _, f in pairs(self.frames) do - f:Show() - end - end -end - - ---[[ - Hides all the registered click binding frames. -]] -function ReBound.prototype:HideRegisteredFrames() - -- because these frames aren't protected, there's no restriction - -- on hiding them while in combat. - for _, f in pairs(self.frames) do - f:Hide() - end -end - --- click binding frame implementation functions -local function ShowTooltip1( self ) - local target = self:GetParent() - - GameTooltip:ClearLines() - GameTooltip:SetOwner(self,"ANCHOR_TOPRIGHT") - -- line 1: button name and current binding - GameTooltip:AddDoubleLine(target:GetName(), colorGreen.."("..(self.ReBound:GetBinding(target,"LeftButton") or L["none"])..")"..colorOff) - -- line 2: current right-click binding (if any) - local binding2 = self.ReBound:GetBinding(target,"RightButton") - if binding2 then - GameTooltip:AddDoubleLine(L["Right-click"]..":", colorGreen.."("..binding2..")"..colorOff) - end - -- line 3: instructions - GameTooltip:AddLine(colorGreen..L["Click"]..colorOff.." "..L["to select for binding"]) - GameTooltip:AddLine(colorGreen..L["Shift-click"]..colorOff.." "..L["to clear binding"]) - GameTooltip:AddLine("") - GameTooltip:AddLine(colorOrange..L["Right-click"]..colorOff.." "..L["to select for alternate (right-click) binding"]) - GameTooltip:AddLine(colorOrange..L["Shift-right-click"]..colorOff.." "..L["to clear alternate (right-click) binding"]) - GameTooltip:Show() -end - -local function ShowTooltip2( self ) - if GameTooltip:IsOwned(self) then - local target = self:GetParent() - GameTooltip:ClearLines() - GameTooltip:SetOwner(self) - local clickSuffix = self.selectedButton == "RightButton" and (" ("..L["Right-click"]..")") or "" - -- line 1: button name and binding to be set - GameTooltip:AddDoubleLine(target:GetName()..clickSuffix, colorGreen.."("..(self.ReBound:GetBinding(target,self.selectedButton) or L["none"])..")"..colorOff) - -- line 2: instructions - GameTooltip:AddLine(colorGreen..L["Press a key to assign binding"]..colorOff) - GameTooltip:Show() - end -end - -local function OnClick( self, button ) - if button == "LeftButton" or button == "RightButton" then - if IsShiftKeyDown() then - self.ReBound:ClearBinding( nil, self:GetParent(), button ) - self.selectedButton = nil - self:EnableKeyboard(false) - ShowTooltip1(self) - else - self.selectedButton = button - self:EnableKeyboard(true) - ShowTooltip2(self) - end - elseif self.selectedButton then - self.ReBound:SetBinding( mouseButtonConvert[button], self:GetParent(), self.selectedButton ) - self.selectedButton = nil - self:EnableKeyboard(false) - ShowTooltip1(self) - end -end - -local function OnEnter( self ) - -- clear current binding button - self.selectedButton = nil - -- show tooltip 1 - ShowTooltip1(self) -end - -local function OnLeave( self ) - -- disable keyboard input, if it was enabled - self:EnableKeyboard(false) - -- hide tooltip - if GameTooltip:IsOwned(self) then - GameTooltip:Hide() - end -end - -local function OnKeyDown( self, key ) - if key == nil or key == "UNKNOWN" or key == "SHIFT" or key == "CTRL" or key == "ALT" then - return - end - if IsShiftKeyDown() then key = "SHIFT-"..key end - if IsControlKeyDown() then key = "CTRL-"..key end - if IsAltKeyDown() then key = "ALT-"..key end - - if key ~= "ESCAPE" then - self.ReBound:SetBinding( key, self:GetParent(), self.selectedButton ) - end - - self:EnableKeyboard(false) - self.selectedButton = nil - ShowTooltip1(self) -end - ---[[ - Creates a click-binding frame attached to the target frame, which can be used for point-and-click keybind assignments. The - frame is initially hidden by default. It is not registered with ReBound for automatic show/hide: use Register() for that. - - Arguments: - target - the frame whose OnClick handler should be the target of keybinding - - Returns: - A clickbinder frame. -]] -function ReBound.prototype:CreateClickBindingFrame( target ) - local f = CreateFrame("Button", nil, target) - f.ReBound = self - f:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square") - f:SetToplevel(1) - f:SetFrameStrata("DIALOG") - f:RegisterForClicks("AnyUp") - f:SetScript("OnClick", OnClick) - f:SetScript("OnEnter", OnEnter) - f:SetScript("OnLeave", OnLeave) - f:SetScript("OnKeyDown", OnKeyDown) - f:SetAllPoints(target) - f:Hide() - return f -end - - - --- library setup - -local function activate( self, oldLib, oldDeactivate ) - -- copy the list of active instances - self.instances = { } - if oldLib and oldLib.instances then - for k,v in pairs(oldLib.instances) do - self.instances[k] = v - end - end - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -AceLibrary:Register(ReBound, version_major, version_minor, activate) -ReBound = nil
--- a/libs/Tablet-2.0/Tablet-2.0.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2758 +0,0 @@ ---[[ -Name: Tablet-2.0 -Revision: $Rev: 19577 $ -Author(s): ckknight (ckknight@gmail.com) -Website: http://ckknight.wowinterface.com/ -Documentation: http://www.wowace.com/index.php/Tablet-2.0 -SVN: http://svn.wowace.com/wowace/trunk/TabletLib/Tablet-2.0 -Description: A library to provide an efficient, featureful tooltip-style display. -Dependencies: AceLibrary, (optional) Dewdrop-2.0 -]] - -local MAJOR_VERSION = "Tablet-2.0" -local MINOR_VERSION = "$Revision: 19577 $" - -if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end -if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end - -local DEBUG = false - -local SCROLL_UP = "Scroll up" -local SCROLL_DOWN = "Scroll down" -local HINT = "Hint" -local DETACH = "Detach" -local DETACH_DESC = "Detach the tablet from its source." -local SIZE = "Size" -local SIZE_DESC = "Scale the tablet." -local CLOSE_MENU = "Close menu" -local CLOSE_MENU_DESC = "Close the menu." -local COLOR = "Background color" -local COLOR_DESC = "Set the background color." -local LOCK = "Lock" -local LOCK_DESC = "Lock the tablet in its current position. Alt+Right-click for menu or Alt+drag to drag it when locked." - -if GetLocale() == "deDE" then - SCROLL_UP = "Hochscrollen" - SCROLL_DOWN = "Runterscrollen" - HINT = "Hinweis" - DETACH = "L\195\182sen" - DETACH_DESC = "L\195\182st den Tooltip aus seiner Verankerung." - SIZE = "Gr\195\182\195\159e" - SIZE_DESC = "Gr\195\182\195\159e des Tooltips \195\164ndern." - CLOSE_MENU = "Menu schlie\195\159en" - CLOSE_MENU_DESC = "Schlie\195\159t das Menu." - COLOR = "Hintergrundfarbe" - COLOR_DESC = "Hintergrundfarbe setzen." - LOCK = "Sperren" - LOCK_DESC = "Sperrt die aktuelle Position vom Tooltip. Alt+Rechts-klick f\195\188rs Men\195\188 oder Alt+Verschieben f\195\188rs verschieben wenn es gesperrt ist." -elseif GetLocale() == "koKR" then - SCROLL_UP = "위로 스크롤" - SCROLL_DOWN = "아래로 스크롤" - HINT = "힌트" - DETACH = "분리" - DETACH_DESC = "테이블을 분리합니다." - SIZE = "크기" - SIZE_DESC = "테이블의 크기입니다." - CLOSE_MENU = "메뉴 닫기" - CLOSE_MENU_DESC = "메뉴를 닫습니다." - COLOR = "배경 색상" - COLOR_DESC = "배경 색상을 설정합니다." - LOCK = "고정" - LOCK_DESC = "현재 위치에 테이블을 고정합니다. 알트+우클릭 : 메뉴열기, 알트+드래그 : 고정된것을 드래그합니다." -elseif GetLocale() == "zhCN" then - SCROLL_UP = "向上翻转" - SCROLL_DOWN = "向上翻转" - HINT = "提示" - DETACH = "分离" - DETACH_DESC = "分离菜单为独立提示." - SIZE = "尺寸" - SIZE_DESC = "缩放菜单显示尺寸." - CLOSE_MENU = "关闭菜单" - CLOSE_MENU_DESC = "关闭菜单" - COLOR = "背景颜色" - COLOR_DESC = "设置菜单背景颜色." - LOCK = "锁定" - LOCK_DESC = "锁定菜单当前位置. alt+右键 将显示选项, alt+拖动 可以移动已锁定的菜单." -elseif GetLocale() == "zhTW" then - SCROLL_UP = "向上翻轉" - SCROLL_DOWN = "向上翻轉" - HINT = "提示" - DETACH = "分離" - DETACH_DESC = "分離選單為獨立提示。" - SIZE = "尺寸" - SIZE_DESC = "縮放選單顯示尺寸。" - CLOSE_MENU = "關閉選單" - CLOSE_MENU_DESC = "關閉選單" - COLOR = "背景顏色" - COLOR_DESC = "設置選單背景顏色。" - LOCK = "鎖定" - LOCK_DESC = "鎖定選單目前位置. Alt+右鍵 將顯示選項,Alt+拖動 可以移動已鎖定的選單。" -elseif GetLocale() == "frFR" then - SCROLL_UP = "Parcourir vers le haut" - SCROLL_DOWN = "Parcourir vers le bas" - HINT = "Astuce" - DETACH = "D\195\169tacher" - DETACH_DESC = "Permet de d\195\169tacher le tableau de sa source." - SIZE = "Taille" - SIZE_DESC = "Permet de changer l'\195\169chelle du tableau." - CLOSE_MENU = "Fermer le menu" - CLOSE_MENU_DESC = "Ferme ce menu." - COLOR = "Couleur du fond" - COLOR_DESC = "Permet de d\195\169finir la couleur du fond." - LOCK = "Bloquer" - LOCK_DESC = "Bloque le tableau \195\160 sa position actuelle. Alt+clic-droit pour le menu ou Alt+glisser pour le d\195\169placer quand il est bloqu\195\169." -end - -local start = GetTime() -local wrap -local GetProfileInfo -if DEBUG then - local tree = {} - local treeMemories = {} - local treeTimes = {} - local memories = {} - local times = {} - function wrap(value, name) - if type(value) == "function" then - local oldFunction = value - memories[name] = 0 - times[name] = 0 - return function(self, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60) - local pos = table.getn(tree) - table.insert(tree, name) - table.insert(treeMemories, 0) - table.insert(treeTimes, 0) - local t, mem = GetTime(), gcinfo() - 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, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60) - mem, t = gcinfo() - mem, GetTime() - t - if pos > 0 then - treeMemories[pos] = treeMemories[pos] + mem - treeTimes[pos] = treeTimes[pos] + t - end - local otherMem = table.remove(treeMemories) - if mem - otherMem > 0 then - memories[name] = memories[name] + mem - otherMem - end - times[name] = times[name] + t - table.remove(treeTimes) - table.remove(tree) - return r1, r2, r3, r4, r5, r6, r7, r8 - end - end - end - - function GetProfileInfo() - return GetTime() - start, times, memories - end -else - function wrap(value) - return value - end -end - -local MIN_TOOLTIP_SIZE = 200 -local TESTSTRING_EXTRA_WIDTH = 5 -local Tablet = {} -local function getsecond(_, value) - return value -end -local Dewdrop = nil -local CleanCategoryPool -local pool = {} - -local function del(t) - if t then - for k in pairs(t) do - t[k] = nil - end - setmetatable(t, nil) - pool[t] = true - end -end - -local new - -local function copy(parent) - local t = next(pool) or {} - pool[t] = nil - if parent then - for k,v in pairs(parent) do - t[k] = v - end - setmetatable(t, getmetatable(parent)) - end - return t -end - -function new(...) - local t = next(pool) or {} - pool[t] = nil - - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t -end - -local tmp -tmp = setmetatable({}, {__index = function(self, key) - local t = {} - tmp[key] = function(...) - for k in pairs(t) do - t[k] = nil - end - for i = 1, select('#', ...), 2 do - local k = select(i, ...) - if k then - t[k] = select(i+1, ...) - else - break - end - end - return t - end - return tmp[key] -end}) - -local headerSize, normalSize -if GameTooltipHeaderText then - _,headerSize = GameTooltipHeaderText:GetFont() -else - headerSize = 14 -end -if GameTooltipText then - _,normalSize = GameTooltipText:GetFont() -else - normalSize = 12 -end -local tooltip -local testString -local TabletData = {} -local Category = {} -local Line = {} -do - local TabletData_mt = { __index = TabletData } - function TabletData:new(tablet) - if not testString then - testString = UIParent:CreateFontString() - testString:Hide() - end - local self = new() - self.categories = new() - self.id = 0 - self.width = 0--(MIN_TOOLTIP_SIZE - 20)*tablet.fontSizePercent - self.tablet = tablet - self.title = "Title" - self.titleR, self.titleG, self.titleB = nil, nil, nil - setmetatable(self, TabletData_mt) - return self - end - - function TabletData:del() - for k, v in ipairs(self.categories) do - v:del() - end - del(self.categories) - del(self) - end - - function TabletData:Display() - if self.tablet == tooltip or self.tablet.registration.showTitleWhenDetached then - local info = new( - 'hideBlankLine', true, - 'text', self.title, - 'justify', "CENTER", - 'font', GameTooltipHeaderText, - 'isTitle', true - ) - if self.titleR then - info.textR = self.titleR - info.textG = self.titleG - info.textB = self.titleB - end - self:AddCategory(info, 1) - del(info) - end - if self.tablet == tooltip or self.tablet.registration.showHintWhenDetached then - if self.hint then - self:AddCategory(nil):AddLine( - 'text', HINT .. ": " .. self.hint, - 'textR', 0, - 'textG', 1, - 'textB', 0, - 'wrap', true - ) - end - end - - local tabletData = self.tabletData - local width - for k, v in ipairs(self.categories) do - if v.columns <= 2 then - width = v.x1 - else - width = v.x1 + v.x2 + v.x3 + v.x4 + v.x5 + v.x6 + (v.columns - 1) * 20 - end - if self.width < width then - self.width = width - end - end - - local good = false - local lastTitle = true - for k, v in ipairs(self.categories) do - if lastTitle then - v.hideBlankLine = true - lastTitle = false - end - if v:Display(self.tablet) then - good = true - end - if v.isTitle then - lastTitle = true - end - end - if not good then - if self.tablet == tooltip or not self.tablet.registration.hideWhenEmpty then - local width - local info = new( - 'hideBlankLine', true, - 'text', self.title, - 'justify', "CENTER", - 'font', GameTooltipHeaderText, - 'isTitle', true - ) - local cat = self:AddCategory(info) - del(info) - self.width = self.categories[table.getn(self.categories)].x1 - cat:Display(self.tablet) - else - self.tablet:__Hide() - self.tablet.tmpHidden = true - end - else - self.tablet:__Show() - self.tablet.tmpHidden = nil - end - end - - function TabletData:AddCategory(info, index) - local made = false - if not info then - made = true - info = new() - end - local cat = Category:new(self, info) - if index then - table.insert(self.categories, index, cat) - else - table.insert(self.categories, cat) - end - if made then - del(info) - end - return cat - end - - function TabletData:SetHint(hint) - self.hint = hint - end - - function TabletData:SetTitle(title) - self.title = title or "Title" - end - - function TabletData:SetTitleColor(r, g, b) - self.titleR = r - self.titleG = g - self.titleB = b - end -end -do - local Category_mt = { __index = Category } - function Category:new(tabletData, info, superCategory) - local self = copy(info) - if superCategory and not self.noInherit then - self.superCategory = superCategory.superCategory - for k, v in pairs(superCategory) do - if string.find(k, "^child_") then - local k = strsub(k, 7) - if self[k] == nil then - self[k] = v - end - end - end - self.columns = superCategory.columns - else - self.superCategory = self - end - self.tabletData = tabletData - self.lines = new() - if not self.columns then - self.columns = 1 - end - self.x1 = 0 - self.x2 = 0 - self.x3 = 0 - self.x4 = 0 - self.x5 = 0 - self.x6 = 0 - setmetatable(self, Category_mt) - self.lastWasTitle = nil - if self.text or self.text2 or self.text3 or self.text4 or self.text5 or self.text6 then - local x = new( - 'category', category, - 'text', self.text, - 'textR', self.textR or 1, - 'textG', self.textG or 1, - 'textB', self.textB or 1, - 'fakeChild', true, - 'func', self.func, - 'arg1', self.arg1, - 'arg2', self.arg2, - 'arg3', self.arg3, - 'hasCheck', self.hasCheck, - 'checked', self.checked, - 'checkIcon', self.checkIcon, - 'isRadio', self.isRadio, - 'font', self.font, - 'size', self.size, - 'wrap', self.wrap, - 'catStart', true, - 'indentation', self.indentation, - 'noInherit', true, - 'justify', self.justify, - 'justify2', self.justify2, - 'justify3', self.justify3, - 'justify4', self.justify4, - 'justify5', self.justify5, - 'justify6', self.justify6 - ) - if self.isTitle then - x.textR = self.textR or 1 - x.textG = self.textG or 0.823529 - x.textB = self.textB or 0 - else - x.textR = self.textR or 1 - x.textG = self.textG or 1 - x.textB = self.textB or 1 - end - x.text2 = self.text2 - x.text3 = self.text3 - x.text4 = self.text4 - x.text5 = self.text5 - x.text6 = self.text6 - x.text2R = self.text2R or self.textR2 or 1 - x.text2G = self.text2G or self.textG2 or 1 - x.text2B = self.text2B or self.textB2 or 1 - x.text3R = self.text3R or self.textR3 or 1 - x.text3G = self.text3G or self.textG3 or 1 - x.text3B = self.text3B or self.textB3 or 1 - x.text4R = self.text4R or self.textR4 or 1 - x.text4G = self.text4G or self.textG4 or 1 - x.text4B = self.text4B or self.textB4 or 1 - x.text5R = self.text5R or self.textR5 or 1 - x.text5G = self.text5G or self.textG5 or 1 - x.text5B = self.text5B or self.textB5 or 1 - x.text6R = self.text6R or self.textR6 or 1 - x.text6G = self.text6G or self.textG6 or 1 - x.text6B = self.text6B or self.textB6 or 1 - x.font2 = self.font2 - x.font3 = self.font3 - x.font4 = self.font4 - x.font5 = self.font5 - x.font6 = self.font6 - x.size2 = self.size2 - x.size3 = self.size3 - x.size4 = self.size4 - x.size5 = self.size5 - x.size6 = self.size6 - self:AddLine(x) - del(x) - self.lastWasTitle = true - end - return self - end - - function Category:del() - local prev = garbageLine - for k, v in pairs(self.lines) do - v:del() - end - del(self.lines) - del(self) - end - - function Category:AddLine(...) - self.lastWasTitle = nil - local line - local k1 = ... - if type(k1) == "table" then - local k2 = select(2, ...) - Line:new(self, k1, k2) - else - local info = new(...) - Line:new(self, info) - info = del(info) - end - end - - function Category:AddCategory(...) - local lastWasTitle = self.lastWasTitle - self.lastWasTitle = nil - local info - local k1 = ... - if type(k1) == "table" then - info = k1 - else - info = new(...) - end - if lastWasTitle or table.getn(self.lines) == 0 then - info.hideBlankLine = true - end - local cat = Category:new(self.tabletData, info, self) - table.insert(self.lines, cat) - if info ~= k1 then - info = del(info) - end - return cat - end - - function Category:HasChildren() - local hasChildren = false - for k, v in ipairs(self.lines) do - if v.HasChildren then - if v:HasChildren() then - return true - end - end - if not v.fakeChild then - return true - end - end - return false - end - - local lastWasTitle = false - function Category:Display(tablet) - if not self.isTitle and not self.showWithoutChildren and not self:HasChildren() then - return false - end - if not self.hideBlankLine and not lastWasTitle then - local info = new( - 'blank', true, - 'fakeChild', true - ) - self:AddLine(info, 1) - del(info) - end - local good = false - if table.getn(self.lines) > 0 then - self.tabletData.id = self.tabletData.id + 1 - self.id = self.tabletData.id - for k, v in ipairs(self.lines) do - if v:Display(tablet) then - good = true - end - end - end - lastWasTitle = self.isTitle - return good - end -end -do - local Line_mt = { __index = Line } - function Line:new(category, info, position) - local self = copy(info) - if not info.noInherit then - for k, v in pairs(category) do - if string.find(k, "^child_") then - local k = strsub(k, 7) - if self[k] == nil then - self[k] = v - end - end - end - end - self.category = category - if position then - table.insert(category.lines, position, self) - else - table.insert(category.lines, self) - end - setmetatable(self, Line_mt) - local columns = category.columns - if columns == 1 then - if not self.justify then - self.justify = "LEFT" - end - elseif columns == 2 then - self.justify = "LEFT" - self.justify2 = "RIGHT" - if self.wrap then - self.wrap2 = false - end - elseif columns == 3 then - if not self.justify then - self.justify = "LEFT" - end - if not self.justify2 then - self.justify2 = "CENTER" - end - if not self.justify3 then - self.justify3 = "RIGHT" - end - if self.wrap then - self.wrap2 = false - self.wrap3 = false - elseif self.wrap2 then - self.wrap3 = false - end - elseif columns == 4 then - if not self.justify then - self.justify = "LEFT" - end - if not self.justify2 then - self.justify2 = "CENTER" - end - if not self.justify3 then - self.justify3 = "CENTER" - end - if not self.justify4 then - self.justify4 = "RIGHT" - end - if self.wrap then - self.wrap2 = false - self.wrap3 = false - self.wrap4 = false - elseif self.wrap2 then - self.wrap3 = false - self.wrap4 = false - elseif self.wrap3 then - self.wrap4 = false - end - elseif columns == 5 then - if not self.justify then - self.justify = "LEFT" - end - if not self.justify2 then - self.justify2 = "CENTER" - end - if not self.justify3 then - self.justify3 = "CENTER" - end - if not self.justify4 then - self.justify4 = "CENTER" - end - if not self.justify5 then - self.justify5 = "RIGHT" - end - if self.wrap then - self.wrap2 = false - self.wrap3 = false - self.wrap4 = false - self.wrap5 = false - elseif self.wrap2 then - self.wrap3 = false - self.wrap4 = false - self.wrap5 = false - elseif self.wrap3 then - self.wrap4 = false - self.wrap5 = false - elseif self.wrap4 then - self.wrap5 = false - end - elseif columns == 6 then - if not self.justify then - self.justify = "LEFT" - end - if not self.justify2 then - self.justify2 = "CENTER" - end - if not self.justify3 then - self.justify3 = "CENTER" - end - if not self.justify4 then - self.justify4 = "CENTER" - end - if not self.justify5 then - self.justify5 = "CENTER" - end - if not self.justify6 then - self.justify6 = "RIGHT" - end - if self.wrap then - self.wrap2 = false - self.wrap3 = false - self.wrap4 = false - self.wrap5 = false - self.wrap6 = false - elseif self.wrap2 then - self.wrap3 = false - self.wrap4 = false - self.wrap5 = false - self.wrap6 = false - elseif self.wrap3 then - self.wrap4 = false - self.wrap5 = false - self.wrap6 = false - elseif self.wrap4 then - self.wrap5 = false - self.wrap6 = false - elseif self.wrap5 then - self.wrap6 = false - end - end - if self.textR2 then - self.text2R, self.textR2 = self.text2R or self.textR2 - self.text2G, self.textG2 = self.text2G or self.textG2 - self.text2B, self.textB2 = self.text2B or self.textB2 - if self.textR3 then - self.text3R, self.textR3 = self.text3R or self.textR3 - self.text3G, self.textG3 = self.text3G or self.textG3 - self.text3B, self.textB3 = self.text3B or self.textB3 - if self.textR4 then - self.text4R, self.textR4 = self.text4R or self.textR4 - self.text4G, self.textG4 = self.text4G or self.textG4 - self.text4B, self.textB4 = self.text4B or self.textB4 - if self.textR5 then - self.text5R, self.textR5 = self.text5R or self.textR5 - self.text5G, self.textG5 = self.text5G or self.textG5 - self.text5B, self.textB5 = self.text5B or self.textB5 - if self.textR5 then - self.text6R, self.textR6 = self.text6R or self.textR6 - self.text6G, self.textG6 = self.text6G or self.textG6 - self.text6B, self.textB6 = self.text6B or self.textB6 - end - end - end - end - end - if not self.indentation or self.indentation < 0 then - self.indentation = 0 - end - if not self.font then - self.font = GameTooltipText - end - if not self.font2 then - self.font2 = self.font - end - if not self.font3 then - self.font3 = self.font - end - if not self.font4 then - self.font4 = self.font - end - if not self.font5 then - self.font5 = self.font - end - if not self.font6 then - self.font6 = self.font - end - if not self.size then - _,self.size = self.font:GetFont() - end - if not self.size2 then - _,self.size2 = self.font2:GetFont() - end - if not self.size3 then - _,self.size3 = self.font3:GetFont() - end - if not self.size4 then - _,self.size4 = self.font4:GetFont() - end - if not self.size5 then - _,self.size5 = self.font5:GetFont() - end - if not self.size6 then - _,self.size6 = self.font6:GetFont() - end - - local fontSizePercent = category.tabletData.tablet.fontSizePercent - local w = 0 - self.checkWidth = 0 - if self.text then - if not self.wrap then - testString:SetWidth(0) - testString:SetFontObject(self.font) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size * fontSizePercent, flags) - testString:SetText(self.text) - local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 - self.checkWidth = checkWidth - w = testString:GetWidth() + self.indentation * fontSizePercent + checkWidth + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x1 < w then - category.superCategory.x1 = w - end - else - if columns == 1 then - testString:SetWidth(0) - testString:SetFontObject(self.font) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size * fontSizePercent, flags) - testString:SetText(self.text) - local checkWidth = self.hasCheck and self.size * fontSizePercent or 0 - self.checkWidth = checkWidth - w = testString:GetWidth() + self.indentation * fontSizePercent + checkWidth + TESTSTRING_EXTRA_WIDTH - if w > (MIN_TOOLTIP_SIZE - 20) * fontSizePercent then - w = (MIN_TOOLTIP_SIZE - 20) * fontSizePercent - end - else - w = MIN_TOOLTIP_SIZE * fontSizePercent / 2 - end - if category.superCategory.x1 < w then - category.superCategory.x1 = w - end - end - end - if columns == 2 and self.text2 then - if not self.wrap2 then - testString:SetWidth(0) - testString:SetFontObject(self.font2) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size2 * fontSizePercent, flags) - testString:SetText(self.text2) - w = w + 40 * fontSizePercent + testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x1 < w then - category.superCategory.x1 = w - end - else - w = w + 40 * fontSizePercent + MIN_TOOLTIP_SIZE * fontSizePercent / 2 - if category.superCategory.x1 < w then - category.superCategory.x1 = w - end - end - elseif columns >= 3 then - if self.text2 then - if not self.wrap2 then - testString:SetWidth(0) - testString:SetFontObject(self.font2) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size2 * fontSizePercent, flags) - testString:SetText(self.text2) - local w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x2 < w then - category.superCategory.x2 = w - end - else - local w = MIN_TOOLTIP_SIZE / 2 - if category.superCategory.x2 < w then - category.superCategory.x2 = w - end - end - end - if self.text3 then - if not self.wrap3 then - testString:SetWidth(0) - testString:SetFontObject(self.font3) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size3 * fontSizePercent, flags) - testString:SetText(self.text3) - local w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x3 < w then - category.superCategory.x3 = w - end - else - local w = MIN_TOOLTIP_SIZE / 2 - if category.superCategory.x3 < w then - category.superCategory.x3 = w - end - end - end - if columns >= 4 then - if self.text4 then - if not self.wrap4 then - testString:SetWidth(0) - testString:SetFontObject(self.font4) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size4 * fontSizePercent, flags) - testString:SetText(self.text4) - w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x4 < w then - category.superCategory.x4 = w - end - else - local w = MIN_TOOLTIP_SIZE / 2 - if category.superCategory.x4 < w then - category.superCategory.x4 = w - end - end - end - if columns >= 5 then - if self.text5 then - if not self.wrap5 then - testString:SetWidth(0) - testString:SetFontObject(self.font5) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size5 * fontSizePercent, flags) - testString:SetText(self.text5) - w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x5 < w then - category.superCategory.x5 = w - end - else - local w = MIN_TOOLTIP_SIZE / 2 - if category.superCategory.x5 < w then - category.superCategory.x5 = w - end - end - end - if columns >= 6 then - if self.text6 then - if not self.wrap6 then - testString:SetWidth(0) - testString:SetFontObject(self.font6) - local font,_,flags = testString:GetFont() - testString:SetFont(font, self.size6 * fontSizePercent, flags) - testString:SetText(self.text6) - w = testString:GetWidth() + TESTSTRING_EXTRA_WIDTH - if category.superCategory.x6 < w then - category.superCategory.x6 = w - end - else - local w = MIN_TOOLTIP_SIZE / 2 - if category.superCategory.x6 < w then - category.superCategory.x6 = w - end - end - end - end - end - end - end - return self - end - - function Line:del() - del(self) - end - - function Line:Display(tablet) - tablet:AddLine(self) - return true - end -end - -local function button_OnEnter() - if type(this.self:GetScript("OnEnter")) == "function" then - this.self:GetScript("OnEnter")() - end - this.highlight:Show() -end - -local function button_OnLeave() - if type(this.self:GetScript("OnLeave")) == "function" then - this.self:GetScript("OnLeave")() - end - this.highlight:Hide() -end - -local function NewLine(self) - if self.maxLines <= self.numLines then - self.maxLines = self.maxLines + 1 - local button = CreateFrame("Button", nil, self) - button.indentation = 0 - local check = button:CreateTexture(nil, "ARTWORK") - local left = button:CreateFontString(nil, "ARTWORK") - local right = button:CreateFontString(nil, "ARTWORK") - local third = button:CreateFontString(nil, "ARTWORK") - local fourth = button:CreateFontString(nil, "ARTWORK") - local fifth = button:CreateFontString(nil, "ARTWORK") - local sixth = button:CreateFontString(nil, "ARTWORK") - local highlight = button:CreateTexture(nil, "BACKGROUND") - highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight") - button.highlight = highlight - highlight:SetBlendMode("ADD") - highlight:SetAllPoints(button) - highlight:Hide() - table.insert(self.buttons, button) - table.insert(self.checks, check) - table.insert(self.lefts, left) - table.insert(self.rights, right) - table.insert(self.thirds, third) - table.insert(self.fourths, fourth) - table.insert(self.fifths, fifth) - table.insert(self.sixths, sixth) - left:SetWidth(0) - if self.maxLines == 1 then - left:SetFontObject(GameTooltipHeaderText) - right:SetFontObject(GameTooltipHeaderText) - third:SetFontObject(GameTooltipHeaderText) - fourth:SetFontObject(GameTooltipHeaderText) - fifth:SetFontObject(GameTooltipHeaderText) - sixth:SetFontObject(GameTooltipHeaderText) - left:SetJustifyH("CENTER") - button:SetPoint("TOPLEFT", self, "TOPLEFT", 8, -10) - else - left:SetFontObject(GameTooltipText) - right:SetFontObject(GameTooltipText) - third:SetFontObject(GameTooltipText) - fourth:SetFontObject(GameTooltipText) - fifth:SetFontObject(GameTooltipText) - sixth:SetFontObject(GameTooltipText) - button:SetPoint("TOPLEFT", self.buttons[self.maxLines - 1], "BOTTOMLEFT", 0, -2) - end - button:SetScript("OnEnter", button_OnEnter) - button:SetScript("OnLeave", button_OnLeave) - button.check = check - button.self = self - button:SetPoint("RIGHT", self, "RIGHT", -12, 0) - check.shown = false - check:SetPoint("TOPLEFT", button, "TOPLEFT") - left:SetPoint("TOPLEFT", check, "TOPLEFT") - right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * self.fontSizePercent, 0) - third:SetPoint("TOPLEFT", right, "TOPRIGHT", 20 * self.fontSizePercent, 0) - fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", 20 * self.fontSizePercent, 0) - fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", 20 * self.fontSizePercent, 0) - sixth:SetPoint("TOPLEFT", fifth, "TOPRIGHT", 20 * self.fontSizePercent, 0) - right:SetJustifyH("RIGHT") - local _,size = GameTooltipText:GetFont() - check:SetHeight(size * 1.5) - check:SetWidth(size * 1.5) - check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - check:SetAlpha(0) - if not button.clicked then - button:SetScript("OnMouseWheel", self:GetScript("OnMouseWheel")) - button:EnableMouseWheel(true) - button:Hide() - end - check:Show() - left:Hide() - right:Hide() - third:Hide() - fourth:Hide() - fifth:Hide() - sixth:Hide() - end -end -NewLine = wrap(NewLine, "NewLine") - -local function GetMaxLinesPerScreen(self) - if self == tooltip then - return floor(50 / self.fontSizePercent) - else - return floor(30 / self.fontSizePercent) - end -end -GetMaxLinesPerScreen = wrap(GetMaxLinesPerScreen, "GetMaxLinesPerScreen") - -local detachedTooltips = {} -local AcquireDetachedFrame, ReleaseDetachedFrame -local function AcquireFrame(self, registration, data, detachedData) - if not detachedData then - detachedData = data - end - if tooltip then - tooltip.data = data - tooltip.detachedData = detachedData - local fontSizePercent = tooltip.data and tooltip.data.fontSizePercent or 1 - local transparency = tooltip.data and tooltip.data.transparency or 0.75 - local r = tooltip.data and tooltip.data.r or 0 - local g = tooltip.data and tooltip.data.g or 0 - local b = tooltip.data and tooltip.data.b or 0 - tooltip:SetFontSizePercent(fontSizePercent) - tooltip:SetTransparency(transparency) - tooltip:SetColor(r, g, b) - else - tooltip = CreateFrame("Frame", "Tablet20Frame", UIParent) - self.tooltip = tooltip - tooltip.data = data - tooltip.detachedData = detachedData - tooltip:EnableMouse(true) - tooltip:EnableMouseWheel(true) - tooltip:SetFrameStrata("TOOLTIP") - tooltip:SetFrameLevel(10) - local backdrop = new( - 'bgFile', "Interface\\Buttons\\WHITE8X8", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'tileSize', 16, - 'edgeSize', 16, - 'insets', new( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ) - ) - tooltip:SetBackdrop(backdrop) - del(backdrop.insets) - del(backdrop) - tooltip:SetBackdropColor(0, 0, 0, 1) - - tooltip.numLines = 0 - tooltip.owner = nil - tooltip.fontSizePercent = tooltip.data and tooltip.data.fontSizePercent or 1 - tooltip.maxLines = 0 - tooltip.buttons = {} - tooltip.checks = {} - tooltip.lefts = {} - tooltip.rights = {} - tooltip.thirds = {} - tooltip.fourths = {} - tooltip.fifths = {} - tooltip.sixths = {} - tooltip.transparency = tooltip.data and tooltip.data.transparency or 0.75 - tooltip:SetBackdropColor(0, 0, 0, tooltip.transparency) - tooltip:SetBackdropBorderColor(1, 1, 1, tooltip.transparency) - tooltip.scroll = 0 - - tooltip:SetScript("OnUpdate", function() - if not tooltip.updating and not tooltip.enteredFrame then - tooltip.scroll = 0 - tooltip:Hide() - tooltip.registration.tooltip = nil - tooltip.registration = nil - end - end) - - tooltip:SetScript("OnEnter", function() - if tooltip.clickable then - tooltip.enteredFrame = true - end - end) - - tooltip:SetScript("OnLeave", function() - if not tooltip.updating then - tooltip.enteredFrame = false - end - end) - - tooltip:SetScript("OnMouseWheel", function() - tooltip.updating = true - tooltip:Scroll(arg1 < 0) - tooltip.updating = false - end) - - NewLine(tooltip) - - tooltip.scrollUp = tooltip:CreateFontString(nil, "ARTWORK") - tooltip.scrollUp:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2) - tooltip.scrollUp:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10) - tooltip.scrollUp:SetFontObject(GameTooltipText) - tooltip.scrollUp:Hide() - local font,_,flags = tooltip.scrollUp:GetFont() - tooltip.scrollUp:SetFont(font, normalSize * tooltip.fontSizePercent, flags) - tooltip.scrollUp:SetJustifyH("CENTER") - tooltip.scrollUp:SetTextColor(1, 0.823529, 0) - tooltip.scrollUp:SetText(" ") - - tooltip.scrollDown = tooltip:CreateFontString(nil, "ARTWORK") - tooltip.scrollDown:SetPoint("TOPLEFT", tooltip.buttons[1], "BOTTOMLEFT", 0, -2) - tooltip.scrollDown:SetPoint("RIGHT", tooltip, "RIGHT", 0, -10) - tooltip.scrollDown:SetFontObject(GameTooltipText) - tooltip.scrollDown:Hide() - local font,_,flags = tooltip.scrollUp:GetFont() - tooltip.scrollDown:SetFont(font, normalSize * tooltip.fontSizePercent, flags) - tooltip.scrollDown:SetJustifyH("CENTER") - tooltip.scrollDown:SetTextColor(1, 0.823529, 0) - tooltip.scrollDown:SetText(" ") - - function tooltip:SetOwner(o) - self:Hide(o) - self.owner = o - end - tooltip.SetOwner = wrap(tooltip.SetOwner, "tooltip:SetOwner") - - function tooltip:IsOwned(o) - return self.owner == o - end - tooltip.IsOwned = wrap(tooltip.IsOwned, "tooltip:IsOwned") - - function tooltip:ClearLines(hide) - CleanCategoryPool(self) - for i = 1, self.numLines do - local button = self.buttons[i] - local check = self.checks[i] - if not button.clicked or hide then - button:Hide() - end - check.shown = false - check:SetAlpha(0) - end - self.numLines = 0 - end - tooltip.ClearLines = wrap(tooltip.ClearLines, "tooltip:ClearLines") - - function tooltip:NumLines() - return self.numLines - end - - local lastWidth - local old_tooltip_Hide = tooltip.Hide - tooltip.__Hide = old_tooltip_Hide - function tooltip:Hide(newOwner) - if self == tooltip or newOwner == nil then - old_tooltip_Hide(self) - end - self:ClearLines(true) - self.owner = nil - self.lastWidth = nil - self.tmpHidden = nil - end - tooltip.Hide = wrap(tooltip.Hide, "tooltip:Hide") - - local old_tooltip_Show = tooltip.Show - tooltip.__Show = old_tooltip_Show - function tooltip:Show(tabletData) - if self.owner == nil or self.notInUse then - return - end - if not self.tmpHidden then - old_tooltip_Show(self) - end - - local maxWidth = tabletData and tabletData.width or self:GetWidth() - 20 - local hasWrap = false - local screenWidth = GetScreenWidth() - local scrollMax = self.numLines - if scrollMax > GetMaxLinesPerScreen(self) + self.scroll then - scrollMax = GetMaxLinesPerScreen(self) + self.scroll - end - local numColumns - - local height = 20 - if scrollMax ~= self.numLines then - self.scrollDown:SetWidth(maxWidth) - height = height + self.scrollDown:GetHeight() + 2 - end - if self.scroll ~= 0 then - self.scrollUp:SetWidth(maxWidth) - height = height + self.scrollUp:GetHeight() + 2 - end - self:SetWidth(maxWidth + 20) - - local tmp = self.scroll + 1 - if tmp ~= 1 then - tmp = tmp + 1 - end - for i = 1, self.numLines do - if i < tmp or i > scrollMax or (i == scrollMax and i ~= self.numLines) then - self.buttons[i]:ClearAllPoints() - self.buttons[i]:Hide() - else - local button = self.buttons[i] - local left = self.lefts[i] - local right = self.rights[i] - local check = self.checks[i] - button:SetWidth(maxWidth) - button:SetHeight(math.max(left:GetHeight(), right:GetHeight())) - height = height + button:GetHeight() + 2 - if i == self.scroll + 1 then - button:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10) - else - button:SetPoint("TOPLEFT", self.buttons[i - 1], "BOTTOMLEFT", 0, -2) - end - if button.clicked then - check:SetPoint("TOPLEFT", button, "TOPLEFT", button.indentation * self.fontSizePercent + (check.width - check:GetWidth()) / 2 + 1, -1) - else - check:SetPoint("TOPLEFT", button, "TOPLEFT", button.indentation * self.fontSizePercent + (check.width - check:GetWidth()) / 2, 0) - end - button:Show() - end - end - if self.scroll ~= 0 then - self.scrollUp:SetPoint("TOPLEFT", self, "TOPLEFT", 10, -10) - self.buttons[self.scroll + 2]:SetPoint("TOPLEFT", self.scrollUp, "BOTTOMLEFT", 0, -2) - self.scrollUp:SetText(SCROLL_UP .. " (" .. self.scroll + 2 .. " / " .. self.numLines .. ")") - self.scrollUp:Show() - else - self.scrollUp:Hide() - end - if scrollMax ~= self.numLines and self.buttons[scrollMax - 1] then - self.scrollDown:SetPoint("TOPLEFT", self.buttons[scrollMax - 1], "BOTTOMLEFT", 0, -2) - self.scrollDown:SetText(SCROLL_DOWN .. " (" .. scrollMax - 1 .. " / " .. self.numLines .. ")") - self.scrollDown:Show() - else - self.scrollDown:Hide() - end - self:SetHeight(height) - end - tooltip.Show = wrap(tooltip.Show, "tooltip:Show") - - local lastMouseDown - local function button_OnClick() - if this.self:HasScript("OnClick") and type(this.self:GetScript("OnClick")) == "function" then - this.self:GetScript("OnClick")() - end - if arg1 == "RightButton" then - if this.self:HasScript("OnClick") and type(this.self:GetScript("OnClick")) == "function" then - this.self:GetScript("OnClick")() - end - elseif arg1 == "LeftButton" then - if this.self.preventClick == nil or GetTime() > this.self.preventClick and GetTime() < lastMouseDown + 0.5 then - this.self.preventClick = nil - this.self.updating = true - this.self.preventRefresh = true - this.func(this.a1, this.a2, this.a3) - if this.self and this.self.registration then - this.self.preventRefresh = false - this.self:children() - this.self.updating = false - end - end - end - end - local function button_OnMouseUp() - if this.self:HasScript("OnMouseUp") and type(this.self:GetScript("OnMouseUp")) == "function" then - this.self:GetScript("OnMouseUp")() - end - if arg1 ~= "RightButton" then - if this.clicked then - local a,b,c,d,e = this.check:GetPoint(1) - this.check:SetPoint(a,b,c,d-1,e+1) - this.clicked = false - end - end - end - local function button_OnMouseDown() - if this.self:HasScript("OnMouseDown") and type(this.self:GetScript("OnMouseDown")) == "function" then - this.self:GetScript("OnMouseDown")() - end - lastMouseDown = GetTime() - if arg1 ~= "RightButton" then - local a,b,c,d,e = this.check:GetPoint(1) - this.check:SetPoint(a,b,c,d+1,e-1) - this.clicked = true - end - end - function tooltip:AddLine(info) - local category = info.category.superCategory - local maxWidth = category.tabletData.width - local text = info.blank and "\n" or info.text - local id = info.id - local func = info.func - local checked = info.checked - local isRadio = info.isRadio - local checkTexture = info.checkTexture - local fontSizePercent = self.fontSizePercent - if not info.font then - info.font = GameTooltipText - end - if not info.size then - _,info.size = info.font:GetFont() - end - local catStart = false - local columns = category and category.columns or 1 - local x1, x2, x3, x4, x5, x6 - if category then - x1, x2, x3, x4, x5, x6 = category.x1, category.x2, category.x3, category.x4, category.x5, category.x6 - else - x1, x2, x3, x4, x5, x6 = 0, 0, 0, 0, 0, 0 - end - if info.isTitle then - justAddedTitle = true - end - - self.numLines = self.numLines + 1 - NewLine(self) - self.lefts[self.numLines]:Show() - self.buttons[self.numLines]:Show() - num = self.numLines - - local button = self.buttons[num] - button.indentation = info.indentation - local left = self.lefts[num] - local right = self.rights[num] - local third = self.thirds[num] - local fourth = self.fourths[num] - local fifth = self.fifths[num] - local sixth = self.sixths[num] - local check = self.checks[num] - do -- if columns >= 1 then - left:SetFontObject(info.font) - left:SetText(text) - left:Show() - if info.textR and info.textG and info.textB then - left:SetTextColor(info.textR, info.textG, info.textB) - else - left:SetTextColor(1, 0.823529, 0) - end - local a,_,b = left:GetFont() - left:SetFont(a, info.size * fontSizePercent, b) - left:SetJustifyH(info.justify) - if columns < 2 then - right:SetText(nil) - right:Hide() - right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * fontSizePercent, 0) - right:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) - third:SetText(nil) - third:Hide() - fourth:SetText(nil) - fourth:Hide() - fifth:SetText(nil) - fifth:Hide() - sixth:SetText(nil) - sixth:Hide() - else - right:SetFontObject(info.font2) - right:SetText(info.text2) - right:Show() - if info.text2R and info.text2G and info.text2B then - right:SetTextColor(info.text2R, info.text2G, info.text2B) - else - right:SetTextColor(1, 0.823529, 0) - end - local a,_,b = right:GetFont() - right:SetFont(a, info.size2 * fontSizePercent, b) - right:SetJustifyH(info.justify2) - if columns < 3 then - right:SetPoint("TOPLEFT", left, "TOPRIGHT", 40 * fontSizePercent, 0) - right:SetPoint("TOPRIGHT", button, "TOPRIGHT", -5, 0) - third:SetText(nil) - third:Hide() - fourth:SetText(nil) - fourth:Hide() - fifth:SetText(nil) - fifth:Hide() - sixth:SetText(nil) - sixth:Hide() - else - third:SetFontObject(info.font3) - third:SetText(info.text3) - third:Show() - if info.text3R and info.text3G and info.text3B then - third:SetTextColor(info.text3R, info.text3G, info.text3B) - else - third:SetTextColor(1, 0.823529, 0) - end - local a,_,b = third:GetFont() - third:SetFont(a, info.size3 * fontSizePercent, b) - right:ClearAllPoints() - right:SetPoint("TOPLEFT", left, "TOPRIGHT", 20 * fontSizePercent, 0) - third:SetJustifyH(info.justify3) - if columns < 4 then - fourth:SetText(nil) - fourth:Hide() - fifth:SetText(nil) - fifth:Hide() - sixth:SetText(nil) - sixth:Hide() - else - fourth:SetFontObject(info.font4) - fourth:SetText(info.text4) - fourth:Show() - if info.text4R and info.text4G and info.text4B then - fourth:SetTextColor(info.text4R, info.text4G, info.text4B) - else - fourth:SetTextColor(1, 0.823529, 0) - end - local a,_,b = fourth:GetFont() - fourth:SetFont(a, info.size4 * fontSizePercent, b) - fourth:SetJustifyH(info.justify4) - if columns < 5 then - fifth:SetText(nil) - fifth:Hide() - sixth:SetText(nil) - sixth:Hide() - else - fifth:SetFontObject(info.font5) - fifth:SetText(info.text5) - fifth:Show() - if info.text5R and info.text5G and info.text5B then - fifth:SetTextColor(info.text5R, info.text5G, info.text5B) - else - fifth:SetTextColor(1, 0.823529, 0) - end - local a,_,b = fourth:GetFont() - fifth:SetFont(a, info.size5 * fontSizePercent, b) - fifth:SetJustifyH(info.justify5) - if columns < 6 then - sixth:SetText(nil) - sixth:Hide() - else - sixth:SetFontObject(info.font6) - sixth:SetText(info.text6) - sixth:Show() - if info.text5R and info.text6G and info.text6B then - sixth:SetTextColor(info.text6R, info.text6G, info.text6B) - else - sixth:SetTextColor(1, 0.823529, 0) - end - local a,_,b = fourth:GetFont() - sixth:SetFont(a, info.size6 * fontSizePercent, b) - sixth:SetJustifyH(info.justify6) - end - end - end - end - end - end - - check:SetWidth(info.size) - check:SetHeight(info.size) - check.width = info.size - if info.hasCheck then - check.shown = true - check:Show() - if isRadio then - check:SetTexture(info.checkIcon or "Interface\\Buttons\\UI-RadioButton") - if info.checked then - check:SetAlpha(1) - check:SetTexCoord(0.25, 0.5, 0, 1) - else - check:SetAlpha(self.transparency) - check:SetTexCoord(0, 0.25, 0, 1) - end - else - if info.checkIcon then - check:SetTexture(info.checkIcon) - if string.sub(info.checkIcon, 1, 16) == "Interface\\Icons\\" then - check:SetTexCoord(0.05, 0.95, 0.05, 0.95) - else - check:SetTexCoord(0, 1, 0, 1) - end - else - check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check") - check:SetWidth(info.size * 1.5) - check:SetHeight(info.size * 1.5) - check.width = info.size * 1.2 - check:SetTexCoord(0, 1, 0, 1) - end - check:SetAlpha(info.checked and 1 or 0) - end - left:SetPoint("TOPLEFT", check, "TOPLEFT", check.width, 0) - else - left:SetPoint("TOPLEFT", check, "TOPLEFT") - end - if columns == 1 then - left:SetWidth(maxWidth) - elseif columns == 2 then - left:SetWidth(0) - right:SetWidth(0) - if info.wrap then - left:SetWidth(maxWidth - right:GetWidth() - 40 * fontSizePercent) - elseif info.wrap2 then - right:SetWidth(maxWidth - left:GetWidth() - 40 * fontSizePercent) - end - right:ClearAllPoints() - right:SetPoint("TOPRIGHT", button, "TOPRIGHT", 0, 0) - if not info.text2 then - left:SetJustifyH(info.justify or "LEFT") - end - elseif columns == 3 then - left:SetWidth(x1 - info.checkWidth) - right:SetWidth(x2) - third:SetWidth(x3) - right:ClearAllPoints() - local num = (category.tabletData.width - x1 - x2 - x3) / 2 - right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) - third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) - elseif columns == 4 then - left:SetWidth(x1 - info.checkWidth) - right:SetWidth(x2) - third:SetWidth(x3) - fourth:SetWidth(x4) - local num = (category.tabletData.width - x1 - x2 - x3 - x4) / 3 - right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) - third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) - fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) - elseif columns == 5 then - left:SetWidth(x1 - info.checkWidth) - right:SetWidth(x2) - third:SetWidth(x3) - fourth:SetWidth(x4) - fifth:SetWidth(x5) - local num = (category.tabletData.width - x1 - x2 - x3 - x4 - x5) / 4 - right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) - third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) - fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) - fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", num, 0) - elseif columns == 6 then - left:SetWidth(x1 - info.checkWidth) - right:SetWidth(x2) - third:SetWidth(x3) - fourth:SetWidth(x4) - fifth:SetWidth(x5) - sixth:SetWidth(x6) - local num = (category.tabletData.width - x1 - x2 - x3 - x4 - x5 - x6) / 5 - right:SetPoint("TOPLEFT", left, "TOPRIGHT", num, 0) - third:SetPoint("TOPLEFT", right, "TOPRIGHT", num, 0) - fourth:SetPoint("TOPLEFT", third, "TOPRIGHT", num, 0) - fifth:SetPoint("TOPLEFT", fourth, "TOPRIGHT", num, 0) - sixth:SetPoint("TOPLEFT", fifth, "TOPRIGHT", num, 0) - end - if not self.locked or IsAltKeyDown() then - local func = info.func - if func then - if type(func) == "string" then - Tablet:assert(type(info.arg1) == "table", "Cannot call method " .. info.func .. " on a non-table") - func = info.arg1[func] - Tablet:assert(type(func) == "function", "Method " .. info.func .. " nonexistant") - end - Tablet:assert(type(func) == "function", "func must be a function or method") - button.func = func - button.a1 = info.arg1 - button.a2 = info.arg2 - button.a3 = info.arg3 - button.self = self - button:SetScript("OnMouseUp", button_OnMouseUp) - button:SetScript("OnMouseDown", button_OnMouseDown) - button:SetScript("OnClick", button_OnClick) - if button.clicked then - button:SetButtonState("PUSHED") - end - button:EnableMouse(true) - else - button:SetScript("OnMouseDown", nil) - button:SetScript("OnMouseUp", nil) - button:SetScript("OnClick", nil) - button:EnableMouse(false) - end - else - button:SetScript("OnMouseDown", nil) - button:SetScript("OnMouseUp", nil) - button:SetScript("OnClick", nil) - button:EnableMouse(false) - end - end - tooltip.AddLine = wrap(tooltip.AddLine, "tooltip:AddLine") - - function tooltip:SetFontSizePercent(percent) - local data, detachedData = self.data, self.detachedData - if detachedData and detachedData.detached then - data = detachedData - end - local lastSize = self.fontSizePercent - percent = tonumber(percent) or 1 - if percent < 0.25 then - percent = 0.25 - elseif percent > 4 then - percent = 4 - end - self.fontSizePercent = percent - if data then - data.fontSizePercent = percent - end - self.scrollUp:SetFont(font, normalSize * self.fontSizePercent, flags) - self.scrollDown:SetFont(font, normalSize * self.fontSizePercent, flags) - local ratio = self.fontSizePercent / lastSize - for i = 1, self.numLines do - local left = self.lefts[i] - local right = self.rights[i] - local third = self.thirds[i] - local fourth = self.fourths[i] - local fifth = self.fifths[i] - local sixth = self.sixths[i] - local check = self.checks[i] - local font, size, flags = left:GetFont() - left:SetFont(font, size * ratio, flags) - font, size, flags = right:GetFont() - right:SetFont(font, size * ratio, flags) - font, size, flags = third:GetFont() - third:SetFont(font, size * ratio, flags) - font, size, flags = fourth:GetFont() - fourth:SetFont(font, size * ratio, flags) - font, size, flags = fifth:GetFont() - fifth:SetFont(font, size * ratio, flags) - font, size, flags = sixth:GetFont() - sixth:SetFont(font, size * ratio, flags) - check.width = check.width * ratio - check:SetWidth(check:GetWidth() * ratio) - check:SetHeight(check:GetHeight() * ratio) - end - self:SetWidth((self:GetWidth() - 51) * ratio + 51) - self:SetHeight((self:GetHeight() - 51) * ratio + 51) - if self:IsShown() and self.children then - self:children() - self:Show() - end - end - tooltip.SetFontSizePercent = wrap(tooltip.SetFontSizePercent, "tooltip:SetFontSizePercent") - - function tooltip:GetFontSizePercent() - return self.fontSizePercent - end - - function tooltip:SetTransparency(alpha) - local data, detachedData = self.data, self.detachedData - if detachedData and detachedData.detached then - data = detachedData - end - self.transparency = alpha - if data then - data.transparency = alpha ~= 0.75 and alpha or nil - end - self:SetBackdropColor(self.r or 0, self.g or 0, self.b or 0, alpha) - self:SetBackdropBorderColor(1, 1, 1, alpha) - end - tooltip.SetTransparency = wrap(tooltip.SetTransparency, "tooltip:SetTransparency") - - function tooltip:GetTransparency() - return self.transparency - end - - function tooltip:SetColor(r, g, b) - local data, detachedData = self.data, self.detachedData - if detachedData and detachedData.detached then - data = detachedData - end - self.r = r - self.g = g - self.b = b - if data then - data.r = r ~= 0 and r or nil - data.g = g ~= 0 and g or nil - data.b = b ~= 0 and b or nil - end - self:SetBackdropColor(r or 0, g or 0, b or 0, self.transparency) - self:SetBackdropBorderColor(1, 1, 1, self.transparency) - end - tooltip.SetColor = wrap(tooltip.SetColor, "tooltip:SetColor") - - function tooltip:GetColor() - return self.r, self.g, self.b - end - - function tooltip:Scroll(down) - if down then - if IsShiftKeyDown() then - self.scroll = self.numLines - GetMaxLinesPerScreen(self) - else - self.scroll = self.scroll + 3 - end - else - if IsShiftKeyDown() then - self.scroll = 0 - else - self.scroll = self.scroll - 3 - end - end - if self.scroll > self.numLines - GetMaxLinesPerScreen(self) then - self.scroll = self.numLines - GetMaxLinesPerScreen(self) - end - if self.scroll < 0 then - self.scroll = 0 - end - if self:IsShown() then - self:Show() - end - end - tooltip.Scroll = wrap(tooltip.Scroll, "tooltip:Scroll") - - function tooltip.Detach(tooltip) - local owner = tooltip.owner - tooltip:Hide() - self:assert(tooltip.detachedData, "You cannot detach if detachedData is not present") - tooltip.detachedData.detached = true - local detached = AcquireDetachedFrame(self, tooltip.registration, tooltip.data, tooltip.detachedData) - - detached.menu, tooltip.menu = tooltip.menu, nil - detached.children = tooltip.children - tooltip.children = nil - detached:SetOwner(owner) - detached:children() - detached:Show() - end - tooltip.Detach = wrap(tooltip.Detach, "tooltip:Detach") - - end - - tooltip.registration = registration - registration.tooltip = tooltip - return tooltip -end -AcquireFrame = wrap(AcquireFrame, "AcquireFrame") - -function ReleaseDetachedFrame(self, data, detachedData) - if not detachedData then - detachedData = data - end - for _, detached in ipairs(detachedTooltips) do - if detached.detachedData == detachedData then - detached.notInUse = true - detached:Hide() - detached.registration.tooltip = nil - detached.registration = nil - end - end -end -ReleaseDetachedFrame = wrap(ReleaseDetachedFrame, "ReleaseDetachedFrame") - -local StartCheckingAlt, StopCheckingAlt -do - local frame - function StartCheckingAlt(func) - if not frame then - frame = CreateFrame("Frame") - frame:SetScript("OnEvent", function(this, _, modifier) - if modifier == "ALT" then - this.func() - end - end) - end - frame:RegisterEvent("MODIFIER_STATE_CHANGED") - frame.func = func - end - function StopCheckingAlt() - if frame then - frame:UnregisterEvent("MODIFIER_STATE_CHANGED") - end - end -end - -function AcquireDetachedFrame(self, registration, data, detachedData) - if not detachedData then - detachedData = data - end - for _, detached in ipairs(detachedTooltips) do - if detached.notInUse then - detached.data = data - detached.detachedData = detachedData - detached.notInUse = nil - local fontSizePercent = detachedData.fontSizePercent or 1 - local transparency = detachedData.transparency or 0.75 - local r = detachedData.r or 0 - local g = detachedData.g or 0 - local b = detachedData.b or 0 - detached:SetFontSizePercent(fontSizePercent) - detached:SetTransparency(transparency) - detached:SetColor(r, g, b) - detached:ClearAllPoints() - detached:SetPoint(detachedData.anchor or "CENTER", UIParent, detachedData.anchor or "CENTER", detachedData.offsetx or 0, detachedData.offsety or 0) - detached.registration = registration - registration.tooltip = detached - return detached - end - end - - if not Dewdrop and AceLibrary:HasInstance("Dewdrop-2.0") then - Dewdrop = AceLibrary("Dewdrop-2.0") - end - StartCheckingAlt(function() - for _, detached in ipairs(detachedTooltips) do - if detached:IsShown() and detached.locked then - detached:EnableMouse(IsAltKeyDown()) - detached:children() - if detached.moving then - local a1 = arg1 - arg1 = "LeftButton" - if type(detached:GetScript("OnMouseUp")) == "function" then - detached:GetScript("OnMouseUp")() - end - arg1 = a1 - end - end - end - end) - if not tooltip then - AcquireFrame(self, {}) - end - local detached = CreateFrame("Frame", "Tablet20DetachedFrame" .. (table.getn(detachedTooltips) + 1), UIParent) - table.insert(detachedTooltips, detached) - detached.notInUse = true - detached:EnableMouse(not data.locked) - detached:EnableMouseWheel(true) - detached:SetMovable(true) - detached:SetPoint(data.anchor or "CENTER", UIParent, data.anchor or "CENTER", data.offsetx or 0, data.offsety or 0) - - detached.numLines = 0 - detached.owner = nil - detached.fontSizePercent = 1 - detached.maxLines = 0 - detached.buttons = {} - detached.checks = {} - detached.lefts = {} - detached.rights = {} - detached.thirds = {} - detached.fourths = {} - detached.fifths = {} - detached.sixths = {} - detached.transparency = 0.75 - detached.r = 0 - detached.g = 0 - detached.b = 0 - detached:SetFrameStrata("BACKGROUND") - detached:SetBackdrop(tmp.a( - 'bgFile', "Interface\\Buttons\\WHITE8X8", - 'edgeFile', "Interface\\Tooltips\\UI-Tooltip-Border", - 'tile', true, - 'tileSize', 16, - 'edgeSize', 16, - 'insets', tmp.b( - 'left', 5, - 'right', 5, - 'top', 5, - 'bottom', 5 - ) - )) - detached.locked = detachedData.locked - detached.scroll = 0 - detached:EnableMouse(not detached.locked) - - local width = GetScreenWidth() - local height = GetScreenHeight() - detached:SetScript("OnMouseDown", function() - if arg1 == "LeftButton" then - detached:StartMoving() - detached.moving = true - end - end) - - detached:SetScript("OnMouseUp", function() - if arg1 == "LeftButton" then - detached:StopMovingOrSizing() - detached.moving = nil - local anchor - local offsetx - local offsety - if detached:GetTop() + detached:GetBottom() < height then - anchor = "BOTTOM" - offsety = detached:GetBottom() - if offsety < 0 then - offsety = 0 - end - if offsety < MainMenuBar:GetTop() and MainMenuBar:IsVisible() then - offsety = MainMenuBar:GetTop() - end - local top = 0 - if FuBar then - for i = 1, FuBar:GetNumPanels() do - local panel = FuBar:GetPanel(i) - if panel:GetAttachPoint() == "BOTTOM" then - if panel.frame:GetTop() > top then - top = panel.frame:GetTop() - break - end - end - end - end - if offsety < top then - offsety = top - end - else - anchor = "TOP" - offsety = detached:GetTop() - height - if offsety > 0 then - offsety = 0 - end - local bottom = GetScreenHeight() - if FuBar then - for i = 1, FuBar:GetNumPanels() do - local panel = FuBar:GetPanel(i) - if panel:GetAttachPoint() == "TOP" then - if panel.frame:GetBottom() < bottom then - bottom = panel.frame:GetBottom() - break - end - end - end - end - bottom = bottom - GetScreenHeight() - if offsety > bottom then - offsety = bottom - end - end - if detached:GetLeft() + detached:GetRight() < width * 2 / 3 then - anchor = anchor .. "LEFT" - offsetx = detached:GetLeft() - if offsetx < 0 then - offsetx = 0 - end - elseif detached:GetLeft() + detached:GetRight() < width * 4 / 3 then - if anchor == "" then - anchor = "CENTER" - end - offsetx = (detached:GetLeft() + detached:GetRight() - GetScreenWidth()) / 2 - else - anchor = anchor .. "RIGHT" - offsetx = detached:GetRight() - width - if offsetx > 0 then - offsetx = 0 - end - end - detached:ClearAllPoints() - detached:SetPoint(anchor, UIParent, anchor, offsetx, offsety) - local t = detached.detachedData - if t.anchor ~= anchor or math.abs(t.offsetx - offsetx) > 8 or math.abs(t.offsety - offsety) > 8 then - detached.preventClick = GetTime() + 0.05 - end - t.anchor = anchor - t.offsetx = offsetx - t.offsety = offsety - detached:Show() - end - end) - - if Dewdrop then - Dewdrop:Register(detached, - 'children', function(level, value) - if not detached.registration then - return - end - if detached.menu then - detached.menu(level, value) - if level == 1 then - Dewdrop:AddLine() - end - end - if level == 1 then - if not detached.registration.cantAttach then - Dewdrop:AddLine( - 'text', DETACH, - 'tooltipTitle', DETACH, - 'tooltipText', DETACH_DESC, - 'checked', true, - 'arg1', detached, - 'func', "Attach", - 'closeWhenClicked', true - ) - end - Dewdrop:AddLine( - 'text', LOCK, - 'tooltipTitle', LOCK, - 'tooltipText', LOCK_DESC, - 'checked', detached:IsLocked(), - 'arg1', detached, - 'func', "Lock", - 'closeWhenClicked', not detached:IsLocked() - ) - Dewdrop:AddLine( - 'text', COLOR, - 'tooltipTitle', COLOR, - 'tooltipText', COLOR_DESC, - 'hasColorSwatch', true, - 'r', detached.r, - 'g', detached.g, - 'b', detached.b, - 'hasOpacity', true, - 'opacity', detached.transparency, - 'colorFunc', function(r, g, b, a) - detached:SetColor(r, g, b) - detached:SetTransparency(a) - end - ) - Dewdrop:AddLine( - 'text', SIZE, - 'tooltipTitle', SIZE, - 'tooltipText', SIZE_DESC, - 'hasArrow', true, - 'hasSlider', true, - 'sliderFunc', function(value) - detached:SetFontSizePercent(value) - end, - 'sliderMax', 2, - 'sliderMin', 0.5, - 'sliderStep', 0.05, - 'sliderIsPercent', true, - 'sliderValue', detached:GetFontSizePercent() - ) - Dewdrop:AddLine( - 'text', CLOSE_MENU, - 'tooltipTitle', CLOSE_MENU, - 'tooltipText', CLOSE_MENU_DESC, - 'func', function() - Dewdrop:Close() - end - ) - end - end, - 'point', function() - local x, y = detached:GetCenter() - if x < GetScreenWidth() / 2 then - if y < GetScreenHeight() / 2 then - return "BOTTOMLEFT", "BOTTOMRIGHT" - else - return "TOPLEFT", "TOPRIGHT" - end - else - if y < GetScreenHeight() / 2 then - return "BOTTOMRIGHT", "BOTTOMLEFT" - else - return "TOPRIGHT", "TOPLEFT" - end - end - end - ) - end - - NewLine(detached) - - detached.scrollUp = detached:CreateFontString(nil, "ARTWORK") - detached.scrollUp:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2) - detached.scrollUp:SetPoint("RIGHT", detached, "RIGHT", 0, -10) - detached.scrollUp:SetFontObject(GameTooltipText) - detached.scrollUp:Hide() - local font,_,flags = detached.scrollUp:GetFont() - detached.scrollUp:SetFont(font, normalSize * detached.fontSizePercent, flags) - detached.scrollUp:SetJustifyH("CENTER") - detached.scrollUp:SetTextColor(1, 0.823529, 0) - detached.scrollUp:SetText(" ") - - detached.scrollDown = detached:CreateFontString(nil, "ARTWORK") - detached.scrollDown:SetPoint("TOPLEFT", detached.buttons[1], "BOTTOMLEFT", 0, -2) - detached.scrollDown:SetPoint("RIGHT", detached, "RIGHT", 0, -10) - detached.scrollDown:SetFontObject(GameTooltipText) - detached.scrollDown:Hide() - local font,_,flags = detached.scrollUp:GetFont() - detached.scrollDown:SetFont(font, normalSize * detached.fontSizePercent, flags) - detached.scrollDown:SetJustifyH("CENTER") - detached.scrollDown:SetTextColor(1, 0.823529, 0) - detached.scrollDown:SetText(" ") - - detached:SetScript("OnMouseWheel", function() - detached:Scroll(arg1 < 0) - end) - - detached.SetTransparency = tooltip.SetTransparency - detached.GetTransparency = tooltip.GetTransparency - detached.SetColor = tooltip.SetColor - detached.GetColor = tooltip.GetColor - detached.SetFontSizePercent = tooltip.SetFontSizePercent - detached.GetFontSizePercent = tooltip.GetFontSizePercent - detached.SetOwner = tooltip.SetOwner - detached.IsOwned = tooltip.IsOwned - detached.ClearLines = tooltip.ClearLines - detached.NumLines = tooltip.NumLines - detached.__Hide = detached.Hide - detached.__Show = detached.Show - detached.Hide = tooltip.Hide - detached.Show = tooltip.Show - local old_IsShown = detached.IsShown - function detached:IsShown() - if self.tmpHidden then - return true - else - return old_IsShown(self) - end - end - detached.AddLine = tooltip.AddLine - detached.Scroll = tooltip.Scroll - function detached:IsLocked() - return self.locked - end - function detached:Lock() - self:EnableMouse(self.locked) - self.locked = not self.locked - self.detachedData.locked = self.locked or nil - self:children() - end - - function detached.Attach(detached) - self:assert(detached, "Detached tooltip not given.") - self:assert(detached.AddLine, "detached argument not a Tooltip.") - self:assert(detached.owner, "Detached tooltip has no owner.") - self:assert(not detached.notInUse, "Detached tooltip not in use.") - detached.menu = nil - detached.detachedData.detached = nil - detached:SetOwner(nil) - detached.notInUse = TRUE - end - - return AcquireDetachedFrame(self, registration, data, detachedData) -end -AcquireDetachedFrame = wrap(AcquireDetachedFrame, "AcquireDetachedFrame") - -function Tablet:Close(parent) - if not parent then - if tooltip and tooltip:IsShown() then - tooltip:Hide() - tooltip.registration.tooltip = nil - tooltip.registration = nil - tooltip.enteredFrame = false - end - return - else - self:argCheck(parent, 2, "table", "string") - end - local info = self.registry[parent] - self:assert(info, "You cannot close a tablet with an unregistered parent frame.") - local data = info.data - local detachedData = info.detachedData - if detachedData and detachedData.detached then - ReleaseDetachedFrame(self, data, detachedData) - elseif tooltip.data == data then - tooltip:Hide() - tooltip.registration.tooltip = nil - tooltip.registration = nil - end - tooltip.enteredFrame = false -end -Tablet.Close = wrap(Tablet.Close, "Tablet:Close") - -local currentFrame -local currentTabletData - -function Tablet:Open(fakeParent, parent) - self:argCheck(fakeParent, 2, "table", "string") - self:argCheck(parent, 3, "nil", "table", "string") - if not parent then - parent = fakeParent - end - local info = self.registry[parent] - self:assert(info, "You cannot open a tablet with an unregistered parent frame.") - self:Close() - local data = info.data - local detachedData = info.detachedData - local children = info.children - if not children then - return - end - local frame = AcquireFrame(self, info, data, detachedData) - frame.clickable = info.clickable - frame.menu = info.menu - local children = info.children - function frame:children() - if not self.preventRefresh then - currentFrame = self - currentTabletData = TabletData:new(self) - self:ClearLines() - if children then - children() - end - currentTabletData:Display(currentFrame) - self:Show(currentTabletData) - currentTabletData:del() - currentTabletData = nil - currentFrame = nil - end - end - frame:SetOwner(fakeParent) - frame:children() - local point = info.point - local relativePoint = info.relativePoint - if type(point) == "function" then - local b - point, b = point(fakeParent) - if b then - relativePoint = b - end - end - if type(relativePoint) == "function" then - relativePoint = relativePoint(fakeParent) - end - if not point then - point = "CENTER" - end - if not relativePoint then - relativePoint = point - end - frame:ClearAllPoints() - if type(parent) ~= "string" then - frame:SetPoint(point, fakeParent, relativePoint) - end - local offsetx = 0 - local offsety = 0 - if frame:GetBottom() and frame:GetLeft() then - if frame:GetRight() > GetScreenWidth() then - offsetx = frame:GetRight() - GetScreenWidth() - elseif frame:GetLeft() < 0 then - offsetx = -frame:GetLeft() - end - local ratio = GetScreenWidth() / GetScreenHeight() - if ratio >= 2.4 and frame:GetRight() > GetScreenWidth() / 2 and frame:GetLeft() < GetScreenWidth() / 2 then - if frame:GetCenter() < GetScreenWidth() / 2 then - offsetx = frame:GetRight() - GetScreenWidth() / 2 - else - offsetx = frame:GetLeft() - GetScreenWidth() / 2 - end - end - if frame:GetBottom() < 0 then - offsety = frame:GetBottom() - elseif frame:GetTop() and frame:GetTop() > GetScreenHeight() then - offsety = frame:GetTop() - GetScreenHeight() - end - if MainMenuBar:IsVisible() and frame:GetBottom() < MainMenuBar:GetTop() and offsety < frame:GetBottom() - MainMenuBar:GetTop() then - offsety = frame:GetBottom() - MainMenuBar:GetTop() - end - - if FuBar then - local top = 0 - if FuBar then - for i = 1, FuBar:GetNumPanels() do - local panel = FuBar:GetPanel(i) - if panel:GetAttachPoint() == "BOTTOM" then - if panel.frame:GetTop() and panel.frame:GetTop() > top then - top = panel.frame:GetTop() - break - end - end - end - end - if frame:GetBottom() < top and offsety < frame:GetBottom() - top then - offsety = frame:GetBottom() - top - end - local bottom = GetScreenHeight() - if FuBar then - for i = 1, FuBar:GetNumPanels() do - local panel = FuBar:GetPanel(i) - if panel:GetAttachPoint() == "TOP" then - if panel.frame:GetBottom() and panel.frame:GetBottom() < bottom then - bottom = panel.frame:GetBottom() - break - end - end - end - end - if frame:GetTop() > bottom and offsety < frame:GetTop() - bottom then - offsety = frame:GetTop() - bottom - end - end - end - if type(fakeParent) ~= "string" then - frame:SetPoint(point, fakeParent, relativePoint, -offsetx, -offsety) - end - - if detachedData and (info.cantAttach or detachedData.detached) and frame == tooltip then - detachedData.detached = false - frame:Detach() - end - if (not detachedData or not detachedData.detached) and GetMouseFocus() == fakeParent then - self.tooltip.enteredFrame = true - end -end -Tablet.Open = wrap(Tablet.Open, "Tablet:Open") - -function Tablet:Register(parent, ...) - self:argCheck(parent, 2, "table", "string") - if self.registry[parent] then - self:Unregister(parent) - end - local info - local k1 = ... - if type(k1) == "table" and k1[0] then - self:assert(type(self.registry[k1]) == "table", "Other parent not registered") - info = copy(self.registry[k1]) - local v1 = select(2, ...) - if type(v1) == "function" then - info.point = v1 - info.relativePoint = nil - end - else - info = new(...) - end - self.registry[parent] = info - info.data = info.data or info.detachedData or {} - info.detachedData = info.detachedData or info.data - local data = info.data - local detachedData = info.detachedData - if not self.onceRegistered[parent] and type(parent) == "table" and type(parent.SetScript) == "function" and not info.dontHook then - if not Dewdrop and AceLibrary:HasInstance("Dewdrop-2.0") then - Dewdrop = AceLibrary("Dewdrop-2.0") - end - local script = parent:GetScript("OnEnter") - parent:SetScript("OnEnter", function() - if script then - script() - end - if self.registry[parent] then - if (not data or not detachedData.detached) and (Dewdrop and not Dewdrop:IsOpen(parent) or true) then - self:Open(parent) - self.tooltip.enteredFrame = true - end - end - end) - local script = parent:GetScript("OnLeave") - parent:SetScript("OnLeave", function() - if script then - script() - end - if self.registry[parent] then - if self.tooltip and (not data or not detachedData or not detachedData.detached) then - self.tooltip.enteredFrame = false - end - end - end) - if parent:HasScript("OnMouseDown") then - local script = parent:GetScript("OnMouseDown") - parent:SetScript("OnMouseDown", function() - if script then - script() - end - if self.registry[parent] and self.registry[parent].tooltip and self.registry[parent].tooltip == self.tooltip then - self.tooltip:Hide() - end - end) - end - if parent:HasScript("OnMouseWheel") then - local script = parent:GetScript("OnMouseWheel") - parent:SetScript("OnMouseWheel", function() - if script then - script() - end - if self.registry[parent] and self.registry[parent].tooltip then - self.registry[parent].tooltip:Scroll(arg1 < 0) - end - end) - end - end - self.onceRegistered[parent] = true - if GetMouseFocus() == parent then - self:Open(parent) - end -end -Tablet.Register = wrap(Tablet.Register, "Tablet:Register") - -function Tablet:Unregister(parent) - self:argCheck(parent, 2, "table", "string") - self:assert(self.registry[parent], "You cannot unregister a parent frame if it has not been registered already.") - self.registry[parent] = nil -end -Tablet.Unregister = wrap(Tablet.Unregister, "Tablet:Unregister") - -function Tablet:IsRegistered(parent) - self:argCheck(parent, 2, "table", "string") - return self.registry[parent] and true -end -Tablet.IsRegistered = wrap(Tablet.IsRegistered, "Tablet:IsRegistered") - -local _id = 0 -local addedCategory -local currentCategoryInfo -local depth = 0 -local categoryPool = {} -function CleanCategoryPool(self) - for k,v in pairs(categoryPool) do - del(v) - categoryPool[k] = nil - end - _id = 0 -end - -function Tablet:AddCategory(...) - self:assert(currentFrame, "You must add categories in within a registration.") - local info = new(...) - local cat = currentTabletData:AddCategory(info) - info = del(info) - return cat -end -Tablet.AddCategory = wrap(Tablet.AddCategory, "Tablet:AddCategory") - -function Tablet:SetHint(text) - self:assert(currentFrame, "You must set hint within a registration.") - self:assert(not currentCategoryInfo, "You cannot set hint in a category.") - currentTabletData:SetHint(text) -end -Tablet.SetHint = wrap(Tablet.SetHint, "Tablet:SetHint") - -function Tablet:SetTitle(text) - self:assert(currentFrame, "You must set title within a registration") - self:assert(not currentCategoryInfo, "You cannot set title in a category.") - currentTabletData:SetTitle(text) -end -Tablet.SetTitle = wrap(Tablet.SetTitle, "Tablet:SetTitle") - -function Tablet:SetTitleColor(r, g, b) - self:assert(currentFrame, "You must set title color within a registration") - self:assert(not currentCategoryInfo, "You cannot set title color in a category.") - self:argCheck(r, 2, "number") - self:argCheck(g, 3, "number") - self:argCheck(b, 4, "number") - currentTabletData:SetTitleColor(r, g, b) -end -Tablet.SetTitleColor = wrap(Tablet.SetTitleColor, "Tablet:SetTitleColor") - -function Tablet:GetNormalFontSize() - return normalSize -end - -function Tablet:GetHeaderFontSize() - return headerSize -end - -function Tablet:GetNormalFontObject() - return GameTooltipText -end - -function Tablet:GetHeaderFontObject() - return GameTooltipHeaderText -end - -function Tablet:SetFontSizePercent(parent, percent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - if info.tooltip then - info.tooltip:SetFontSizePercent(percent) - else - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - detachedData.fontSizePercent = percent - else - data.fontSizePercent = percent - end - end - elseif type(parent) == "table" then - parent.fontSizePercent = percent - else - self:assert(false, "You cannot change font size with an unregistered parent frame.") - end -end -Tablet.SetFontSizePercent = wrap(Tablet.SetFontSizePercent, "Tablet:SetFontSizePercent") - -function Tablet:GetFontSizePercent(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - return detachedData.fontSizePercent or 1 - else - return data.fontSizePercent or 1 - end - elseif type(parent) == "table" then - return parent.fontSizePercent or 1 - else - self:assert(false, "You cannot check font size with an unregistered parent frame.") - end -end -Tablet.GetFontSizePercent = wrap(Tablet.GetFontSizePercent, "Tablet:GetFontSizePercent") - -function Tablet:SetTransparency(parent, percent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - if info.tooltip then - info.tooltip:SetTransparency(percent) - else - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - detachedData.transparency = percent - elseif data then - data.transparency = percent - end - end - elseif type(parent) == "table" then - parent.transparency = percent - else - self:assert(false, "You cannot change transparency with an unregistered parent frame.") - end -end -Tablet.SetTransparency = wrap(Tablet.SetTransparency, "Tablet:SetTransparency") - -function Tablet:GetTransparency(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - return detachedData.transparency or 0.75 - else - return data.transparency or 0.75 - end - elseif type(parent) == "table" then - return parent.transparency or 0.75 - else - self:assert(parent, "You must provide a parent frame to check transparency") - end -end -Tablet.GetTransparency = wrap(Tablet.GetTransparency, "Tablet:GetTransparency") - -function Tablet:SetColor(parent, r, g, b) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - if info.tooltip then - info.tooltip:SetColor(r, g, b) - else - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - detachedData.r = r - detachedData.g = g - detachedData.b = b - else - data.r = r - data.g = g - data.b = b - end - end - elseif type(parent) == "table" then - parent.r = r - parent.g = g - parent.b = b - else - self:assert(false, "You cannot change color with an unregistered parent frame.") - end -end -Tablet.SetColor = wrap(Tablet.SetColor, "Tablet:SetColor") - -function Tablet:GetColor(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - if info then - local data = info.data - local detachedData = info.detachedData - if detachedData.detached then - return detachedData.r or 0, detachedData.g or 0, detachedData.b or 0 - else - return data.r or 0, data.g or 0, data.b or 0 - end - elseif type(parent) == "table" then - return parent.r or 0, parent.g or 0, parent.b or 0 - else - self:assert(parent, "You must provide a parent frame to check color") - end -end -Tablet.GetColor = wrap(Tablet.GetColor, "Tablet:GetColor") - -function Tablet:Detach(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot detach tablet with an unregistered parent frame.") - self:assert(info.detachedData, "You cannot detach tablet without a data field.") - if info.tooltip and info.tooltip == tooltip then - tooltip:Detach() - else - info.detachedData.detached = true - local detached = AcquireDetachedFrame(self, info, info.data, info.detachedData) - - detached.menu = info.menu - local children = info.children - function detached:children() - if not self.preventRefresh then - currentFrame = self - currentTabletData = TabletData:new(self) - self:ClearLines() - if children then - children() - end - currentTabletData:Display(currentFrame) - self:Show(currentTabletData) - currentTabletData:del() - currentTabletData = nil - currentFrame = nil - end - end - detached:SetOwner(parent) - detached:children() - end -end -Tablet.Detach = wrap(Tablet.Detach, "Tablet:Detach") - -function Tablet:Attach(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot detach tablet with an unregistered parent frame.") - self:assert(info.detachedData, "You cannot attach tablet without a data field.") - if info.tooltip and info.tooltip ~= tooltip then - info.tooltip:Attach() - else - info.detachedData.detached = false - end -end -Tablet.Attach = wrap(Tablet.Attach, "Tablet:Attach") - -function Tablet:IsAttached(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot check tablet with an unregistered parent frame.") - return not info.detachedData or not info.detachedData.detached -end -Tablet.IsAttached = wrap(Tablet.IsAttached, "Tablet:IsAttached") - -function Tablet:Refresh(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot refresh tablet with an unregistered parent frame.") - local tt = info.tooltip - if tt and not tt.preventRefresh and tt:IsShown() then - tt.updating = true - tt:children() - tt.updating = false - end -end -Tablet.Refresh = wrap(Tablet.Refresh, "Tablet:Refresh") - -function Tablet:IsLocked(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot detach tablet with an unregistered parent frame.") - return info.detachedData and info.detachedData.locked -end -Tablet.IsLocked = wrap(Tablet.IsLocked, "Tablet:IsLocked") - -function Tablet:ToggleLocked(parent) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot detach tablet with an unregistered parent frame.") - if info.tooltip and info.tooltip ~= tooltip then - info.tooltip:Lock() - elseif info.detachedData then - info.detachedData.locked = info.detachedData.locked - end -end -Tablet.ToggleLocked = wrap(Tablet.ToggleLocked, "Tablet:ToggleLocked") - -function Tablet:UpdateDetachedData(parent, detachedData) - self:argCheck(parent, 2, "table", "string") - local info = self.registry[parent] - self:assert(info, "You cannot detach tablet with an unregistered parent frame.") - self:argCheck(detachedData, 3, "table") - if info.data == info.detachedData then - info.data = detachedData - end - info.detachedData = detachedData - if info.detachedData.detached then - self:Detach(parent) - elseif info.tooltip and info.tooltip.owner then - self:Attach(parent) - end -end -Tablet.UpdateDetachedData = wrap(Tablet.UpdateDetachedData, "Tablet:UpdateDetachedData") - -if DEBUG then - function Tablet:ListProfileInfo() - local duration, times, memories = GetProfileInfo() - self:assert(duration and times and memories) - local t = new() - for method in pairs(memories) do - table.insert(t, method) - end - table.sort(t, function(alpha, bravo) - if memories[alpha] ~= memories[bravo] then - return memories[alpha] < memories[bravo] - elseif times[alpha] ~= times[bravo] then - return times[alpha] < times[bravo] - else - return alpha < bravo - end - end) - local memory = 0 - local time = 0 - for _,method in ipairs(t) do - DEFAULT_CHAT_FRAME:AddMessage(format("%s || %.3f s || %.3f%% || %d KiB", method, times[method], times[method] / duration * 100, memories[method])) - memory = memory + memories[method] - time = time + times[method] - end - DEFAULT_CHAT_FRAME:AddMessage(format("%s || %.3f s || %.3f%% || %d KiB", "Total", time, time / duration * 100, memory)) - del(t) - end - SLASH_TABLET1 = "/tablet" - SLASH_TABLET2 = "/tabletlib" - SlashCmdList["TABLET"] = function(msg) - TabletLib:GetInstance(MAJOR_VERSION):ListProfileInfo() - end -end - -local function activate(self, oldLib, oldDeactivate) - Tablet = self - if oldLib then - self.registry = oldLib.registry - self.onceRegistered = oldLib.onceRegistered - self.tooltip = oldLib.tooltip - else - self.registry = {} - self.onceRegistered = {} - end - - tooltip = self.tooltip - - if oldDeactivate then - oldDeactivate(oldLib) - end -end - -local function deactivate(self) - StopCheckingAlt() -end - -AceLibrary:Register(Tablet, MAJOR_VERSION, MINOR_VERSION, activate, deactivate)
--- a/locale-enUS.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ --- English localization file for ReAction - -local L = AceLibrary("AceLocale-2.2"):new("ReAction") - -L:RegisterTranslations( "enUS", function() -return { - -- main.lua - ["ReAction"] = true, - ["Toggle ReAction Bar Lock"] = true, - ["ReAction Keybinding Mode"] = true, - ["/reaction"] = true, - ["/rxn"] = true, - ["ReAction bars locked when in combat"] = true, - ["Bar lock"] = true, - ["Locked"] = true, - ["Unlocked"] = true, - ["Button lock"] = true, - ["On"] = true, - ["Off"] = true, - ["Kebinding mode"] = true, - ["Tried to create a button of unknown type"] = true, - ["|cffffcc00Shift-Click for bar lock|n|cff33ff33Alt-Click|r for keybindings|nRight-click for menu"] = true, - ["ReAction Keybinding"] = true, - ["Click Buttons to Set Keybindings"] = true, - ["Save"] = true, - ["Revert"] = true, - ["Use ReAction"] = true, - ["Action Bar Functions Disabled"] = true, - ["Multi-Action Bar Functions Disabled"] = true, - -} -end )
--- a/main.lua Fri Mar 07 21:54:26 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,594 +0,0 @@ --- main.lua --- --- Top-level file for the ReAction Action Bar add-on --- --- implemented in terms of the Ace 2 development framework library: http://www.wowace.com --- - - --- Ace Library local object initialization -local L = AceLibrary("AceLocale-2.2"):new("ReAction") -local dewdrop = AceLibrary("Dewdrop-2.0") -local tablet = AceLibrary("Tablet-2.0") -local ReBound = AceLibrary("ReBound-1.0"):new("ReAction") - --- private functions -local function tcopy(t) - local r = { } - for k, v in pairs(t) do - r[k] = (type(v) == "table" and tcopy(v) or v) - end - return r -end - --- private constants -local EMPTY_BAR_SLOT = -1 - --- key binding label constants -BINDING_HEADER_REACTION = L["ReAction"] -BINDING_NAME_REACTION_TOGGLELOCK = L["Toggle ReAction Bar Lock"] -BINDING_NAME_REACTION_TOGGLEKEYBIND = L["ReAction Keybinding Mode"] - --- UI panel strings -REACTION_KEYBIND_TITLE = L["ReAction Keybinding"] -REACTION_KEYBIND_SUBTITLE = L["Click Buttons to Set Keybindings"] -REACTION_KEYBIND_DONE = L["Save"] -REACTION_KEYBIND_REVERT = L["Revert"] - - - ------------------------------- --- AceAddon setup ------------------------------- -local main = AceLibrary("AceAddon-2.0"):new( - "AceConsole-2.0", - "AceEvent-2.0", - "AceDB-2.0", - "FuBarPlugin-2.0" -) - -function main:OnInitialize() - self:RegisterChatCommand( {L["/reaction"], L["/rxn"]}, ReActionConsoleOptions, "REACTION" ) - self:RegisterDB("ReActionDB","ReActionDBPC") - self:RegisterDefaults("profile", ReAction_DefaultProfile) - self:RegisterEvent("PLAYER_REGEN_DISABLED","CombatLockdown") - self:DisableDefaultKeybindings() - - -- create update function for keybinding frame - ReActionKeybindDialog:SetScript("OnHide", function(frame) main:HideKeybindDialog(frame) end) - - -- initial non-persistent state - self.locked = true - self.keybindMode = false - self.bars = { } -end - --- OnEnable is called at PLAYER_LOGIN or when the addon is enabled. -function main:OnEnable( ) - self:HideDefaultBars() - self:SetupProfile( ) -end - -function main:OnDisable() - self:Lock() -end - --- OnProfileEnable() is only called when switching profiles, NOT for the initial profile at load time. -function main:OnProfileEnable( oldName, oldData ) - self:UnregisterEvent("REBOUND_BIND") - self:UnregisterEvent("REBOUND_UNBIND") - ReBound:ClearRegisteredBindings() - self:SetupProfile() -end - -function main:SetupProfile( ) - local profile = self.db.profile - if profile.firstRunDone ~= true then - profile.bars = tcopy(ReAction_DefaultBlizzardBars) - end - self:DestroyAllBars() - self:UpgradeProfile() - self:HideArt() - self:SetupBars() - self:SetupKeybindings() - if profile.firstRunDone ~= true then - self:Unlock() - profile.firstRunDone = true - end -end - --- Set a global variable for Bindings.xml (I use 'setglobal' for clarity, it's not strictly necessary) -setglobal("ReActionAddOn", main) - - - - ------------------------------------------------------------- --- Profile conversion functions (from old profiles) --- --- NOTE: these will be REMOVED when alpha testing is over. ------------------------------------------------------------- -function main:UpgradeBindingConfig() - if #self.db.profile.bindings == 0 then - for _, bar in pairs(self.bars) do - for _, button in pairs(bar.buttons) do - local key = ReBound:GetBinding(button:GetActionFrame(),"LeftButton") - if key and #key > 0 and not self.db.profile.bindings[key] then - self:REBOUND_BIND(key,button:GetActionFrame():GetName(),"LeftButton") - end - end - end - end -end - -function main:UpgradeProfile() - for _, bar in pairs(self.db.profile.bars) do - if bar.btnConfig and bar.btnConfig.ids then - bar.btnConfig.buttons = { } - for i, ids in ipairs(bar.btnConfig.ids) do - bar.btnConfig.buttons[i] = { id = ids[1], actions = ids } - end - bar.btnConfig.ids = nil - end - end -end - - - --------------------------------------------- --- FuBar plugin setup --- Even if FuBar isn't installed, the plugin --- provides a nice minimap-button interface. ---------------------------------------------- -main.hasIcon = "Interface\\Icons\\INV_Qiraj_JewelEncased" -main.hasNoColor = true -main.hideMenuTitle = true -main.defaultPosition = "LEFT" -main.defaultMinimapPosition = 240 -- degrees -main.OnMenuRequest = tcopy(ReActionGlobalMenuOptions) -- use a copy, or bar menus will have FuBar inserted items -main.independentProfile = true - --- set the handler for the global bar menu options --- have to do this after tcopy() above, otherwise it will try to copy the handler object (bad idea) -ReActionGlobalMenuOptions.handler = main - -function main:OnTooltipUpdate() - local c = tablet:AddCategory("columns", 2) - c:AddLine("text", L["Bar lock"], "text2", self.locked and ("|cffff0000"..L["Locked"].."|r") or ("|cffffcc00"..L["Unlocked"].."|r")) - c:AddLine("text", L["Button lock"], "text2", LOCK_ACTIONBAR == "1" and ("|cffcc0000"..L["Locked"].."|r") or ("|cff00cc00"..L["Unlocked"].."|r")) - c:AddLine("text", L["Kebinding mode"], "text2", self:GetKeybindMode() and ("|cff33ff33"..L["On"].."|r") or ("|cffffcc00"..L["Off"].."|r")) - tablet:SetHint(L["|cffffcc00Shift-Click for bar lock|n|cff33ff33Alt-Click|r for keybindings|nRight-click for menu"]) -end - -function main:OnClick(button) - if IsShiftKeyDown() then - self:ToggleLocked() - self:UpdateDisplay() - elseif IsAltKeyDown() then - self:ToggleKeybindMode() - self:UpdateDisplay() - end -end - - - - ------------------------------- --- Key binding functions ------------------------------- -function main:DisableDefaultKeybindings() - -- change the labels on all actionbar keybindings in the default interface. - local label = "|cff999999("..L["Use ReAction"]..")|r" - for i = 1, 12 do - setglobal("BINDING_NAME_ACTIONBUTTON"..i,label) - for j = 1, 4 do - setglobal("BINDING_NAME_MULTIACTIONBAR"..j.."BUTTON"..i,label) - end - end - for i = 1, 6 do - setglobal("BINDING_NAME_ACTIONPAGE"..i,label) - end - for i = 1, 10 do - setglobal("BINDING_NAME_BONUSACTIONBUTTON"..i,label) --- setglobal("BINDING_NAME_SHAPESHIFTBUTTON"..i,label) - end - BINDING_HEADER_ACTIONBAR = "|cff999999"..L["Action Bar Functions Disabled"].."|r" - BINDING_HEADER_MULTIACTIONBAR = "|cff999999"..L["Multi-Action Bar Functions Disabled"].."|r" - BINDING_NAME_NEXTACTIONPAGE = label - BINDING_NAME_PREVIOUSACTIONPAGE = label -end - -function main:SetupKeybindings() - if self.db.profile.firstRunDone ~= true then - self:StealKeyBindings() - else - self:UpgradeBindingConfig() - local needsSave = false - for key, binding in pairs(self.db.profile.bindings) do - local target = getglobal(binding.target) - if target then - if ReBound:GetBinding(target,binding.button) ~= key then - ReBound:SetBinding(key,target,binding.button,true) - needsSave = true - end - end - end - if needsSave then - ReBound:SaveBindings() - end - end - self:RegisterEvent("REBOUND_BIND") - self:RegisterEvent("REBOUND_UNBIND") -end - -function main:StealKeyBindings() - -- steal the keybindings of the main action bar and assign them to rebar 1, buttons 1-12 - local bar = self.bars[1] - if bar and bar ~= EMPTY_BAR_SLOT then - for i = 1, 12 do - local key = GetBindingKey("ACTIONBUTTON"..i) - if key and #key > 0 then - local button = bar.buttons[i] - if button then - ReBound:SetBinding(key, button:GetActionFrame(),nil,true) - end - end - end - local key = GetBindingKey("NEXTACTIONPAGE") - if key and #key > 0 then - ReBound:SetBinding(key, bar.upArrow,nil,true) - end - key = GetBindingKey("PREVIOUSACTIONPAGE") - if key and #key > 0 then - ReBound:SetBinding(key, bar.downArrow,nil,true) - end - ReBound:SaveBindings() - end -end - -function main:REBOUND_BIND(id, key, target, button) - if id == "ReAction" and key and target then - self.db.profile.bindings[key] = { target = target, button = button } - end -end - -function main:REBOUND_UNBIND(id, key) - if id == "ReAction" and key then - self.db.profile.bindings[key] = nil - end -end - -function main:ToggleKeybindMode() - self:SetKeybindMode(not self:GetKeybindMode()) -end - -function main:GetKeybindMode() - return self.keybindMode -end - -function main:SetKeybindMode(enabled) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(ERROR_NOT_IN_COMBAT) - else - self.keybindMode = enabled - for _, bar in pairs(self.bars) do - if bar and bar ~= EMPTY_BAR_SLOT then - for __, button in pairs(bar.buttons) do - if button then - button:TempShow(enabled) - end - end - end - end - if enabled then - ReBound:ShowRegisteredFrames() - ReActionKeybindDialog:Show() - else - ReBound:HideRegisteredFrames() - if ReActionKeybindDialog:IsShown() then - ReActionKeybindDialog:Hide() - end - end - end -end - -function main:HideKeybindDialog( frame ) - self:SetKeybindMode(false) - if frame.save then - ReBound:SaveBindings() - else - ReBound:RevertBindings() - end - frame.save = false -end - - ----------------------------- --- Bar lock/unlock functions ----------------------------- -function main:CombatLockdown() - if not self:IsLocked() then - self:Lock() - UIErrorsFrame:AddMessage(L["ReAction bars locked when in combat"]) - end - ReActionKeybindDialog:Hide() -end - -function main:SetLocked( lock ) - if lock ~= self.locked then - if not lock and InCombatLockdown() then - UIErrorsFrame:AddMessage(ERROR_NOT_IN_COMBAT) - else - self.locked = lock and true or false -- force data integrity - for _, bar in pairs(self.bars) do - if bar ~= EMPTY_BAR_SLOT then - if self.locked then - bar:HideControls() - -- close any dewdrop menu owned by the bar - if bar:GetControlFrame() == dewdrop:GetOpenedParent() then - dewdrop:Close() - end - else - bar:ShowControls() - end - end - end - end - end -end - -function main:IsLocked() - return self.locked -end - -function main:Lock() - self:SetLocked(true) -end - -function main:Unlock() - self:SetLocked(false) -end - -function main:ToggleLocked() - self:SetLocked( not(self.locked) ) -end - - - --------------------------------------------------------- --- Functions to hide the default Blizzard main bar parts --------------------------------------------------------- -function main:HideArt() - if self.db.profile.hideArt then - -- the pet bar is a child of MainMenuBar, but can't be hidden because it will - -- break automatic pet bar show/hide. Need to reparent it. - PetActionBarFrame:SetParent(UIParent) - - -- these two are the pet bar background - -- unfortunately UIParent_ManageFramePositions() shows and hides these too - -- so they get reparented to MainMenuBar - SlidingActionBarTexture0:SetParent(MainMenuBar) - SlidingActionBarTexture1:SetParent(MainMenuBar) - - MainMenuBar:Hide() -- this also hides the bags, xp bar, lag meter, and micro menu buttons. - else - SlidingActionBarTexture0:SetParent(PetActionBarFrame) - SlidingActionBarTexture1:SetParent(PetActionBarFrame) - PetActionBarFrame:SetParent(MainMenuBar) - MainMenuBar:Show() - end -end - -function main:IsArtHidden() - return self.db.profile.hideArt -end - -function main:SetHideArt( hide ) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - self.db.profile.hideArt = hide and true or false -- force data integrity - self:HideArt() - end -end - -function main:ToggleHideArt() - self:SetHideArt( not self:IsArtHidden() ) -end - --- Hide default Blizzard bars -local blizzDefaultBars = { - ActionButton1, - ActionButton2, - ActionButton3, - ActionButton4, - ActionButton5, - ActionButton6, - ActionButton7, - ActionButton8, - ActionButton9, - ActionButton10, - ActionButton11, - ActionButton12, - PetActionButton1, - PetActionButton2, - PetActionButton3, - PetActionButton4, - PetActionButton5, - PetActionButton6, - PetActionButton7, - PetActionButton8, - PetActionButton9, - PetActionButton10, - -- NOT the PetActionBarFrame, though - we need that to auto-hide/show our pet action bars - MainMenuBarPageNumber, - ActionBarUpButton, - ActionBarDownButton, - BonusActionBarFrame, - ShapeshiftBarFrame, - MultiBarLeft, - MultiBarRight, - MultiBarBottomLeft, - MultiBarBottomRight, -} - -local function disableUIOptions() - -- disable the buttons to hide/show the blizzard multiaction bars - -- see UIOptionsFrame.lua and .xml - -- This is called every time the options panel is shown, after it is set up - for _, idx in pairs( { 33, 34, 35, 36, 37, 40 } ) do - local f = getglobal("UIOptionsFrameCheckButton"..idx) - f.disabled = true - OptionsFrame_DisableCheckBox(f) - f:SetChecked(false) - end -end - -function main:HideDefaultBars() - for _, f in pairs(blizzDefaultBars) do - f:Hide() - f:ClearAllPoints() - f:SetParent(ReAction.recycler) - f:SetPoint("TOPLEFT") - end - - MainMenuBar:SetFrameStrata("LOW") -- otherwise it appears on top of bars, if it isn't hidden - hooksecurefunc("UIOptionsFrame_Load",disableUIOptions) -end - - - - ---------------------------------------- --- Bar setup and manipulation functions ---------------------------------------- --- Reset bars to blizzard defaults -function main:ResetBars() - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - self.db.profile.bars = tcopy(ReAction_DefaultBlizzardBars) - self:OnProfileEnable() -- treat it like a profile switch - end -end - -function main:DestroyAllBars() - -- destroy any existing bars - for id = 1, table.maxn(self.bars) do - self:DestroyBar(id) - end -end - -function main:SetupBars() - -- set up the bars from the profile - -- note the use of table.maxn rather than # or ipairs: - -- our array of bars can in fact contain holes - for id = 1, table.maxn(self.db.profile.bars) do - local config = self.db.profile.bars[id] - if config then - self.bars[id] = self:CreateBar(config, id) - end - end - - -- anchor the bars, have to do this in a second pass because - -- they might be anchored to each other in a non-ordered way - for _, bar in pairs(self.bars) do - if bar ~= EMPTY_BAR_SLOT then - bar:ApplyAnchor() - end - end -end - -function main:CreateBar( config, id ) - local buttonType = config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) - local subtype = buttonType and buttonType:GetButtonType(config.btnConfig.subtype) - - if not subtype then - self:Print(L["Tried to create a button of unknown type"]) - return - end - - local bar = ReBar:new(config, id) - - -- initialize dewdrop menu - dewdrop:Register(bar:GetControlFrame(), - 'children', - function() - dewdrop:FeedAceOptionsTable(ReActionGlobalMenuOptions) - dewdrop:FeedAceOptionsTable(GenerateReActionBarOptions(bar,self)) - dewdrop:FeedAceOptionsTable(subtype:GenerateOptionsTable(config.btnConfig, function() return bar:GetButtonList() end)) - end, - 'cursorX', true, - 'cursorY', true - ) - - -- register page up/down buttons with ReBound for keybinding - ReBound:Register(bar.upArrow) - ReBound:Register(bar.downArrow) - - if not self.locked then - bar:ShowControls() - end - - return bar -end - -function main:DestroyBar( id ) - local bar = self.bars[id] - if bar and bar ~= EMPTY_BAR_SLOT then - local cf = bar:GetControlFrame() - if cf == dewdrop:GetOpenedParent() then - dewdrop:Close() - dewdrop:Unregister(cf) - end - bar:Destroy() - -- we can't do tremove because each bar ID is encoded into the - -- frame names as they're created. Need a blank entry in the table. - -- The nice thing is that table.insert in NewBar() will automatically - -- find the lowest numbered nil slot. - self.bars[id] = EMPTY_BAR_SLOT - end -end - --- --- this function is a wrapper for CreateBar() which looks up the bar type --- and constructs a new configuration object of the right type. -function main:NewBar( type ) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - return - end - - local t = ReAction:GetButtonType(type) - if t then - local c = tcopy(ReAction_DefaultBarConfig["ReAction"][type]) - local id = nil - for i = 1, table.maxn(self.bars) + 1 do -- there may be holes, so #self.bars won't work - if self.bars[i] == nil or self.bars[i] == EMPTY_BAR_SLOT then - id = i - break - end - end - self.bars[id] = self:CreateBar(c, id) - self.db.profile.bars[id] = c - self.bars[id]:ApplyAnchor() - self:Unlock() - end -end - --- --- This function is a wrapper for DestroyBar() which does in-combat --- checking and updates the config. -function main:DeleteBar(id) - if InCombatLockdown() then - UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) - else - if self.bars[id] then - self:DestroyBar(id) - self.db.profile.bars[id] = nil - end - end -end - - -