diff --git a/Clique.lua b/Clique.lua
index 5405744..0ea2b42 100644
--- a/Clique.lua
+++ b/Clique.lua
@@ -18,12 +18,6 @@ eventFrame:SetScript("OnUpdate", function()
end
end)
eventFrame:Hide()
-
-if not InCombatLockdown then
- function InCombatLockdown()
- return UnitAffectingCombat("player")
- end
-end
function Clique:Enable()
-- Grab the localisation header
@@ -31,28 +25,40 @@ function Clique:Enable()
self.defaults = {
profile = {
- [L.CLICKSET_DEFAULT] = {},
- [L.CLICKSET_HARMFUL] = {},
- [L.CLICKSET_HELPFUL] = {},
- [L.CLICKSET_OOC] = {},
+ clicksets = {
+ [L.CLICKSET_DEFAULT] = {},
+ [L.CLICKSET_HARMFUL] = {},
+ [L.CLICKSET_HELPFUL] = {},
+ [L.CLICKSET_OOC] = {},
+ },
+ blacklist = {
+ },
}
}
self.db = self:InitializeDB("CliqueDB", self.defaults)
self.profile = self.db.profile
+ self.clicksets = self.profile.clicksets
- self.editSet = self.profile[L.CLICKSET_DEFAULT]
+ self.editSet = self.clicksets[L.CLICKSET_DEFAULT]
+
+ ClickCastFrames = ClickCastFrames or {}
+ self.ccframes = ClickCastFrames
local newindex = function(t,k,v)
- Clique:RegisterFrame(k)
- rawset(t,k,v)
+ if v == nil then
+ Clique:UnregisterFrame(k)
+ rawset(self.ccframes, k, nil)
+ else
+ Clique:RegisterFrame(k)
+ rawset(self.ccframes, k, v)
+ end
end
- ClickCastFrames = ClickCastFrames or {}
- setmetatable(ClickCastFrames, {__newindex=newindex})
+ ClickCastFrames = setmetatable({}, {__newindex=newindex})
-- Register all frames that snuck in before we did =)
- for frame in pairs(ClickCastFrames) do
+ for frame in pairs(self.ccframes) do
self:RegisterFrame(frame)
end
@@ -86,10 +92,14 @@ function Clique:Enable()
self:RegisterEvent("LEARNED_SPELL_IN_TAB")
self:LEARNED_SPELL_IN_TAB()
+ -- Register for dongle events
+ self:RegisterEvent("DONGLE_PROFILE_CHANGED")
+ self:RegisterEvent("DONGLE_PROFILE_DELETED")
+
-- Run the OOC script if we need to
Clique:CombatUnlock()
- -- Securehook the RaidFrame_LoadUI
+ -- Securehook CreateFrame to catch any new raid frames
local raidFunc = function(type, name, parent, template)
if template == "RaidPulloutButtonTemplate" then
ClickCastFrames[getglobal(name.."ClearButton")] = true
@@ -123,8 +133,8 @@ function Clique:LEARNED_SPELL_IN_TAB()
for i=1,num do
local name = GetSpellName(i, BOOKTYPE_SPELL)
if forms[name] then
- profile[name] = profile[name] or {}
- self.profile[name] = self.profile[name] or {}
+ --profile[name] = profile[name] or {}
+ --self.profile[name] = self.profile[name] or {}
end
end
end
@@ -166,9 +176,9 @@ function Clique:SpellBookButtonPressed()
local type = "spell"
local button
- if self.editSet == self.profile[L.CLICKSET_HARMFUL] then
+ if self.editSet == self.clicksets[L.CLICKSET_HARMFUL] then
button = string.format("%s%d", "harmbutton", self:GetButtonNumber())
- elseif self.editSet == self.profile[L.CLICKSET_HELPFUL] then
+ elseif self.editSet == self.clicksets[L.CLICKSET_HELPFUL] then
button = string.format("%s%d", "helpbutton", self:GetButtonNumber())
else
button = self:GetButtonNumber()
@@ -200,21 +210,21 @@ end
function Clique:CombatLockdown()
self:Debug(1, "Going into combat mode")
-- Remove all OOC clicks
- for k,v in pairs(self.profile[L.CLICKSET_OOC]) do
+ for k,v in pairs(self.clicksets[L.CLICKSET_OOC]) do
self:DeleteAction(v)
self:Debug(1, "Removing %s, %s", v.type, tostring(v.arg1))
end
-- Just bluntly force our clicks back onto the frames
- for frame in pairs(ClickCastFrames) do
+ for frame in pairs(self.ccframes) do
self:RegisterFrame(frame)
end
end
function Clique:CombatUnlock()
self:Debug(1, "Setting any out of combat clicks")
- for frame in pairs(ClickCastFrames) do
- for k,v in pairs(self.profile[L.CLICKSET_OOC]) do
+ for frame in pairs(self.cc.frames) do
+ for k,v in pairs(self.clicksets[L.CLICKSET_OOC]) do
self:SetAttribute(v,frame)
end
end
@@ -253,11 +263,24 @@ function Clique:ClearQueue()
end
function Clique:RegisterFrame(frame)
- if self:CombatDelay(frame) then return end
+ local name = frame:GetName()
+ if self.profile.blacklist[name] then
+ rawset(self.ccframes, frame, false)
+ return
+ end
+
+-- if self:CombatDelay(frame) then return end
+ if not ClickCastFrames[frame] then
+ rawset(self.ccframes, frame, true)
+ if CliqueTextListFrame then
+ Clique:TextListScrollUpdate()
+ end
+ end
+
-- Ensure we have all the buttons registered
frame:RegisterForClicks("LeftButtonUp", "MiddleButtonUp", "RightButtonUp", "Button4Up", "Button5Up")
- for name,set in pairs(self.profile) do
+ for name,set in pairs(self.clicksets) do
if name ~= L.CLICKSET_OOC then
for modifier,entry in pairs(set) do
self:SetAttribute(entry, frame)
@@ -266,26 +289,62 @@ function Clique:RegisterFrame(frame)
end
end
-function Clique:ProfileChanged(new)
- for name,set in pairs(self.profile) do
- for modifier,entry in pairs(set) do
- self:DeleteAction(entry)
- end
+function Clique:UnregisterFrame(frame)
+ for name,set in pairs(self.clicksets) do
+ for modifier,entry in pairs(set) do
+ local type,button,value
+
+ if not tonumber(entry.button) then
+ type,button = select(3, string.find(entry.button, "(%a+)button(%d+)"))
+ frame:SetAttribute(entry.modifier..entry.button, nil)
+ button = string.format("-%s%s", type, button)
+ end
+
+ button = button or entry.button
+
+ entry.delete = true
+
+ frame:SetAttribute(entry.modifier.."type"..button, nil)
+ frame:SetAttribute(entry.modifier..entry.type..button, nil)
+ end
end
+end
- self.profile = self.db.profile
- self.editSet = self.profile[L.CLICKSET_DEFAULT]
- self.profileKey = new
+function Clique:DONGLE_PROFILE_CHANGED(event, addon, name)
+ if addon == "Clique" then
+ self:Print("Profile has changed to '%s'.", name)
+ for name,set in pairs(self.clicksets) do
+ for modifier,entry in pairs(set) do
+ self:DeleteAction(entry)
+ end
+ end
+
+ self.profile = self.db.profile
+ self.clicksets = self.profile.clicksets
+ self.editSet = self.clicksets[L.CLICKSET_DEFAULT]
+ self.profileKey = new
- -- refresh the dropdown if its active
- CliqueDropDownProfile:Hide()
- CliqueDropDownProfile:Show()
+ -- Refresh the profile editor if it exists
+ self.textlistSelected = nil
+ self:TextListScrollUpdate()
+ self:ListScrollUpdate()
- for frame in pairs(ClickCastFrames) do
- self:RegisterFrame(frame)
- end
+ for frame in pairs(self.ccframes) do
+ self:RegisterFrame(frame)
+ end
+ end
end
+function Clique:DONGLE_PROFILE_DELETED(event, addon, name)
+ if addon == "Clique" then
+ self:Print("Profile '%s' has been deleted.", name)
+
+ self.textlistSelected = nil
+ self:TextListScrollUpdate()
+ self:ListScrollUpdate()
+ end
+end
+
function Clique:SetAttribute(entry, frame)
-- Set up any special attributes
local type,button,value
@@ -328,6 +387,7 @@ function Clique:SetAttribute(entry, frame)
elseif entry.type == "macro" then
frame:SetAttribute(entry.modifier.."type"..button, entry.type)
frame:SetAttribute(entry.modifier.."macro"..button, entry.arg1)
+ frame:SetAttribute(entry.modifier.."macrotext"..button, entry.arg2)
elseif entry.type == "stop" then
frame:SetAttribute(entry.modifier.."type"..button, entry.type)
elseif entry.type == "target" then
@@ -347,8 +407,10 @@ end
function Clique:SetAction(entry)
if self:CombatDelay(entry) then return end
- for frame in pairs(ClickCastFrames) do
- self:SetAttribute(entry, frame)
+ for frame,enabled in pairs(self.ccframes) do
+ if enabled then
+ self:SetAttribute(entry, frame)
+ end
end
end
@@ -357,7 +419,7 @@ function Clique:DeleteAction(entry)
if not tonumber(entry.button) then
type,button = select(3, string.find(entry.button, "(%a+)button(%d+)"))
- for frame in pairs(ClickCastFrames) do
+ for frame in pairs(self.ccframes) do
frame:SetAttribute(entry.modifier..entry.button, nil)
end
button = string.format("-%s%s", type, button)
@@ -368,7 +430,7 @@ function Clique:DeleteAction(entry)
entry.delete = true
if self:CombatDelay(entry) then return end
- for frame in pairs(ClickCastFrames) do
+ for frame in pairs(self.ccframes) do
frame:SetAttribute(entry.modifier.."type"..button, nil)
frame:SetAttribute(entry.modifier..entry.type..button, nil)
end
diff --git a/Clique.toc b/Clique.toc
index 437e21e..c8a4ebe 100644
--- a/Clique.toc
+++ b/Clique.toc
@@ -5,6 +5,7 @@
## SavedVariables: CliqueDB
## OptionalDeps: Dongle
+Dongle.lua
Clique.lua
Clique.xml
Localization.en.lua
diff --git a/CliqueOptions.lua b/CliqueOptions.lua
index 8e1bac9..07b0d4c 100644
--- a/CliqueOptions.lua
+++ b/CliqueOptions.lua
@@ -12,6 +12,37 @@ function Clique:OptionsOnLoad()
this.updateTooltip = nil
GameTooltip:Hide()
end
+
+ self.special = CreateFrame("Frame", UIParent)
+ self.special:SetFrameStrata("DIALOG")
+ self.special:SetHeight(32)
+ self.special:SetWidth(32)
+ self.special.texture = self.special:CreateTexture("ARTWORK")
+ self.special.texture:SetTexture("Interface\\AddOns\\Clique\\Images\\myborder")
+ self.special.texture:SetAllPoints()
+ self.special:SetAlpha(1.0)
+
+ CreateFrame("Button", "CliqueSpecialButton")
+
+ CliqueSpecialButton:SetScript("OnClick", function()
+ if not self.sequence then self.sequence = 1 end
+ ClearOverrideBindings(CliqueSpecialButton)
+ if self.sequence == 1 then
+ SetOverrideBindingClick(CliqueSpecialButton, true, "O", "CliqueSpecialButton")
+ elseif self.sequence == 2 then
+ SetOverrideBindingClick(CliqueSpecialButton, true, "L", "CliqueSpecialButton")
+ elseif self.sequence == 3 then
+ SetOverrideBindingClick(CliqueSpecialButton, true, "E", "CliqueSpecialButton")
+ elseif self.sequence == 4 then
+ self:Print("Special mode activated")
+ for k,v in pairs(self.ccframes) do
+ k:SetScript("PostClick", function()
+ self.special:SetPoint("CENTER", k, "CENTER", 0, 0)
+ end)
+ end
+ end
+ self.sequence = self.sequence + 1
+ end)
for i=1,12 do
local parent = getglobal("SpellButton"..i)
@@ -33,7 +64,7 @@ function Clique:OptionsOnLoad()
CliquePulloutTab:SetScript("OnEnter", function() local i = 1 end)
CliquePulloutTab:SetScript("OnShow", function()
Clique.inuse = nil
- for k,v in pairs(self.profile) do
+ for k,v in pairs(self.clicksets) do
if next(v) then
Clique.inuse = true
end
@@ -131,6 +162,10 @@ function Clique:Toggle()
Clique:CreateOptionsFrame()
CliqueFrame:Hide()
CliqueFrame:Show()
+ SetOverrideBindingClick(CliqueSpecialButton, true, "M", "CliqueSpecialButton")
+ CliqueFrame:SetScript("OnHide", function()
+ ClearOverrideBindings(CliqueSpecialButton)
+ end)
else
if CliqueFrame:IsVisible() then
CliqueFrame:Hide()
@@ -138,6 +173,7 @@ function Clique:Toggle()
else
CliqueFrame:Show()
CliquePulloutTab:SetChecked(true)
+ SetOverrideBindingClick(CliqueSpecialButton, true, "M", "CliqueSpecialButton")
end
end
@@ -164,6 +200,7 @@ function Clique:SkinFrame(frame)
});
frame:EnableMouse()
+ frame:SetClampedToScreen(true)
frame.titleBar = CreateFrame("Button", nil, frame)
frame.titleBar:SetHeight(32)
@@ -229,6 +266,15 @@ function Clique:CreateOptionsFrame()
CliqueHelpText:Show()
end
end)
+
+ CliqueFrame:SetScript("OnShow", function()
+ if InCombatLockdown() then
+ CliqueFrame:Hide()
+ end
+ Clique:ToggleSpellBookButtons()
+ end)
+
+ CliqueFrame:SetScript("OnHide", function() Clique:ToggleSpellBookButtons() end)
local frame = CreateFrame("Frame", "CliqueListFrame", CliqueFrame)
frame:SetAllPoints()
@@ -271,10 +317,10 @@ function Clique:CreateOptionsFrame()
entry.icon:SetWidth(24)
entry.icon:SetPoint("LEFT", 5, 0)
- entry.name = entry:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ entry.name = entry:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
entry.name:SetPoint("LEFT", entry.icon, "RIGHT", 5, 0)
- entry.binding = entry:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ entry.binding = entry:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
entry.binding:SetPoint("RIGHT", entry, "RIGHT", -5, 0)
frames[i] = entry
end
@@ -306,6 +352,118 @@ function Clique:CreateOptionsFrame()
CliqueListScroll:SetScript("OnVerticalScroll", function() FauxScrollFrame_OnVerticalScroll(ENTRY_SIZE, update) end)
CliqueListScroll:SetScript("OnShow", update)
+ local frame = CreateFrame("Frame", "CliqueTextListFrame", CliqueFrame)
+ frame:SetHeight(300)
+ frame:SetWidth(250)
+ frame:SetPoint("BOTTOMLEFT", CliqueFrame, "BOTTOMRIGHT", 0, 0)
+ self:SkinFrame(frame)
+ frame:SetFrameStrata("HIGH")
+
+ local onclick = function()
+ local offset = FauxScrollFrame_GetOffset(CliqueTextListScroll)
+ if self.textlistSelected == offset + this.id then
+ self.textlistSelected = nil
+ else
+ self.textlistSelected = offset + this.id
+ end
+ if self.textlist == "FRAMES" then
+ local name = this.name:GetText()
+ local frame = getglobal(name)
+ if this:GetChecked() then
+ self.profile.blacklist[name] = nil
+ self:RegisterFrame(getglobal(name))
+ else
+ self.profile.blacklist[name] = true
+ self:UnregisterFrame(frame)
+ end
+ end
+ Clique:TextListScrollUpdate()
+ end
+
+ local onenter = function() this:SetBackdropBorderColor(1, 1, 1) end
+ local onleave = function()
+ local selected = FauxScrollFrame_GetOffset(CliqueTextListScroll) + this.id
+ this:SetBackdropBorderColor(0.3, 0.3, 0.3)
+ end
+
+ local frames = {}
+
+ for i=1,12 do
+ local entry = CreateFrame("CheckButton", "CliqueTextList"..i, frame)
+ entry.id = i
+ entry:SetHeight(22)
+ entry:SetWidth(240)
+ entry:SetBackdrop({
+-- bgFile="Interface\\Tooltips\\UI-Tooltip-Background",
+-- edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
+-- tile = true, tileSize = 8, edgeSize = 16,
+ insets = {left = 2, right = 2, top = 2, bottom = 2}})
+
+ entry:SetBackdropBorderColor(0.3, 0.3, 0.3)
+ entry:SetBackdropColor(0.1, 0.1, 0.1, 0.3)
+ entry:SetScript("OnClick", onclick)
+ entry:SetScript("OnEnter", onenter)
+ entry:SetScript("OnLeave", onleave)
+
+ local texture = entry:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ entry:SetNormalTexture(texture)
+
+ local texture = entry:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ texture:SetBlendMode("ADD")
+ entry:SetHighlightTexture(texture)
+
+ local texture = entry:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ entry:SetCheckedTexture(texture)
+
+ entry.name = entry:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ entry.name:SetPoint("LEFT", 25, 0)
+ entry.name:SetJustifyH("LEFT")
+ entry.name:SetText("Profile Name")
+ frames[i] = entry
+ end
+
+ frames[1]:SetPoint("TOPLEFT", 5, -25)
+ for i=2,12 do
+ frames[i]:SetPoint("TOP", frames[i-1], "BOTTOM", 0, 2)
+ end
+
+ local endButton = CliqueTextList12
+ CreateFrame("ScrollFrame", "CliqueTextListScroll", CliqueTextListFrame, "FauxScrollFrameTemplate")
+ CliqueTextListScroll:SetPoint("TOPLEFT", CliqueTextList1, "TOPLEFT", 0, 0)
+ CliqueTextListScroll:SetPoint("BOTTOMRIGHT", endButton, "BOTTOMRIGHT", 0, 0)
+
+ local texture = CliqueTextListScroll:CreateTexture(nil, "BACKGROUND")
+ texture:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
+ texture:SetPoint("TOPLEFT", CliqueTextListScroll, "TOPRIGHT", 14, 0)
+ texture:SetPoint("BOTTOMRIGHT", CliqueTextListScroll, "BOTTOMRIGHT", 23, 0)
+ texture:SetGradientAlpha("HORIZONTAL", 0.5, 0.25, 0.05, 0, 0.15, 0.15, 0.15, 1)
+
+ local texture = CliqueTextListScroll:CreateTexture(nil, "BACKGROUND")
+ texture:SetTexture("Interface\\ChatFrame\\ChatFrameBackground")
+ texture:SetPoint("TOPLEFT", CliqueTextListScroll, "TOPRIGHT", 4, 0)
+ texture:SetPoint("BOTTOMRIGHT", CliqueTextListScroll, "BOTTOMRIGHT", 14, 0)
+ texture:SetGradientAlpha("HORIZONTAL", 0.15, 0.15, 0.15, 0.15, 1, 0.5, 0.25, 0.05, 0)
+
+ local update = function()
+ Clique:TextListScrollUpdate()
+ end
+
+ CliqueTextListScroll:SetScript("OnVerticalScroll", function() FauxScrollFrame_OnVerticalScroll(22, update) end)
+ CliqueTextListFrame:SetScript("OnShow", update)
+ CliqueTextListFrame:Hide()
+
-- Dropdown Frame
CreateFrame("Frame", "CliqueDropDown", CliqueFrame, "UIDropDownMenuTemplate")
CliqueDropDown:SetID(1)
@@ -315,14 +473,6 @@ function Clique:CreateOptionsFrame()
local font = CliqueDropDown:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
font:SetText("Click Set:")
font:SetPoint("RIGHT", CliqueDropDown, "LEFT", 5, 3)
-
- -- Profile Dropdown Frame
- CreateFrame("Frame", "CliqueDropDownProfile", CliqueFrame, "UIDropDownMenuTemplate")
- CliqueDropDownProfile:SetID(1)
- CliqueDropDownProfile:SetPoint("TOPLEFT", CliqueFrame, "TOPLEFT", -10, -25)
- CliqueDropDownProfile:SetScript("OnShow", function() Clique:DropDownProfile_OnShow() end)
- UIDropDownMenu_SetWidth(150, CliqueDropDownProfile)
-
-- Button Creations
local buttonFunc = function() Clique:ButtonOnClick() end
@@ -332,36 +482,78 @@ function Clique:CreateOptionsFrame()
button:SetPoint("TOPRIGHT", -5, 3)
button:SetScript("OnClick", buttonFunc)
+ local button = CreateFrame("Button", "CliqueButtonCustom", CliqueFrame, "UIPanelButtonGrayTemplate")
+ button:SetHeight(24)
+ button:SetWidth(60)
+ button:SetText("Custom")
+ button:SetPoint("BOTTOMLEFT", CliqueFrame, "BOTTOMLEFT", 10, 5)
+ button:SetScript("OnClick", buttonFunc)
+
+ local button = CreateFrame("Button", "CliqueButtonOptions", CliqueFrame, "UIPanelButtonGrayTemplate")
+ button:SetHeight(24)
+ button:SetWidth(60)
+ button:SetText("Options")
+ button:SetPoint("LEFT", CliqueButtonCustom, "RIGHT", 3, 0)
+ button:SetScript("OnClick", buttonFunc)
+
+ local button = CreateFrame("Button", "CliqueButtonProfiles", CliqueFrame, "UIPanelButtonGrayTemplate")
+ button:SetHeight(24)
+ button:SetWidth(60)
+ button:SetText("Profiles")
+ button:SetPoint("LEFT", CliqueButtonOptions, "RIGHT", 3, 0)
+ button:SetScript("OnClick", buttonFunc)
+
local button = CreateFrame("Button", "CliqueButtonDelete", CliqueFrame, "UIPanelButtonGrayTemplate")
button:SetHeight(24)
- button:SetWidth(70)
+ button:SetWidth(60)
button:SetText("Delete")
- button:SetPoint("BOTTOM", -38, 4)
+ button:SetPoint("LEFT", CliqueButtonProfiles, "RIGHT", 3, 0)
button:SetScript("OnClick", buttonFunc)
local button = CreateFrame("Button", "CliqueButtonEdit", CliqueFrame, "UIPanelButtonGrayTemplate")
button:SetHeight(24)
- button:SetWidth(70)
+ button:SetWidth(60)
button:SetText("Edit")
- button:SetPoint("BOTTOM", 38, 4)
+ button:SetPoint("LEFT", CliqueButtonDelete, "RIGHT", 3, 0)
button:SetScript("OnClick", buttonFunc)
local button = CreateFrame("Button", "CliqueButtonMax", CliqueFrame, "UIPanelButtonGrayTemplate")
button:SetHeight(24)
- button:SetWidth(70)
- button:SetText("Max Rank")
- button:SetPoint("LEFT", CliqueButtonEdit, "RIGHT", 6, 0)
+ button:SetWidth(60)
+ button:SetText("Max")
+ button:SetPoint("LEFT", CliqueButtonEdit, "RIGHT", 3, 0)
button:SetScript("OnClick", buttonFunc)
- -- Create the custom edit screen
- local button = CreateFrame("Button", "CliqueButtonCustom", CliqueFrame, "UIPanelButtonGrayTemplate")
+ -- Buttons for text list scroll frame
+
+ local button = CreateFrame("Button", "CliqueTextButtonClose", CliqueTextListFrame.titleBar, "UIPanelCloseButton")
+ button:SetHeight(25)
+ button:SetWidth(25)
+ button:SetPoint("TOPRIGHT", -5, 3)
+ button:SetScript("OnClick", buttonFunc)
+
+ local button = CreateFrame("Button", "CliqueButtonDeleteProfile", CliqueTextListFrame, "UIPanelButtonGrayTemplate")
button:SetHeight(24)
- button:SetWidth(70)
- button:SetText("Custom")
- button:SetPoint("RIGHT", CliqueButtonDelete, "LEFT", -6, 0)
+ button:SetWidth(60)
+ button:SetText("Delete")
+ button:SetPoint("BOTTOMLEFT", CliqueTextListFrame, "BOTTOMLEFT", 30, 5)
button:SetScript("OnClick", buttonFunc)
- self.customEntry = {}
-
+
+ local button = CreateFrame("Button", "CliqueButtonSetProfile", CliqueTextListFrame, "UIPanelButtonGrayTemplate")
+ button:SetHeight(24)
+ button:SetWidth(60)
+ button:SetText("Set")
+ button:SetPoint("LEFT", CliqueButtonDeleteProfile, "RIGHT", 3, 0)
+ button:SetScript("OnClick", buttonFunc)
+
+ local button = CreateFrame("Button", "CliqueButtonNewProfile", CliqueTextListFrame, "UIPanelButtonGrayTemplate")
+ button:SetHeight(24)
+ button:SetWidth(60)
+ button:SetText("New")
+ button:SetPoint("LEFT", CliqueButtonSetProfile, "RIGHT", 3, 0)
+ button:SetScript("OnClick", buttonFunc)
+
+ self.customEntry = {}
local frame = CreateFrame("Frame", "CliqueCustomFrame", CliqueFrame)
frame:SetHeight(375)
frame:SetWidth(450)
@@ -395,11 +587,51 @@ function Clique:CreateOptionsFrame()
{type = "click", name = "Click Button"},
}
+ for i=1,#buttons do
+ local entry = buttons[i]
+
+ local name = "CliqueRadioButton"..entry.type
+ local button = CreateFrame("CheckButton", name, CliqueCustomFrame)
+ button:SetHeight(20)
+ button:SetWidth(150)
+
+ local texture = button:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\AddOns\\Clique\\images\\RadioEmpty")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ button:SetNormalTexture(texture)
+
+ local texture = button:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\AddOns\\Clique\\images\\RadioChecked")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ texture:SetBlendMode("ADD")
+ button:SetHighlightTexture(texture)
+
+ local texture = button:CreateTexture("ARTWORK")
+ texture:SetTexture("Interface\\AddOns\\Clique\\images\\RadioChecked")
+ texture:SetPoint("LEFT", 0, 0)
+ texture:SetHeight(20)
+ texture:SetWidth(20)
+ button:SetCheckedTexture(texture)
+
+ button.name = button:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
+ button.name:SetPoint("LEFT", 25, 0)
+ button.name:SetJustifyH("LEFT")
+
+ local entry = buttons[1]
+ local name = "CliqueRadioButton"..entry.type
+ local button = CreateFrame("CheckButton", name, CliqueCustomFrame)
+ button:SetHeight(22)
+ button:SetWidth(150)
+ end
+
local entry = buttons[1]
- local name = "CliqueRadioButton"..entry.type
- local button = CreateFrame("CheckButton", name, CliqueCustomFrame, "UIRadioButtonTemplate")
+ local button = getglobal("CliqueRadioButton"..entry.type)
button.type = entry.type
- getglobal(name.."Text"):SetText(entry.name)
+ button.name:SetText(entry.name)
button:SetPoint("TOPLEFT", 5, -30)
button:SetScript("OnClick", checkFunc)
self.radio[button] = true
@@ -409,18 +641,16 @@ function Clique:CreateOptionsFrame()
for i=2,#buttons do
local entry = buttons[i]
local name = "CliqueRadioButton"..entry.type
- local button = CreateFrame("CheckButton", name, CliqueCustomFrame, "UIRadioButtonTemplate")
+ local button = getglobal(name)
+
button.type = entry.type
- getglobal(name.."Text"):SetText(entry.name)
+ button.name:SetText(entry.name)
button:SetPoint("TOPLEFT", prev, "BOTTOMLEFT", 0, 0)
button:SetScript("OnClick", checkFunc)
self.radio[button] = true
prev = button
end
- -- Disable the click button
- CliqueRadioButtonclick:Disable()
-
-- Button to set the binding
local button = CreateFrame("Button", "CliqueCustomButtonBinding", CliqueCustomFrame, "UIPanelButtonGrayTemplate")
@@ -458,6 +688,7 @@ function Clique:CreateOptionsFrame()
local edit = CreateFrame("EditBox", "CliqueCustomArg1", CliqueCustomFrame, "InputBoxTemplate")
edit:SetHeight(30)
edit:SetWidth(200)
+ edit:SetMultiLine(true)
edit:SetPoint("TOPRIGHT", CliqueCustomFrame, "TOPRIGHT", -10, -190)
edit:SetAutoFocus(nil)
edit:SetScript("OnTabPressed", function()
@@ -681,7 +912,8 @@ function Clique:CreateOptionsFrame()
-- Create the CliqueHelpText
CliqueFrame:CreateFontString("CliqueHelpText", "OVERLAY", "GameFontHighlight")
CliqueHelpText:SetText(L.HELP_TEXT)
- CliqueHelpText:SetAllPoints()
+ CliqueHelpText:SetPoint("TOPLEFT", 10, -10)
+ CliqueHelpText:SetPoint("BOTTOMRIGHT", -10, 10)
CliqueHelpText:SetJustifyH("CENTER")
CliqueHelpText:SetJustifyV("CENTER")
CliqueHelpText:SetPoint("CENTER", 0, 0)
@@ -691,8 +923,9 @@ function Clique:CreateOptionsFrame()
end
function Clique:ListScrollUpdate()
- local idx,button
+ if not CliqueListScroll then return end
+ local idx,button
Clique:SortList()
local clickCasts = self.sortList
local offset = FauxScrollFrame_GetOffset(CliqueListScroll)
@@ -763,7 +996,7 @@ function Clique:ValidateButtons()
-- Disable the help text
Clique.inuse = nil
- for k,v in pairs(self.profile) do
+ for k,v in pairs(self.clicksets) do
if next(v) then
Clique.inuse = true
end
@@ -784,20 +1017,34 @@ function Clique:FillListEntry(frame, idx)
frame.icon:SetTexture(entry.texture or "Interface/Icons/Ability_Rogue_Sprint")
frame.binding:SetText(entry.modifier..self:GetButtonText(button))
+
if entry.type == "action" then
- frame.name:SetText(string.format("Action Button %d", entry.arg1))
+ frame.name:SetText(string.format("Action Button %d%s", entry.arg1, entry.arg2 and " on "..entry.arg2 or ""))
+ elseif entry.type == "actionbar" then
+ frame.name:SetText(string.format("Action Bar: %s", entry.arg1))
elseif entry.type == "pet" then
- frame.name:SetText(string.format("Pet Action %d", entry.arg1))
+ frame.name:SetText(string.format("Pet Action %d%s", entry.arg1, entry.arg2 and " on "..entry.arg2 or ""))
elseif entry.type == "spell" then
- frame.name:SetText(string.format(entry.arg2 and "%s (%s %d)" or "%s", entry.arg1, L.RANK, entry.arg2))
+ if entry.arg2 then
+ frame.name:SetText(string.format("%s (%s %d)%s", entry.arg1, L.RANK, entry.arg2,
+ entry.arg5 and " on "..entry.arg5 or ""))
+ else
+ frame.name:SetText(string.format("%s%s", entry.arg1, entry.arg5 and " on "..entry.arg5 or ""))
+ end
elseif entry.type == "stop" then
frame.name:SetText("Stop Casting")
elseif entry.type == "target" then
- frame.name:SetText("Target Unit")
+ frame.name:SetText("Target Unit: %s" .. entry.arg2 and entry.arg2 or "")
elseif entry.type == "focus" then
- frame.name:SetText("Set Focus Unit")
+ frame.name:SetText("Set Focus Unit: %s" .. entry.arg2 and entry.arg2 or "")
elseif entry.type == "assist" then
- frame.name:SetText("Assist Unit")
+ frame.name:SetText("Assist Unit: %s" .. entry.arg2 and entry.arg2 or "")
+ elseif entry.type == "item" then
+ if entry.arg1 then
+ frame.name:SetText(string.format("Item: %d,%d", entry.arg1, entry.arg2))
+ elseif entry.arg3 then
+ frame.name:SetText(string.format("Item: %s", entry.arg3))
+ end
end
frame:Show()
@@ -826,6 +1073,8 @@ function Clique:ButtonOnClick(button)
self:ListScrollUpdate()
elseif this == CliqueButtonClose then
self:Toggle()
+ elseif this == CliqueTextButtonClose then
+ CliqueTextListFrame:Hide()
elseif this == CliqueButtonMax then
entry.arg2 = nil
self:DeleteAction(entry)
@@ -836,6 +1085,47 @@ function Clique:ButtonOnClick(button)
else
CliqueCustomFrame:Show()
end
+ elseif this == CliqueButtonOptions then
+ if CliqueTextListFrame:IsVisible() and self.textlist == "FRAMES" then
+ CliqueTextListFrame:Hide()
+ else
+ CliqueTextListFrame:Show()
+ end
+
+ self.textlist = "FRAMES"
+ CliqueButtonDeleteProfile:Hide()
+ CliqueButtonSetProfile:Hide()
+ CliqueButtonNewProfile:Hide()
+
+ self:TextListScrollUpdate()
+ CliqueTextListFrame.title:SetText("Clique Frame Editor")
+ self.textlistSelected = nil
+ elseif this == CliqueButtonProfiles then
+ if CliqueTextListFrame:IsVisible() and self.textlist == "PROFILES" then
+ CliqueTextListFrame:Hide()
+ else
+ CliqueTextListFrame:Show()
+ end
+ self.textlist = "PROFILES"
+ self:TextListScrollUpdate()
+ CliqueButtonDeleteProfile:Show()
+ CliqueButtonSetProfile:Show()
+ CliqueButtonNewProfile:Show()
+
+ --CliqueTextListFrame.title:SetText("Profile: " .. self.db.char.profileKey)
+ self.textlistSelected = nil
+ elseif this == CliqueButtonSetProfile then
+ local offset = FauxScrollFrame_GetOffset(CliqueTextListScroll)
+ local selected = self.textlistSelected - offset
+ local button = getglobal("CliqueTextList"..selected)
+ self:SetProfile(button.name:GetText())
+ elseif this == CliqueButtonNewProfile then
+ StaticPopup_Show("CLIQUE_NEW_PROFILE")
+ elseif this == CliqueButtonDeleteProfile then
+ local offset = FauxScrollFrame_GetOffset(CliqueTextListScroll)
+ local selected = self.textlistSelected - offset
+ local button = getglobal("CliqueTextList"..selected)
+ self:DeleteProfile(button.name:GetText())
elseif this == CliqueButtonEdit then
-- Make a copy of the entry
self.customEntry = {}
@@ -963,7 +1253,7 @@ function Clique:DropDown_Initialize()
for k,v in pairs(work) do
info = {}
info.text = v
- info.value = Clique.profile[v]
+ info.value = self.clicksets[v]
info.func = click_func
UIDropDownMenu_AddButton(info)
end
@@ -978,7 +1268,7 @@ end
function Clique:DropDown_OnShow()
work = {}
- for k,v in pairs(self.profile) do
+ for k,v in pairs(self.clicksets) do
table.insert(work, k)
end
table.sort(work)
@@ -988,65 +1278,6 @@ function Clique:DropDown_OnShow()
Clique:ListScrollUpdate()
end
--- Profile dropdown
-
-local work
-local click_func = function() Clique:DropDownProfile_OnClick() end
-
-function Clique:DropDownProfile_Initialize()
- local info = {}
-
- for k,v in ipairs(work) do
- info = {}
- info.text = v
- info.value = v
- info.func = click_func
- UIDropDownMenu_AddButton(info)
- end
-
- info = {
- text = "New profile",
- value = -1,
- func = click_func
- }
- UIDropDownMenu_AddButton(info)
-
- info = {
- text = "Delete Profile",
- value = -2,
- func = click_func
- }
- UIDropDownMenu_AddButton(info)
-end
-
-function Clique:DropDownProfile_OnClick()
- if this.value == -1 then
- StaticPopup_Show("CLIQUE_NEW_PROFILE")
- return
- elseif this.value == -2 then
- StaticPopup_Show("CLIQUE_DELETE_PROFILE")
- return
- end
-
- UIDropDownMenu_SetSelectedValue(CliqueDropDownProfile, this.value)
- self:SetProfile(this.value)
- self.listSelected = 0
- Clique:ListScrollUpdate()
-end
-
-function Clique:DropDownProfile_OnShow()
- work = {}
- for k,v in pairs(self.db.profiles) do
- table.insert(work, k)
- end
- table.sort(work)
-
- UIDropDownMenu_Initialize(this, function() Clique:DropDownProfile_Initialize() end);
- UIDropDownMenu_SetSelectedValue(CliqueDropDownProfile, self.db.char.profileKey)
- Clique:ListScrollUpdate()
-end
-
-
function Clique:CustomBinding_OnClick()
-- This handles the binding click
local mod = self:GetModifierText()
@@ -1142,7 +1373,7 @@ function Clique:CustomRadio(button)
CliqueCustomButtonBinding:SetText("Set Click Binding")
return
end
-
+
-- Clear any open arguments
CliqueCustomArg1:SetText("")
CliqueCustomArg2:SetText("")
@@ -1330,3 +1561,95 @@ StaticPopupDialogs["CLIQUE_DELETE_PROFILE"] = {
ClearCursor();
end
}
+
+local work = {}
+
+function Clique:TextListScrollUpdate()
+ if not CliqueTextListScroll then return end
+
+ local idx,button
+ for k,v in pairs(work) do work[k] = nil end
+
+ if not self.textlist then self.textlist = "FRAMES" end
+
+ if self.textlist == "PROFILES" then
+ for k,v in pairs(self.db.profiles) do table.insert(work, k) end
+ table.sort(work)
+ CliqueTextListFrame.title:SetText("Profile: " .. self.db.char.profileKey)
+
+ elseif self.textlist == "FRAMES" then
+ for k,v in pairs(self.ccframes) do
+ local name = k:GetName()
+ if name then
+ table.insert(work, name)
+ end
+ end
+ table.sort(work)
+ end
+
+ local offset = FauxScrollFrame_GetOffset(CliqueTextListScroll)
+ FauxScrollFrame_Update(CliqueTextListScroll, #work, 12, 22)
+
+ if not CliqueTextListScroll:IsShown() then
+ CliqueTextListFrame:SetWidth(250)
+ else
+ CliqueTextListFrame:SetWidth(275)
+ end
+
+ for i=1,12 do
+ idx = offset + i
+ button = getglobal("CliqueTextList"..i)
+ if idx <= #work then
+ button.name:SetText(work[idx])
+ button:Show()
+ -- Change texture
+ if self.textlist == "PROFILES" then
+ button:SetNormalTexture("Interface\\AddOns\\Clique\\images\\RadioEmpty")
+ button:SetCheckedTexture("Interface\\AddOns\\Clique\\images\\RadioChecked")
+ button:SetHighlightTexture("Interface\\AddOns\\Clique\\images\\RadioChecked")
+ else
+ button:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
+ button:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check")
+ button:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
+ end
+
+ if self.textlistSelected == nil and self.textlist == "PROFILES" then
+ if work[idx] == self.db.char.profileKey then
+ button:SetChecked(true)
+ CliqueButtonSetProfile:Disable()
+ CliqueButtonDeleteProfile:Disable()
+ else
+ button:SetChecked(nil)
+ end
+ elseif idx == self.textlistSelected and self.textlist == "PROFILES" then
+ if work[idx] == self.db.char.profileKey then
+ CliqueButtonSetProfile:Disable()
+ CliqueButtonDeleteProfile:Disable()
+ else
+ CliqueButtonSetProfile:Enable()
+ CliqueButtonDeleteProfile:Enable()
+ end
+ button:SetChecked(true)
+ elseif self.textlist == "FRAMES" then
+ local name = work[idx]
+ local frame = getglobal(name)
+
+ if not self.profile.blacklist then
+ self.profile.blacklist = {}
+ end
+ local bl = self.profile.blacklist
+
+ if bl[name] then
+ button:SetChecked(nil)
+ else
+ button:SetChecked(true)
+ end
+ else
+ button:SetBackdropBorderColor(0.3, 0.3, 0.3)
+ button:SetChecked(nil)
+ end
+ else
+ button:Hide()
+ end
+ end
+end
diff --git a/Dongle.lua b/Dongle.lua
new file mode 100644
index 0000000..0d513fd
--- /dev/null
+++ b/Dongle.lua
@@ -0,0 +1,686 @@
+--[[-------------------------------------------------------------------------
+ Copyright (c) 2006, Dongle Development Team
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of the Dongle Development Team nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------]]
+
+local major,minor = "DongleStub", 1
+local g = getfenv(0)
+
+if not g.DongleStub or g.DongleStub:IsNewerVersion(major, minor) then
+ local lib = setmetatable({}, {
+ __call = function(t,k)
+ if type(t.versions == "table") and t.versions[k] then
+ return t.versions[k]
+ else
+ error("Cannot find a library with name '"..tostring(k).."'")
+ end
+ end
+ })
+
+ function lib:IsNewerVersion(major, minor)
+ local entry = self.versions and self.versions[major]
+
+ if not entry then return true end
+ local oldmajor,oldminor = entry:GetVersion()
+
+ return minor > oldminor
+ end
+
+ function lib:Register(new)
+ local major,minor = new:GetVersion()
+ if not self:IsNewerVersion(major, minor) then return false end
+ local old = self.versions and self.versions[major]
+ -- Run the new libraries activation
+ new:Activate(old)
+
+ -- Deactivate the old libary if necessary
+ if old and old.Deactivate then old:Deactivate(new) end
+
+ self.versions[major] = new
+ end
+
+ function lib:GetVersion() return major,minor end
+
+ function lib:Activate(old)
+ if old then
+ self.versions = old.versions
+ else
+ self.versions = {}
+ end
+ g.DongleStub = self
+ end
+
+ -- Actually trigger libary activation here
+ local stub = g.DongleStub or lib
+ stub:Register(lib)
+end
+
+--[[-------------------------------------------------------------------------
+Begin Library Implementation
+---------------------------------------------------------------------------]]
+
+local major = "Dongle"
+local minor = tonumber(select(3,string.find("$Revision: 67 $", "(%d+)")) or 1)
+
+assert(DongleStub, string.format("%s requires DongleStub.", major))
+if not DongleStub:IsNewerVersion(major, minor) then return end
+
+Dongle = {}
+local methods = {
+ "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents", "TriggerEvent",
+ "EnableDebug", "Print", "Debug",
+ "InitializeDB", "RegisterDBDefaults", "ResetDB",
+ "SetProfile", "CopyProfile", "ResetProfile", "DeleteProfile",
+ "NewModule", "HasModule", "IterateModules",
+}
+
+local registry = {}
+local lookup = {}
+local loadqueue = {}
+local loadorder = {}
+local events = {}
+
+local function assert(level,condition,message)
+ if not condition then
+ error(message,level)
+ end
+end
+
+local function argcheck(value, num, ...)
+ assert(1, type(num) == "number",
+ "Bad argument #2 to 'argcheck' (number expected, got " .. type(level) .. ")")
+
+ for i=1,select("#", ...) do
+ if type(value) == select(i, ...) then return end
+ end
+
+ local types = strjoin(", ", ...)
+ local name = string.match(debugstack(), "`argcheck'.-[`<](.-)['>]") or "Unknown"
+ error(string.format("bad argument #%d to '%s' (%s expected, got %s)",
+ num, name, types, type(value)), 3)
+end
+
+local function safecall(func,...)
+ local success,err = pcall(func,...)
+ if not success then geterrorhandler(err) end
+end
+
+function Dongle:New(obj, name)
+ argcheck(obj, 2, "table", "string", "nil")
+ argcheck(name, 3, "string", "nil")
+
+ if not name and type(obj) == "string" then
+ name = obj
+ obj = {}
+ end
+
+ if registry[name] then
+ error("A Dongle with the name '"..name.."' is already registered.")
+ end
+
+ local reg = {["obj"] = obj, ["name"] = name}
+
+ registry[name] = reg
+ lookup[obj] = reg
+ lookup[name] = reg
+
+ for k,v in pairs(methods) do
+ obj[v] = self[v]
+ end
+
+ -- Add this Dongle to the end of the queue
+ table.insert(loadqueue, obj)
+ return obj,name
+end
+
+function Dongle:NewModule(obj, name)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'NewModule' from a registered Dongle.")
+ argcheck(obj, 2, "table", "string", "nil")
+ argcheck(name, 3, "string", "nil")
+
+ obj,name = Dongle:New(obj, name)
+
+ if not reg.modules then reg.modules = {} end
+ table.insert(reg.modules, name)
+ table.sort(reg.modules)
+
+ return obj,name
+end
+
+function Dongle:HasModule(name)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'HasModule' from a registered Dongle.")
+ argcheck(name, 2, "string")
+
+ return lookup[name]
+end
+
+local EMPTY_TABLE = {}
+
+function Dongle:IterateModules()
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'IterateModules' from a registered Dongle.")
+
+ return ipairs(reg.modules or EMPTY_TABLE)
+end
+
+function Dongle:ADDON_LOADED(frame, event, ...)
+ for i=1, #loadqueue do
+ local obj = loadqueue[i]
+ table.insert(loadorder, obj)
+
+ if type(obj.Initialize) == "function" then
+ safecall(obj.Initialize, obj)
+ end
+
+ if self.initialized and type(obj.Enable) == "function" then
+ safecall(obj.Enable, obj)
+ end
+ loadqueue[i] = nil
+ end
+end
+
+function Dongle:PLAYER_LOGIN()
+ self.initialized = true
+ for i,obj in ipairs(loadorder) do
+ if type(obj.Enable) == "function" then
+ safecall(obj.Enable, obj)
+ end
+ end
+end
+
+function Dongle:TriggerEvent(event, ...)
+ argcheck(event, 2, "string")
+ local eventTbl = events[event]
+ if eventTbl then
+ for obj,func in pairs(eventTbl) do
+ if type(func) == "string" then
+ if type(obj[func]) then
+ safecall(obj[func], obj, event, ...)
+ end
+ else
+ safecall(func,event,...)
+ end
+ end
+ end
+end
+
+function Dongle:OnEvent(frame, event, ...)
+ local eventTbl = events[event]
+ if eventTbl then
+ for obj,func in pairs(eventTbl) do
+ if type(func) == "string" then
+ if type(obj[func]) then
+ obj[func](obj, event, ...)
+ end
+ else
+ func(event, ...)
+ end
+ end
+ end
+end
+
+function Dongle:RegisterEvent(event, func)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'RegisterEvent' from a registered Dongle.")
+ argcheck(event, 2, "string")
+ argcheck(func, 3, "string", "function", "nil")
+
+ -- Name the method the same as the event if necessary
+ if not func then func = event end
+
+ if not events[event] then
+ events[event] = {}
+ frame:RegisterEvent(event)
+ end
+ events[event][self] = func
+end
+
+function Dongle:UnregisterEvent(event)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'UnregisterEvent' from a registered Dongle.")
+ argcheck(event, 2, "string")
+
+ if events[event] then
+ events[event][self] = nil
+ if not next(events[event]) then
+ events[event] = nil
+ frame:UnregisterEvent(event)
+ end
+ end
+end
+
+function Dongle:UnregisterAllEvents()
+ assert(3, lookup[self], "You must call 'UnregisterAllEvents' from a registered Dongle.")
+
+ for event,tbl in pairs(events) do
+ tbl[self] = nil
+ end
+end
+
+function Dongle:AdminEvents(event)
+ local method
+ if event == "PLAYER_LOGOUT" then
+ Dongle:ClearDBDefaults()
+ method = "Disable"
+ elseif event == "PLAYER_REGEN_DISABLED" then
+ method = "CombatLockdown"
+ elseif event == "PLAYER_REGEN_ENABLED" then
+ method = "CombatUnlock"
+ end
+
+ if method then
+ for k,v in pairs(registry) do
+ local obj = v.obj
+ if obj[method] then obj[method](obj) end
+ end
+ end
+end
+
+function Dongle:EnableDebug(level)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'EnableDebug' from a registered Dongle.")
+ argcheck(level, 2, "number", "nil")
+
+ reg.debugLevel = level
+end
+
+do
+ local function printHelp(obj, method, msg, ...)
+ local reg = lookup[obj]
+ assert(4, reg, "You must call '"..method.."' from a registered Dongle.")
+
+ local name = reg.name
+ local msg = string.format("|cFF33FF99%s|r: %s", name, msg)
+
+ local success,txt = pcall(string.format, msg, ...)
+ if success then
+ ChatFrame1:AddMessage(string.format(txt, ...))
+ else
+ error(string.gsub(txt, "'%?'", string.format("'%s'", method)), 3)
+ end
+ end
+
+ function Dongle:Print(msg, ...)
+ return printHelp(self, "Print", msg, ...)
+ end
+
+ function Dongle:Debug(level, msg, ...)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'Debug' from a registered Dongle.")
+ argcheck(level, 2, "number")
+
+ if reg.debugLevel and level >= reg.debugLevel then
+ printHelp(self, "Debug", msg, ...)
+ end
+ end
+end
+
+function Dongle:InitializeDB(name, defaults)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'InitializeDB' from a registered Dongle.")
+ argcheck(name, 2, "string")
+ argcheck(defaults, 3, "table", "nil")
+
+ local sv = getglobal(name)
+
+ if not sv then
+ sv = {}
+ setglobal(name, sv)
+
+ -- Lets do the initial setup
+ sv.char = {}
+ sv.faction = {}
+ sv.realm = {}
+ sv.class = {}
+ sv.global = {}
+ sv.profiles = {}
+ end
+
+ -- Initialize the specific databases
+ local char = string.format("%s of %s", UnitName("player"), GetRealmName())
+ local realm = string.format("%s", GetRealmName())
+ local class = UnitClass("player")
+ local race = select(2, UnitRace("player"))
+ local faction = UnitFactionGroup("player")
+
+ -- Initialize the containers
+ if not sv.char then sv.char = {} end
+ if not sv.realm then sv.realm = {} end
+ if not sv.class then sv.class = {} end
+ if not sv.faction then sv.faction = {} end
+ if not sv.global then sv.global = {} end
+ if not sv.profiles then sv.profiles = {} end
+
+ -- Initialize this characters profiles
+ if not sv.char[char] then sv.char[char] = {} end
+ if not sv.realm[realm] then sv.realm[realm] = {} end
+ if not sv.class[class] then sv.class[class] = {} end
+ if not sv.faction[faction] then sv.faction[faction] = {} end
+
+ -- Try to get the profile selected from the char db
+ local profileKey = sv.char[char].profileKey or char
+ sv.char[char].profileKey = profileKey
+
+ if not sv.profiles[profileKey] then sv.profiles[profileKey] = {} end
+
+ local db = {
+ ["char"] = sv.char[char],
+ ["realm"] = sv.realm[realm],
+ ["class"] = sv.class[class],
+ ["faction"] = sv.faction[faction],
+ ["profile"] = sv.profiles[profileKey],
+ ["global"] = sv.global,
+ ["profiles"] = sv.profiles,
+ }
+
+ local reg = lookup[self]
+ reg.sv = sv
+ reg.sv_name = name
+ reg.db = db
+ reg.db_char = char
+ reg.db_realm = realm
+ reg.db_class = class
+ reg.db_faction = faction
+ reg.db_profileKey = profileKey
+
+ if defaults then
+ self:RegisterDBDefaults(db, defaults)
+ end
+
+ return db
+end
+
+local function copyDefaults(dest, src)
+ for k,v in pairs(src) do
+ if type(v) == "table" then
+ if not dest[k] then dest[k] = {} end
+ copyDefaults(dest[k], v)
+ else
+ dest[k] = v
+ end
+ end
+end
+
+function Dongle:RegisterDBDefaults(db, defaults)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'RegisterDBDefaults' from a registered Dongle.")
+ argcheck(db, 2, "table")
+ argcheck(defaults, 3, "table")
+ assert(3, reg.db, "You cannot call \"RegisterDBDefaults\" before calling \"InitializeDB\".")
+
+ if defaults.char then copyDefaults(db.char, defaults.char) end
+ if defaults.realm then copyDefaults(db.realm, defaults.realm) end
+ if defaults.class then copyDefaults(db.class, defaults.class) end
+ if defaults.faction then copyDefaults(db.faction, defaults.faction) end
+ if defaults.global then copyDefaults(db.global, defaults.global) end
+ if defaults.profile then copyDefaults(db.profile, defaults.profile) end
+
+ reg.dbDefaults = defaults
+end
+
+local function removeDefaults(db, defaults)
+ if not db then return end
+ for k,v in pairs(defaults) do
+ if type(v) == "table" and db[k] then
+ removeDefaults(db[k], v)
+ if not next(db[k]) then
+ db[k] = nil
+ end
+ else
+ if db[k] == defaults[k] then
+ db[k] = nil
+ end
+ end
+ end
+end
+
+function Dongle:ClearDBDefaults()
+ for name,obj in pairs(registry) do
+ local db = obj.db
+ local defaults = obj.dbDefaults
+ local sv = obj.sv
+
+ if db and defaults then
+ if defaults.char then removeDefaults(db.char, defaults.char) end
+ if defaults.realm then removeDefaults(db.realm, defaults.realm) end
+ if defaults.class then removeDefaults(db.class, defaults.class) end
+ if defaults.faction then removeDefaults(db.faction, defaults.faction) end
+ if defaults.global then removeDefaults(db.global, defaults.global) end
+ if defaults.profile then
+ for k,v in pairs(sv.profiles) do
+ removeDefaults(sv.profiles[k], defaults.profile)
+ end
+ end
+
+ -- Remove any blank "profiles"
+ if not next(db.char) then sv.char[obj.db_char] = nil end
+ if not next(db.realm) then sv.realm[obj.db_realm] = nil end
+ if not next(db.class) then sv.class[obj.db_class] = nil end
+ if not next(db.faction) then sv.faction[obj.db_faction] = nil end
+ if not next(db.global) then sv.global = nil end
+ end
+ end
+end
+
+function Dongle:SetProfile(name)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'SetProfile' from a registered Dongle.")
+ argcheck(name, 2, "string")
+ assert(3, reg.db, "You cannot call \"SetProfile\" before calling \"InitializeDB\".")
+
+ local old = reg.sv.profiles[reg.db_profileKey]
+
+ local new = reg.sv.profiles[name]
+ if not new then
+ reg.sv.profiles[name] = {}
+ new = reg.sv.profiles[name]
+ end
+
+ if reg.dbDefaults and reg.dbDefaults.profile then
+ -- Remove the defaults from the old profile
+ removeDefaults(old, reg.dbDefaults.profile)
+
+ -- Inject the defaults into the new profile
+ copyDefaults(new, reg.dbDefaults.profile)
+ end
+
+ reg.db.profile = new
+
+ -- Save this new profile name in db.char
+ reg.db.char.profileKey = name
+
+ self:TriggerEvent("DONGLE_PROFILE_CHANGED", reg.name, name)
+end
+
+function Dongle:DeleteProfile(name)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'DeleteProfile' from a registered Dongle.")
+ argcheck(name, 2, "string")
+ assert(3, reg.db, "You cannot call \"DeleteProfile\" before calling \"InitializeDB\".")
+
+ if reg.db.char.profileKey == name then
+ error("You cannot delete your active profile. Change profiles, then attempt to delete.", 2)
+ end
+
+ reg.sv.profiles[name] = nil
+ self:TriggerEvent("DONGLE_PROFILE_DELETED", reg.name, name)
+end
+
+function Dongle:CopyProfile(name)
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'CopyProfile' from a registered Dongle.")
+ argcheck(name, 2, "string")
+ assert(3, reg.db, "You cannot call \"CopyProfile\" before calling \"InitializeDB\".")
+
+ assert(3, reg.db.char.profileKey ~= name, "Source/Destination profile cannot be the same profile")
+ assert(3, type(reg.sv.profiles[name]) == "table", "Profile \""..name.."\" doesn't exist.")
+
+ local profile = reg.db.profile
+ local source = reg.sv.profiles[name]
+
+ -- Don't do a destructive copy, just do what we're told
+ copyDefaults(profile, source)
+ self:TriggerEvent("DONGLE_PROFILE_COPIED", reg.name, name, reg.db.char.profileKey)
+end
+
+function Dongle:ResetProfile()
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'ResetProfile' from a registered Dongle.")
+ assert(3, reg.db, "You cannot call \"ResetProfile\" before calling \"InitializeDB\".")
+
+ local profile = reg.db.profile
+
+ for k,v in pairs(profile) do
+ profile[k] = nil
+ end
+ if reg.dbDefaults and reg.dbDefaults.profile then
+ copyDefaults(profile, reg.dbDefaults.profile)
+ end
+ self:TriggerEvent("DONGLE_PROFILE_RESET", reg.name, name)
+end
+
+function Dongle:ResetDB()
+ local reg = lookup[self]
+ assert(3, reg, "You must call 'ResetDB' from a registered Dongle.")
+ assert(3, reg.db, "You cannot call \"ResetDB\" before calling \"InitializeDB\".")
+
+ local sv = reg.sv
+ for k,v in pairs(sv) do
+ sv[k] = nil
+ end
+
+ local db = self:InitializeDB(reg.sv_name, reg.dbDefaults)
+ self:SetProfile(reg.db.char.profileKey)
+ self:TriggerEvent("DONGLE_DATABASE_RESET", reg.name)
+ return db
+end
+
+-- Set up a basic slash command for /dongle and /reload
+SLASH_RELOAD1 = "/reload"
+SLASH_RELOAD2 = "/rl"
+SlashCmdList["RELOAD"] = ReloadUI
+
+SLASH_DONGLE1 = "/dongle"
+
+SlashCmdList["DONGLE"] = function(msg)
+ local s,e,cmd,args = string.find(msg, "([^%s]+)%s*(.*)")
+ if not cmd then return end
+
+ cmd = string.lower(cmd)
+
+ if cmd == "enable" then
+ local name,title,notes,enabled = GetAddOnInfo(args)
+ if enabled then
+ Dongle:Print("'%s' is already enabled.", args)
+ elseif not name then
+ Dongle:Print("'%s' is not a valid addon.", args)
+ elseif args then
+ EnableAddOn(args)
+ Dongle:Print("Enabled AddOn '%s'", args)
+ end
+ elseif cmd == "disable" then
+ local name,title,notes,enabled = GetAddOnInfo(args)
+ if not name then
+ Dongle:Print("'%s' is not a valid addon.", args)
+ elseif not enabled then
+ Dongle:Print("'%s' is already disabled.", args)
+ elseif args then
+ DisableAddOn(args)
+ Dongle:Print("Disabled AddOn '%s'", args)
+ end
+ end
+end
+
+--]]
+
+--[[-------------------------------------------------------------------------
+ Begin DongleStub required functions and registration
+---------------------------------------------------------------------------]]
+
+function Dongle:GetVersion() return major,minor end
+
+function Dongle:Activate(old)
+ if old then
+ self.registry = old.registry
+ self.lookup = old.lookup
+ self.loadqueue = old.loadqueue
+ self.loadorder = old.loadorder
+ self.events = old.events
+
+ registry = self.registry
+ lookup = self.lookup
+ loadqueue = self.loadqueue
+ loadorder = self.loadorder
+ events = self.events
+
+ frame = old.frame
+ self.registry[major].obj = self
+ else
+ self.registry = registry
+ self.lookup = lookup
+ self.loadqueue = loadqueue
+ self.loadorder = loadorder
+ self.events = events
+
+ local reg = {obj = self, name = "Dongle"}
+ registry[major] = reg
+ lookup[self] = reg
+ lookup[major] = reg
+ end
+
+ if not frame then
+ frame = CreateFrame("Frame")
+ end
+
+ self.frame = frame
+ frame:SetScript("OnEvent", function(...) self:OnEvent(...) end)
+
+ -- Register for events using Dongle itself
+ self:RegisterEvent("ADDON_LOADED")
+ self:RegisterEvent("PLAYER_LOGIN")
+ self:RegisterEvent("PLAYER_LOGOUT", "AdminEvents")
+ self:RegisterEvent("PLAYER_REGEN_ENABLED", "AdminEvents")
+ self:RegisterEvent("PLAYER_REGEN_DISABLED", "AdminEvents")
+
+ -- Convert all the modules handles
+ for name,obj in pairs(registry) do
+ for k,v in ipairs(methods) do
+ obj[k] = self[v]
+ end
+ end
+end
+
+function Dongle:Deactivate(new)
+ lookup[self] = nil
+ self:UnregisterAllEvents()
+end
+
+DongleStub:Register(Dongle)
diff --git a/images/RadioChecked.tga b/images/RadioChecked.tga
new file mode 100644
index 0000000..2895d73
Binary files /dev/null and b/images/RadioChecked.tga differ
diff --git a/images/RadioEmpty.tga b/images/RadioEmpty.tga
new file mode 100644
index 0000000..1fba516
Binary files /dev/null and b/images/RadioEmpty.tga differ
diff --git a/images/myborder.tga b/images/myborder.tga
new file mode 100644
index 0000000..700c1ba
Binary files /dev/null and b/images/myborder.tga differ