init
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
<Bindings>
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
|
||||
|
||||
<Binding name="DCRSHOW" header="DECURSIVE">
|
||||
Dcr:HideBar(false);
|
||||
</Binding>
|
||||
<Binding name="DCRMUFSHOWHIDE">
|
||||
Dcr:ShowHideDebuffsFrame ();
|
||||
</Binding>
|
||||
<Binding name="DCRSHOWOPTION">
|
||||
Dcr.Waterfall:Open("Decursive");
|
||||
</Binding>
|
||||
<Binding name="DCRPRSHOW">
|
||||
Dcr:ShowHidePriorityListUI();
|
||||
</Binding>
|
||||
<Binding name="DCRPRADD">
|
||||
Dcr:AddTargetToPriorityList();
|
||||
</Binding>
|
||||
<Binding name="DCRPRCLEAR">
|
||||
Dcr:ClearPriorityList();
|
||||
</Binding>
|
||||
<!--<Binding name="DCRPRLIST">
|
||||
Dcr:PrintPriorityList();
|
||||
</Binding>-->
|
||||
<Binding name="DCRSKSHOW">
|
||||
Dcr:ShowHideSkipListUI();
|
||||
</Binding>
|
||||
<Binding name="DCRSKADD">
|
||||
Dcr:AddTargetToSkipList();
|
||||
</Binding>
|
||||
<Binding name="DCRSKCLEAR">
|
||||
Dcr:ClearSkipList();
|
||||
</Binding>
|
||||
<!--<Binding name="DCRSKLIST">
|
||||
Dcr:PrintSkipList();
|
||||
</Binding>-->
|
||||
</Bindings>
|
||||
@@ -0,0 +1,9 @@
|
||||
Archarodim:
|
||||
- - Added X-Max-Interface and X-Min-Interface to toc
|
||||
- - fix "Dcr_lists.lua:140: attempt to index local 'frame' (a nil value)" introduced in b03f6b93f98
|
||||
- - Added Fear (rank 1) for Warlocks to use on charmed units
|
||||
- WoW 4.0: Added support for 'Singe Magic' imp spell for Warlocks and changed 'Devour Magic' to 'enemy magic' only.
|
||||
- WoW 4.0: Removed rank for Polymorph
|
||||
- - fixed changelog in .pkgmeta
|
||||
- - Fix missing spell reporting in WoW 4.0
|
||||
- WoW 4.0 basic compatibility (this --> self, etc...)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,430 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
local addonName, T = ...;
|
||||
DecursiveRootTable = T;
|
||||
|
||||
DecursiveInstallCorrupted = false;
|
||||
|
||||
DcrC = {}; -- needed until we get rid of the xml based UI.
|
||||
T._C = DcrC;
|
||||
local DC = DcrC;
|
||||
|
||||
DC.StartTime = GetTime();
|
||||
DC.MyClass = "unknown";
|
||||
|
||||
T._LoadedFiles = {
|
||||
["Dcr_DIAG.xml"] = false,
|
||||
["Dcr_DIAG.lua"] = false,
|
||||
["DCR_init.lua"] = false,
|
||||
["Dcr_LDB.lua"] = false,
|
||||
["Dcr_utils.lua"] = false,
|
||||
|
||||
["enUS.lua"] = false,
|
||||
["frFR.lua"] = false,
|
||||
["deDE.lua"] = false,
|
||||
["zhTW.lua"] = false,
|
||||
["esES.lua"] = false,
|
||||
["koKR.lua"] = false,
|
||||
["zhCN.lua"] = false,
|
||||
["ruRU.lua"] = false,
|
||||
|
||||
["Dcr_opt.lua"] = false,
|
||||
["Dcr_Events.lua"] = false,
|
||||
["Dcr_Raid.lua"] = false,
|
||||
["Decursive.lua"] = false,
|
||||
["Dcr_lists.lua"] = false,
|
||||
["Dcr_DebuffsFrame.lua"] = false,
|
||||
["Dcr_LiveList.lua"] = false,
|
||||
|
||||
["Dcr_DebuffsFrame.xml"] = false,
|
||||
["Dcr_lists.xml"] = false,
|
||||
["Dcr_LiveList.xml"] = false,
|
||||
["Decursive.xml"] = false,
|
||||
|
||||
};
|
||||
|
||||
-- This self diagnostic functionality is here to give clear instructions to the
|
||||
-- user when something goes wrong with the Ace shared libraries or when a
|
||||
-- Decursive file could not be loaded.
|
||||
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = false,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
|
||||
-- Decursive LUA error manager and debug reporting functions {{{
|
||||
|
||||
local function NiceTime()
|
||||
return tonumber(("%.4f"):format(GetTime() - DC.StartTime));
|
||||
end
|
||||
|
||||
local function print(t)
|
||||
if DEFAULT_CHAT_FRAME then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(t);
|
||||
end
|
||||
end
|
||||
|
||||
-- taken from AceConsole-2.0
|
||||
local function tostring_args(a1, ...)
|
||||
if select('#', ...) < 1 then
|
||||
return tostring(a1)
|
||||
end
|
||||
return tostring(a1), tostring_args(...)
|
||||
end
|
||||
|
||||
T._DebugText = "";
|
||||
-- inspired from BugSack
|
||||
function T._DebugFrameOnTextChanged(frame)
|
||||
if frame:GetText() ~= T._DebugText then
|
||||
frame:SetText(T._DebugText)
|
||||
end
|
||||
frame:GetParent():UpdateScrollChildRect()
|
||||
local _, m = DecursiveDebuggingFrameScrollScrollBar:GetMinMaxValues()
|
||||
if m > 0 and frame.max ~= m then
|
||||
frame.max = m
|
||||
DecursiveDebuggingFrameScrollScrollBar:SetValue(0)
|
||||
end
|
||||
end
|
||||
|
||||
T._DebugTextTable = {};
|
||||
local DebugTextTable = T._DebugTextTable;
|
||||
local Reported = {};
|
||||
local GetFramerate = _G.GetFramerate;
|
||||
local GetNetStats = _G.GetNetStats;
|
||||
function T._AddDebugText(a1, ...)
|
||||
|
||||
if T.Dcr.Debug then
|
||||
T.Dcr:Debug("Error processed");
|
||||
end
|
||||
local text = "";
|
||||
|
||||
if select('#', ...) > 0 then
|
||||
text = strjoin(", ", tostring_args(a1, ...))
|
||||
else
|
||||
text = tostring(a1);
|
||||
end
|
||||
|
||||
if not Reported[text] then
|
||||
table.insert (DebugTextTable, ("\n------\n%.4f (%d-%d): %s -|count: "):format(NiceTime(), select(3, GetNetStats()), GetFramerate(), text) );
|
||||
table.insert (DebugTextTable, 1);
|
||||
Reported[text] = #DebugTextTable;
|
||||
else
|
||||
DebugTextTable[Reported[text]] = DebugTextTable[Reported[text]] + 1;
|
||||
end
|
||||
end
|
||||
|
||||
local AddDebugText = T._AddDebugText;
|
||||
|
||||
-- The error handler
|
||||
local ProperErrorHandler = false;
|
||||
local IsReporting = false;
|
||||
|
||||
local version, build, date, tocversion = GetBuildInfo();
|
||||
|
||||
T._CatchAllErrors = false;
|
||||
T._tocversion = tocversion;
|
||||
|
||||
function T._DecursiveErrorHandler(err, ...)
|
||||
|
||||
-- second blizzard bug HotFix
|
||||
---[=[
|
||||
if ScriptErrorsFrameScrollFrameText then
|
||||
if not ScriptErrorsFrameScrollFrameText.cursorOffset then
|
||||
ScriptErrorsFrameScrollFrameText.cursorOffset = 0;
|
||||
if ( GetCVarBool("scriptErrors") ) then
|
||||
print("Decursive |cFF00FF00HotFix to Blizzard_DebugTools:|r |cFFFF0000ScriptErrorsFrameScrollFrameText.cursorOffset was nil (check for Lua errors using BugGrabber and BugSack)|r");
|
||||
end
|
||||
end
|
||||
end
|
||||
--]=]
|
||||
|
||||
err = tostring(err);
|
||||
|
||||
--Add a check to see if the error is happening inside the Blizzard debug tool himself...
|
||||
if (err:lower()):find("blizzard_debugtools") then
|
||||
if ( GetCVarBool("scriptErrors") ) then
|
||||
print (("|cFFFF0000%s|r"):format(err));
|
||||
end
|
||||
return;
|
||||
end
|
||||
|
||||
if not IsReporting and (T._CatchAllErrors or (err:lower()):find("decursive") and not (err:lower()):find("\\libs\\")) then
|
||||
T._CatchAllErrors = false; -- Errors are unacceptable so one is enough, no need to get all subsequent errors.
|
||||
IsReporting = true;
|
||||
AddDebugText(err, debugstack(2), ...);
|
||||
if T.Dcr then
|
||||
T.Dcr:Debug("Error recorded");
|
||||
end
|
||||
IsReporting = false;
|
||||
end
|
||||
|
||||
if ProperErrorHandler then
|
||||
return ProperErrorHandler( err, ... ); -- returning this way prevents this function from appearing in the stack
|
||||
end
|
||||
end
|
||||
|
||||
function T._HookErrorHandler()
|
||||
if not ProperErrorHandler then
|
||||
|
||||
---[=[
|
||||
-- seems to be required even in 3.3 because debuglocals, unlike debugstack is sensitive to intermediates so we need to add 1 to its level for each intermediate
|
||||
if GetCVarBool("scriptErrors") and not BugGrabber then
|
||||
-- this whole block is a bad idea, it could create cascading tainting issues if an error occur in a Blizz secured code...
|
||||
-- it is enabled only if the user turned Lua error reporting on otherwise no one cares about debuglocals being useless.
|
||||
T._original_debuglocals = _G.debuglocals;
|
||||
_G.debuglocals = function (level)
|
||||
local ADDLEVEL = 2; -- 2 is for this function and _DecursiveErrorHandler
|
||||
|
||||
-- test for other add-on that hooks the error handler and increment ADDLEVEL
|
||||
if QuestHelper_Errors then
|
||||
ADDLEVEL = ADDLEVEL + 1;
|
||||
end
|
||||
|
||||
if Swatter and Swatter.OnError then
|
||||
ADDLEVEL = ADDLEVEL + 1;
|
||||
end
|
||||
|
||||
|
||||
return T._original_debuglocals(level + ADDLEVEL) or "Sometimes debuglocals() returns nothing, it's one of those times... (FYI: This last sentence (only) is a HotFix from Decursive to prevent a C stack overflow in the new Blizzard error handler and thus giving you the opportunity to send this debug report to the author of the problematic add-on so he/she can fix it)";
|
||||
end;
|
||||
end
|
||||
--]=]
|
||||
|
||||
|
||||
ProperErrorHandler = geterrorhandler();
|
||||
seterrorhandler(T._DecursiveErrorHandler);
|
||||
end
|
||||
end
|
||||
|
||||
--}}}
|
||||
|
||||
|
||||
-- Dev version usage warning {{{
|
||||
-- the beautiful beta notice popup : {{{ -
|
||||
StaticPopupDialogs["Decursive_Notice_Frame"] = {
|
||||
text = "|cFFFF0000Decursive Notice:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = false,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
do
|
||||
T._DiagStatus = false;
|
||||
|
||||
local PrintMessage = function (message, ...) if T._DiagStatus ~= 2 then T.Dcr:Print("|cFFFFAA55Self diagnostic:|r ", format(message, ...)); end end;
|
||||
|
||||
-- {{{
|
||||
function T._SelfDiagnostic (force, FromCommand)
|
||||
|
||||
-- will not executes several times unless forced
|
||||
if not force and T._DiagStatus then
|
||||
return T._DiagStatus;
|
||||
end
|
||||
|
||||
T._DiagStatus = 0; -- will be set to 1 if the diagnostic fails
|
||||
|
||||
-- Table with all the required libraries with their current revision at Decursive release time.
|
||||
|
||||
--LibStub:GetLibrary
|
||||
local UseLibStub = {
|
||||
["AceAddon-3.0"] = 5,
|
||||
["AceConsole-3.0"] = 7,
|
||||
["AceEvent-3.0"] = 3,
|
||||
["AceTimer-3.0"] = 5,
|
||||
["AceHook-3.0"] = 5,
|
||||
["AceDB-3.0"] = 21,
|
||||
["AceDBOptions-3.0"] = 12,
|
||||
["AceLocale-3.0"] = 2,
|
||||
["AceComm-3.0"] = 6,
|
||||
|
||||
["AceGUI-3.0"] = 33,
|
||||
["AceConfig-3.0"] = 2,
|
||||
["AceConfigRegistry-3.0"] = 12,
|
||||
["AceConfigCmd-3.0"] = 12,
|
||||
["AceConfigDialog-3.0"] = 49,
|
||||
|
||||
["LibDataBroker-1.1"] = 4,
|
||||
["LibDBIcon-1.0"] = 14,
|
||||
["LibQTip-1.0"] = 34,
|
||||
["CallbackHandler-1.0"] = 5,
|
||||
};
|
||||
|
||||
local GenericErrorMessage1 = "Decursive could not initialize properly because one or several of the required shared libraries (at least |cFF00FF00AceLibrary or LibStub|r) could not be found.\n";
|
||||
local GenericErrorMessage2 = "Try to re-install Decursive from its original archive or use the |cFF00FF00Curse client|r (Curse.com) to update |cFFFF0000ALL|r your add-ons properly.";
|
||||
|
||||
local ErrorFound = false;
|
||||
local Errors = {};
|
||||
local FatalOccured = false;
|
||||
|
||||
-- Check each version of the required libraries that use LibStub
|
||||
if LibStub then
|
||||
for k,v in pairs(UseLibStub) do
|
||||
if LibStub:GetLibrary(k, true) then
|
||||
if (select(2, LibStub:GetLibrary(k))) < v then
|
||||
table.insert(Errors, ("The shared library |cFF00FF00%s|r is out-dated, revision |cFF0077FF%s|r at least is required.\n"):format(k, tostring(v)));
|
||||
end
|
||||
else
|
||||
table.insert(Errors, ("The shared library |cFF00FF00%s|r could not be found!!!\n"):format(k));
|
||||
FatalOccured = true;
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(Errors, GenericErrorMessage1);
|
||||
FatalOccured = true;
|
||||
end
|
||||
|
||||
|
||||
-- check if all Decursive files are loaded
|
||||
local mixedFileVersionsdetection = {};
|
||||
local MixedVersionsCount = 0;
|
||||
if not FatalOccured then
|
||||
for k,v in pairs (T._LoadedFiles) do
|
||||
if v and v ~= "@pro" .. "ject-version@" and not mixedFileVersionsdetection[v] then
|
||||
mixedFileVersionsdetection[v] = k;
|
||||
MixedVersionsCount = MixedVersionsCount + 1;
|
||||
end
|
||||
|
||||
if not v then
|
||||
table.insert(Errors, ("The Decursive file |cFF00FF00%s|r could not be loaded!\n"):format(k));
|
||||
FatalOccured = true;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if MixedVersionsCount > 1 then
|
||||
-- some mixed files were detected
|
||||
local MixedDetails = "|cFFFF5599The versions of these files differ|r:\n\n";
|
||||
for k,v in pairs (mixedFileVersionsdetection) do
|
||||
MixedDetails = ("%s%s --> %s\n"):format(MixedDetails, v, k);
|
||||
end
|
||||
|
||||
table.insert(Errors, ("Decursive installation is corrupted, mixed versions detected!\n\n%s\n"):format(MixedDetails));
|
||||
FatalOccured = true;
|
||||
end
|
||||
|
||||
if #Errors > 0 then
|
||||
local ErrorString = ("|cFFFF0000%d error(s)|r found while loading Decursive:\n\n"):format(#Errors);
|
||||
|
||||
for k, v in pairs (Errors) do
|
||||
ErrorString = ErrorString .. v;
|
||||
end
|
||||
|
||||
ErrorString = ErrorString .. "\n\n" .. GenericErrorMessage2;
|
||||
|
||||
T._FatalError(ErrorString);
|
||||
T._DiagStatus = FatalOccured and 2 or 1;
|
||||
end
|
||||
|
||||
-- if the diagnostic was requested by the user, we also test AceEvent functionalities {{{ -
|
||||
if force and FromCommand and T._DiagStatus == 0 then
|
||||
|
||||
PrintMessage("|cFF00FF00No problem found in shared libraries or Decursive files!|r");
|
||||
|
||||
PrintMessage("Now checking spell translations...");
|
||||
if T.Dcr:GetSpellsTranslations(true) then
|
||||
PrintMessage("|cFF00FF00No error found in spell translations!|r");
|
||||
end
|
||||
|
||||
AddDebugText("Now checking the event management library...");
|
||||
PrintMessage("Now checking the event management library...");
|
||||
PrintMessage("If, in about 2 seconds, the message \"|cFF00FF00Event library functionning properly|r\" does not appear then there is a problem");
|
||||
|
||||
local OneTimeEvent = "not set"; local ReapeatingEventRate = 1; local ReapeatingEventCount = 0; local CustomEvent = "DCR_TEST_DIAG_EVENT"; local CustomEventCaught = "not set";
|
||||
local ConfirmOneTimeEventMessage = "That was a good time!";
|
||||
local ConfirmCustomEventMessage = "I was really caught!";
|
||||
|
||||
-- Register a curstom event
|
||||
T.Dcr:RegisterMessage(CustomEvent, function(message, DiagTestArg1) CustomEventCaught = DiagTestArg1; T.Dcr:Debug("CustomEvent callback executed"); end);
|
||||
|
||||
-- Schedule a function call in 0.5s
|
||||
T.Dcr:ScheduleDelayedCall("DcrDiagOneTimeEvent", function(DiagTestArg2) OneTimeEvent = DiagTestArg2; T.Dcr:Debug("OneTimeEvent callback executed"); end, ReapeatingEventRate / 2, ConfirmOneTimeEventMessage);
|
||||
|
||||
-- Set a repeating function call that will check for other test event completion
|
||||
T.Dcr:ScheduleRepeatedCall("DcrDiagRepeat",
|
||||
function (argTest)
|
||||
local argtestdone = false;
|
||||
if not argtestdone and argTest ~= "test" then
|
||||
AddDebugText("Event lib management error: argument could not be read!");
|
||||
PrintMessage("|cFFFF0000Event lib management error: argument could not be read!|r");
|
||||
argtestdone = true;
|
||||
end
|
||||
|
||||
if OneTimeEvent == ConfirmOneTimeEventMessage and CustomEventCaught == ConfirmCustomEventMessage then
|
||||
T.Dcr:CancelDelayedCall("DcrDiagRepeat");
|
||||
T.Dcr:UnregisterMessage(CustomEvent);
|
||||
PrintMessage("|cFF00FF00Event library functionning properly!|r");
|
||||
PrintMessage("|cFF00FF00Everything seems to be OK.|r");
|
||||
AddDebugText("Event library functionning properly, Everything seems to be OK");
|
||||
return;
|
||||
else
|
||||
T.Dcr:Debug(OneTimeEvent, "is not", ConfirmOneTimeEventMessage, "and", CustomEventCaught, "is not", ConfirmCustomEventMessage);
|
||||
end
|
||||
|
||||
-- cast the custom event
|
||||
T.Dcr:SendMessage(CustomEvent, ConfirmCustomEventMessage);
|
||||
|
||||
if ReapeatingEventCount == 4 then
|
||||
AddDebugText("A problem occured, OneTimeEvent:", OneTimeEvent, "CustomEventCaught:", CustomEventCaught);
|
||||
PrintMessage("|cFFFF0000A problem occured, OneTimeEvent='%q', CustomEventCaught='%q'|r", OneTimeEvent, CustomEventCaught);
|
||||
T.Dcr:CancelDelayedCall("DcrDiagRepeat");
|
||||
T.Dcr:UnregisterMessage(CustomEvent);
|
||||
return;
|
||||
end
|
||||
|
||||
ReapeatingEventCount = ReapeatingEventCount + 1;
|
||||
|
||||
end,
|
||||
ReapeatingEventRate, "test");
|
||||
|
||||
end -- }}}
|
||||
|
||||
if T._DiagStatus == 0 then
|
||||
DecursiveInstallCorrupted = nil;
|
||||
end
|
||||
|
||||
return T._DiagStatus;
|
||||
|
||||
|
||||
end -- }}}
|
||||
end
|
||||
|
||||
|
||||
T._LoadedFiles["Dcr_DIAG.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,138 @@
|
||||
<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/">
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
|
||||
<Script>
|
||||
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
|
||||
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_DIAG.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_DIAG.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
</Script>
|
||||
|
||||
<!-- =================The DEBUGGING FRAME======================= {{{ -->
|
||||
<!-- Inspired from BugSack error report frame-->
|
||||
|
||||
<Frame name="DecursiveDebuggingFrame" parent="UIParent" inherits="DialogBoxFrame" hidden="true">
|
||||
<Backdrop name="$parentBackdrop" bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
</Backdrop>
|
||||
<Size>
|
||||
<AbsDimension x="500" y="400"/>
|
||||
</Size>
|
||||
<Layers>
|
||||
<Layer level="ARTWORK">
|
||||
<FontString name="DecursiveDEBUGtext" inherits="GameFontHighlight">
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset> <AbsDimension x="5" y="-5" /> </Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<ScrollFrame name="DecursiveDebuggingFrameScroll" inherits="UIPanelScrollFrameTemplate" toplevel="true">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="DecursiveDEBUGtext">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-10"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="BOTTOM" relativePoint="TOP" relativeTo="DecursiveDebuggingFrameButton">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="10"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="RIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-30" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<ScrollChild>
|
||||
<EditBox name="DecursiveDebuggingFrameText" letters="99999" multiLine="true" autoFocus="true" enableMouse="true" >
|
||||
<Size>
|
||||
<AbsDimension x="450" y="314"/>
|
||||
</Size>
|
||||
<FontString inherits="ChatFontNormal"/>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
self:SetAutoFocus(false)
|
||||
</OnLoad>
|
||||
<OnShow>
|
||||
self:SetFocus()
|
||||
</OnShow>
|
||||
<OnTextChanged>
|
||||
DecursiveRootTable._DebugFrameOnTextChanged(self)
|
||||
</OnTextChanged>
|
||||
<OnEscapePressed>
|
||||
self:ClearFocus()
|
||||
</OnEscapePressed>
|
||||
</Scripts>
|
||||
</EditBox>
|
||||
</ScrollChild>
|
||||
</ScrollFrame>
|
||||
</Frames>
|
||||
</Frame>
|
||||
|
||||
<!-- ================================================================== }}} -->
|
||||
|
||||
<Script>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
T._LoadedFiles["Dcr_DIAG.xml"] = "2.5.1-6-gd3885c5";
|
||||
</Script>
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
<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/">
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
<Script>
|
||||
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_DebuffsFrame.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_DebuffsFrame.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
-- Dcr:SetDateAndRevision("$Date: 2008-04-10 00:53:55 +0200 (jeu., 10 avr. 2008) $", "$Revision: 68827 $");
|
||||
</Script>
|
||||
|
||||
<Frame name="DcrMUFsContainer" clampedToScreen="true" frameStrata="MEDIUM" toplevel="true" enableMouse="true" movable="true" hidden="true" parent="UIParent">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" relativePoint="CENTER">
|
||||
<Offset>
|
||||
<AbsDimension x="200" y="250"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
self.UpdateYourself = true;
|
||||
self.MaxUnit = 5;
|
||||
self.UnitShown = 0;
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
<Frames>
|
||||
<Button name="$parentDragButton">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMLEFT" relativePoint="TOPLEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD" />
|
||||
<!--<HighlightTexture file="Interface\Buttons\ButtonHilight-Square" alphaMode="ADD" /> -->
|
||||
<!--<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD"/> -->
|
||||
|
||||
<Scripts>
|
||||
<OnMouseUp>
|
||||
if ( self.isMoving ) then
|
||||
self:GetParent():StopMovingOrSizing();
|
||||
self.isMoving = false;
|
||||
Dcr.MicroUnitF.DraggingHandle = false;
|
||||
Dcr.MicroUnitF:SavePos();
|
||||
Dcr.MicroUnitF:Place();
|
||||
Dcr.MicroUnitF:SavePos();
|
||||
elseif Dcr.Status.MouseOveringCorner then
|
||||
Dcr:QuickAccess(self, button);
|
||||
end
|
||||
</OnMouseUp>
|
||||
<OnMouseDown>
|
||||
if ( button == "LeftButton" and IsAltKeyDown() ) then
|
||||
self.isMoving = true;
|
||||
Dcr.MicroUnitF.DraggingHandle = true;
|
||||
self:GetParent():StartMoving();
|
||||
end
|
||||
</OnMouseDown>
|
||||
|
||||
<OnHide>
|
||||
if ( self.isMoving ) then
|
||||
self:GetParent():StopMovingOrSizing();
|
||||
self.isMoving = false;
|
||||
Dcr.MicroUnitF.DraggingHandle = false;
|
||||
end
|
||||
</OnHide>
|
||||
<OnEnter>
|
||||
Dcr.Status.MouseOveringCorner = true;
|
||||
Dcr.MicroUnitF:OnCornerEnter(self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
Dcr.Status.MouseOveringCorner = false;
|
||||
|
||||
if (Dcr.profile.DebuffsFrameShowHelp) then
|
||||
GameTooltip:Hide();
|
||||
end;
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
</Frames>
|
||||
</Frame>
|
||||
|
||||
<!-- Templates -->
|
||||
<Cooldown name="DcrMicroUnitCDTemplate" virtual="true" hidden="true" setAllPoints="false">
|
||||
<Size>
|
||||
<AbsDimension x="16" y="16"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" relativePoint="CENTER">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Cooldown>
|
||||
|
||||
<Button name="DcrMicroUnitTemplateSecure" inherits="SecureUnitButtonTemplate" virtual="true" hidden="true">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20"/>
|
||||
</Size>
|
||||
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
Dcr.MicroUnitF:OnLoad(self);
|
||||
</OnLoad>
|
||||
<OnEnter>
|
||||
Dcr.MicroUnitF:OnEnter(self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
Dcr.MicroUnitF:OnLeave();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
|
||||
<FontString name="DcrMicroUnitChronoFont" inherits="NumberFontNormalSmall" maxLines="1" text="" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" relativePoint="CENTER" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="1" y="-2"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Color r="0.5" g="0.1" b="0.2" a="0.6"/>
|
||||
<Shadow>
|
||||
<offset>
|
||||
<AbsDimension x="1" y="-1" />
|
||||
</offset>
|
||||
<color r="0" g="0" b="0" />
|
||||
</Shadow>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
|
||||
<Script>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
T._LoadedFiles["Dcr_DebuffsFrame.xml"] = "2.5.1-6-gd3885c5";
|
||||
</Script>
|
||||
</Ui>
|
||||
@@ -0,0 +1,834 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_opt.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_opt.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-09-16 00:25:13 +0200 (mar., 16 sept. 2008) $", "$Revision: 81755 $");
|
||||
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
|
||||
D.DebuffUpdateRequest = 0;
|
||||
|
||||
--@alpha@
|
||||
D.DetectHistory = {};
|
||||
--@end-alpha@
|
||||
|
||||
local pairs = _G.pairs;
|
||||
local next = _G.next;
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local unpack = _G.unpack;
|
||||
local select = _G.select;
|
||||
local table = _G.table;
|
||||
local UnitCreatureFamily = _G.UnitCreatureFamily;
|
||||
local InCombatLockdown = _G.InCombatLockdown;
|
||||
local PlaySoundFile = _G.PlaySoundFile;
|
||||
local UnitExists = _G.UnitExists;
|
||||
local UnitCanAttack = _G.UnitCanAttack;
|
||||
local UnitName = _G.UnitName;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local GetTime = _G.GetTime;
|
||||
|
||||
|
||||
function D:GroupChanged (reason) -- {{{
|
||||
-- this will trigger an update of the unit array
|
||||
self.Groups_datas_are_invalid = true;
|
||||
self.Status.GroupUpdateEvent = self:NiceTime();
|
||||
|
||||
if self.profile.ShowDebuffsFrame then
|
||||
-- Update the MUFs display in a short moment
|
||||
self.MicroUnitF:Delayed_MFsDisplay_Update ();
|
||||
elseif not self.profile.Hide_LiveList then
|
||||
D:ScheduleDelayedCall("Dcr_GetUnitArray", self.GetUnitArray, 1.5, self);
|
||||
end
|
||||
|
||||
|
||||
-- Test if we have to hide Decursive MUF window
|
||||
if self.profile.AutoHideDebuffsFrame ~= 0 then
|
||||
self:ScheduleDelayedCall("Dcr_CheckIfHideShow", self.AutoHideShowMUFs, 2, self);
|
||||
end
|
||||
|
||||
self:Debug("Groups changed", reason);
|
||||
end -- }}}
|
||||
|
||||
local OncePetRetry = false;
|
||||
|
||||
function D:UNIT_PET (selfevent, Unit) -- {{{
|
||||
|
||||
-- when a pet changes somwhere, we update the unit array.
|
||||
|
||||
D:Debug("Pet changed for: ", Unit);
|
||||
if (D.profile.Scan_Pets and Unit ~= "focus" and self.Status.Unit_Array_UnitToGUID[Unit]) then
|
||||
D:GroupChanged ("UNIT_PET");
|
||||
end
|
||||
|
||||
|
||||
-- If the player's pet changed then we should check it for interesting spells
|
||||
if ( Unit == "player" ) then
|
||||
self:ScheduleDelayedCall("Dcr_CheckPet", self.UpdatePlayerPet, 2, self);
|
||||
OncePetRetry = false;
|
||||
D:Debug ("PLAYER pet detected! Poll in 2 seconds...");
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
local curr_petType = false;
|
||||
local last_petType = false;
|
||||
|
||||
function D:UpdatePlayerPet () -- {{{
|
||||
curr_petType = UnitCreatureFamily("pet");
|
||||
D:Debug("|cFF0000FFCurrent Pet type is",curr_petType,"|r");
|
||||
|
||||
-- if we had a pet and lost it, retry once later...
|
||||
if (last_petType and not curr_petType and not OncePetRetry) then
|
||||
OncePetRetry = true;
|
||||
|
||||
D:Debug("|cFF9900FFPet lost, retry in 10 seconds|r");
|
||||
D:ScheduleDelayedCall("Dcr_ReCheckPetOnce", D.UpdatePlayerPet, 10, self);
|
||||
return;
|
||||
end
|
||||
|
||||
-- if we've changed of pet
|
||||
if (last_petType ~= curr_petType) then
|
||||
if (curr_petType) then D:Debug ("|cFF0066FFPet name changed:",curr_petType,"|r"); else D:Debug ("|cFF0066FFNo more pet!|r"); end; -- debug info only
|
||||
|
||||
last_petType = curr_petType;
|
||||
D:Configure();
|
||||
else
|
||||
D:Debug ("|cFFAA66FFNo change in Pet Type",curr_petType,"|r");
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
|
||||
|
||||
local FocusPrevious_ElligStatus = false;
|
||||
function D:PLAYER_FOCUS_CHANGED () -- {{{
|
||||
|
||||
-- we need to rescan if the focus is not in our group and it's nice or if we already have a focus unit registered
|
||||
|
||||
local FocusCurrent_ElligStatus = (
|
||||
not self.Status.Unit_Array_GUIDToUnit[UnitGUID("focus")] -- it's not already in the unit array
|
||||
) and ( UnitExists("focus") and (not UnitCanAttack("focus", "player") or UnitIsFriend("focus", "player"))) -- and it is (or used to) be nice
|
||||
|
||||
|
||||
if not FocusCurrent_ElligStatus then FocusCurrent_ElligStatus = false; end -- avoid the difference between nil and false...
|
||||
|
||||
if FocusCurrent_ElligStatus~=FocusPrevious_ElligStatus or self.Status.Unit_Array_UnitToGUID["focus"] then
|
||||
self:GroupChanged ("FOCUS changed");
|
||||
self:Debug("Groups set to invalid due to focus update", FocusPrevious_ElligStatus, FocusCurrent_ElligStatus);
|
||||
|
||||
self.MicroUnitF:UpdateMUFUnit("focus", true); -- update the focus unit
|
||||
|
||||
if FocusCurrent_ElligStatus~=FocusPrevious_ElligStatus then -- if the focus is no longer valid, we need to update things
|
||||
self.MicroUnitF:Delayed_MFsDisplay_Update();
|
||||
end
|
||||
|
||||
FocusPrevious_ElligStatus = FocusCurrent_ElligStatus;
|
||||
|
||||
end
|
||||
|
||||
|
||||
end -- }}}
|
||||
|
||||
function D:OnDebugEnable ()
|
||||
self.db.global.debugging = true;
|
||||
end
|
||||
|
||||
function D:OnDebugDisable ()
|
||||
self.db.global.debugging = false;
|
||||
end
|
||||
|
||||
-- This function update Decursive states :
|
||||
-- - Clear the black list
|
||||
-- - Execute things we couldn't do when in combat
|
||||
local LastScanAllTime = 0;
|
||||
D.Status.MaxConcurentUpdateDebuff = 0;
|
||||
function D:ScheduledTasks() -- {{{
|
||||
|
||||
-- clean up the blacklist
|
||||
for unit in pairs(self.Status.Blacklisted_Array) do
|
||||
self.Status.Blacklisted_Array[unit] = self.Status.Blacklisted_Array[unit] - 0.1;
|
||||
if (self.Status.Blacklisted_Array[unit] < 0) then
|
||||
self.Status.Blacklisted_Array[unit] = nil; -- remove it from the BL
|
||||
end
|
||||
end
|
||||
|
||||
if (self.Status.Combat and not InCombatLockdown()) then -- just in case...
|
||||
D:LeaveCombat();
|
||||
end
|
||||
|
||||
if (not InCombatLockdown() and self.Status.DelayedFunctionCallsCount > 0) then
|
||||
for Id, FuncAndArgs in pairs (self.Status.DelayedFunctionCalls) do
|
||||
D:Debug("Running post combat command", Id);
|
||||
local DidSmth = FuncAndArgs.func(unpack(FuncAndArgs.args));
|
||||
self.Status.DelayedFunctionCalls[Id] = nil; -- remove it from the list
|
||||
self.Status.DelayedFunctionCallsCount = self.Status.DelayedFunctionCallsCount - 1;
|
||||
if (DidSmth) then
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if D.DebuffUpdateRequest > D.Status.MaxConcurentUpdateDebuff then
|
||||
D.Status.MaxConcurentUpdateDebuff = D.DebuffUpdateRequest;
|
||||
end
|
||||
|
||||
-- Rescan all only if the MUF are used else we don't care at all...
|
||||
if self.profile.ShowDebuffsFrame and GetTime() - LastScanAllTime > 1 then
|
||||
self:ScanEveryBody();
|
||||
LastScanAllTime = GetTime();
|
||||
end
|
||||
|
||||
D.DebuffUpdateRequest = 0;
|
||||
|
||||
end --}}}
|
||||
|
||||
-- the combat functions and events. // {{{
|
||||
-------------------------------------------------------------------------------
|
||||
function D:EnterCombat() -- called on PLAYER_REGEN_DISABLED {{{
|
||||
-- this is not reliable for testing unitframe modifications authorization,
|
||||
-- this event fires after the player enters in combat, only InCombatLockdown() may be used for critical checks
|
||||
self.Status.Combat = true;
|
||||
end --}}}
|
||||
|
||||
local LastDebugReportNotification = 0;
|
||||
function D:LeaveCombat() --{{{
|
||||
--D:Debug("Leaving combat");
|
||||
self.Status.Combat = false;
|
||||
|
||||
-- test for debug report
|
||||
if #T._DebugTextTable > 0 and GetTime() - LastDebugReportNotification > 300 then
|
||||
if LastDebugReportNotification == 0 then
|
||||
T._FatalError(L["DECURSIVE_DEBUG_REPORT_NOTIFY"]);
|
||||
end
|
||||
self:Println(L["DECURSIVE_DEBUG_REPORT_NOTIFY"]);
|
||||
LastDebugReportNotification = GetTime();
|
||||
end
|
||||
end --}}}
|
||||
-- }}}
|
||||
|
||||
-- This let us park command we can't execute while in combat to execute them later {{{
|
||||
-- the called function must return a non false value when it does something to prevent UI lagging
|
||||
function D:AddDelayedFunctionCall(CallID,functionLink, ...)
|
||||
|
||||
|
||||
if (not self.Status.DelayedFunctionCalls[CallID]) then
|
||||
self.Status.DelayedFunctionCalls[CallID] = {["func"] = functionLink, ["args"] = {...}};
|
||||
self.Status.DelayedFunctionCallsCount = self.Status.DelayedFunctionCallsCount + 1;
|
||||
elseif select("#",...) > 1 then -- if we had more than the function reference and its object
|
||||
|
||||
local args = self.Status.DelayedFunctionCalls[CallID].args;
|
||||
|
||||
for i=1,select("#",...), 1 do
|
||||
args[i]=select(i, ...);
|
||||
end
|
||||
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
|
||||
|
||||
function D:UPDATE_MOUSEOVER_UNIT ()
|
||||
if not self.profile.Hide_LiveList and not self.Status.MouseOveringMUF and not UnitCanAttack("mouseover", "player") then
|
||||
-- D:Debug("will check MouseOver");
|
||||
self.LiveList:DelayedGetDebuff("mouseover");
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function D:PLAYER_TARGET_CHANGED()
|
||||
|
||||
if UnitExists("target") and not UnitCanAttack("player", "target") then
|
||||
|
||||
D.Status.TargetExists = true;
|
||||
|
||||
self.LiveList:DelayedGetDebuff("target");
|
||||
|
||||
|
||||
if self:CheckUnitStealth("target") then
|
||||
self.Stealthed_Units["target"] = true;
|
||||
end
|
||||
|
||||
else
|
||||
D.Status.TargetExists = false;
|
||||
self.Stealthed_Units["target"] = false;
|
||||
end
|
||||
end
|
||||
|
||||
function D:PLAYER_ALIVE()
|
||||
D:Debug("|cFFFF0000PLAYER_ALIVE|r");
|
||||
D:ReConfigure();
|
||||
self:UnregisterEvent("PLAYER_ALIVE");
|
||||
D:CheckPlayer();
|
||||
end
|
||||
|
||||
function D:LEARNED_SPELL_IN_TAB()
|
||||
D:Debug("|cFFFF0000A new spell was learned, scheduling a reconfiguration|r");
|
||||
self:ScheduleDelayedCall("Dcr_NewSpellLearned", self.Configure, 5, self);
|
||||
end
|
||||
|
||||
function D:SPELLS_CHANGED()
|
||||
D:Debug("|cFFFF0000Spells were changed, scheduling a reconfiguration check|r");
|
||||
self:ScheduleDelayedCall("Dcr_SpellsChanged", self.ReConfigure, 15, self);
|
||||
end
|
||||
|
||||
function D:PLAYER_TALENT_UPDATE()
|
||||
D:Debug("|cFFFF0000Talents were changed, scheduling a reconfiguration check|r");
|
||||
self:ScheduleDelayedCall("Dcr_TalentUpdate", self.ReConfigure, 4, self);
|
||||
end
|
||||
|
||||
---[=[
|
||||
local SeenUnitEventsUNITAURA = {};
|
||||
local SeenUnitEventsCOMBAT = {};
|
||||
|
||||
do
|
||||
local FAR = DC.FAR;
|
||||
local UnitAura = _G.UnitAura;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local UnitIsCharmed = _G.UnitIsCharmed;
|
||||
local time = _G.time;
|
||||
local GetTime = _G.GetTime;
|
||||
-- This event manager is only here to catch events when the GUID unit array is not reliable.
|
||||
-- For everything else the combat log event manager does the job since it's a lot more resource friendly. (UNIT_AURA fires way too often and provides no data)
|
||||
function D:UNIT_AURA(selfevent, UnitID, ...)
|
||||
|
||||
if not self.Status.Unit_Array_UnitToGUID[UnitID] then
|
||||
-- self:Debug(UnitID, " |cFFFF7711is not in raid|r");
|
||||
return;
|
||||
end
|
||||
|
||||
local unitguid = UnitGUID(UnitID);
|
||||
|
||||
--[===[@debug@
|
||||
|
||||
|
||||
--D:Debug("UNIT_AURA", ..., UnitID, GetTime() + (GetTime() % 1));
|
||||
|
||||
--@end-debug@]===]
|
||||
|
||||
|
||||
-- Here we test if the GUID->Unit array is ok if it isn't we need to scan the unit for debuffs
|
||||
-- We also scan the unit if it's charmed. The combatLog event manager tends to not detect those properly, the charm effect is a bitch to manage.
|
||||
if unitguid ~= self.Status.Unit_Array_UnitToGUID[UnitID] or UnitID ~= self.Status.Unit_Array_GUIDToUnit[unitguid] or UnitIsCharmed(UnitID) then
|
||||
|
||||
local unitToguid = self.Status.Unit_Array_UnitToGUID[UnitID];
|
||||
|
||||
-- if we updated the unit array but we are here then rebuild the unit array.
|
||||
if self.Status.GroupUpdatedOn >= self.Status.GroupUpdateEvent then
|
||||
|
||||
D:GroupChanged("UNIT_AURA-|cFFFF0000bad group detection|r");
|
||||
|
||||
--[=[
|
||||
self:AddDebugText("AURA event received and Unit_Array_UnitToGUID ~= UnitGUID() and groups up to date, SG:", self.Status.Unit_Array_UnitToGUID[UnitID],
|
||||
"FG:", unitguid,
|
||||
"Unit ID:|cFFFF0000", UnitID,
|
||||
"|rGUIDToUnit[UnitGUID()]:", unitguid and self.Status.Unit_Array_GUIDToUnit[unitguid] or "Xnoguid",
|
||||
"GUIDToUnit[UnitToGUID[]]:|cFFFF0000", unitToguid and self.Status.Unit_Array_GUIDToUnit[unitToguid] or "Xnone",
|
||||
"|rScP:", self.profile.Scan_Pets,
|
||||
"LGU:", self.Status.GroupUpdatedOn,
|
||||
"LGuEr", self.Status.GroupUpdateEvent,
|
||||
"foundUnits:", #self.Status.Unit_Array,
|
||||
"RealRaidNum:", GetNumRaidMembers()
|
||||
--"Zone:", GetZoneText()
|
||||
--"FUnitsList:", unpack(D.Status.Unit_Array)
|
||||
);
|
||||
--]=]
|
||||
end
|
||||
|
||||
--[===[@debug@
|
||||
self:Debug("|cFF552255UNIT_AURA triggers a rescan|r because of", UnitID);
|
||||
--@end-debug@]===]
|
||||
|
||||
if unitguid then
|
||||
self.Status.Unit_Array_UnitToGUID[UnitID] = unitguid;
|
||||
self.Status.Unit_Array_GUIDToUnit[unitguid] = UnitID;
|
||||
end
|
||||
|
||||
if self.profile.ShowDebuffsFrame and self.MicroUnitF.UnitToMUF[UnitID] then
|
||||
|
||||
if self.MicroUnitF.UnitToMUF[UnitID].UnitStatus == FAR then
|
||||
--self:Debug(UnitID, " |cFFFF7711is too far|r (UNIT_AURA)");
|
||||
return
|
||||
end
|
||||
|
||||
-- get out of here if this is just about a fucking buff, combat log event manager handles those... unless there is no debuff because the last was removed
|
||||
if not UnitAura(UnitID, 1, "HARMFUL") and not self.MicroUnitF.UnitToMUF[UnitID].IsDebuffed then
|
||||
--self:Debug(UnitID, " |cFFFF7711has no debuff|r (UNIT_AURA)");
|
||||
return;
|
||||
end
|
||||
|
||||
--self:errln("update schedule for MUF", UnitID);
|
||||
self.MicroUnitF:UpdateMUFUnit(UnitID, true);
|
||||
return;
|
||||
end
|
||||
|
||||
if not self.profile.Hide_LiveList then
|
||||
self.LiveList:DelayedGetDebuff(UnitID);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--]=]
|
||||
|
||||
|
||||
do
|
||||
local bit = _G.bit;
|
||||
local band = bit.band;
|
||||
local bor = bit.bor;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local GetTime = _G.GetTime;
|
||||
local GetSpellInfo = _G.GetSpellInfo;
|
||||
local time = _G.time;
|
||||
local timev = 0;
|
||||
|
||||
|
||||
--@alpha@
|
||||
local DetectHistoryIndex = 1;
|
||||
--@end-alpha@
|
||||
|
||||
-- AURA bitfields -- now useless {{{
|
||||
-- a friendly player character controled directly by the player that is not an outsider
|
||||
local PLAYER = bit.bor (COMBATLOG_OBJECT_CONTROL_PLAYER , COMBATLOG_OBJECT_TYPE_PLAYER , COMBATLOG_OBJECT_REACTION_FRIENDLY ); -- still used
|
||||
local PLAYER_MASK = bit.bnot (COMBATLOG_OBJECT_AFFILIATION_OUTSIDER);
|
||||
|
||||
-- a hostile player character contoled as a pet and that is not an outsider
|
||||
local REACTION_HOSTILE = COMBATLOG_OBJECT_REACTION_HOSTILE;
|
||||
|
||||
-- a pet controled by a friendly player that is not an outsider
|
||||
local PET = bit.bor (COMBATLOG_OBJECT_CONTROL_PLAYER , COMBATLOG_OBJECT_TYPE_PET , COMBATLOG_OBJECT_REACTION_FRIENDLY );
|
||||
local PET_MASK = bit.bnot (COMBATLOG_OBJECT_AFFILIATION_OUTSIDER);
|
||||
|
||||
-- An outsider friendly focused unit
|
||||
local FOCUSED_FRIEND = bit.bor (COMBATLOG_OBJECT_REACTION_FRIENDLY , COMBATLOG_OBJECT_FOCUS , COMBATLOG_OBJECT_AFFILIATION_OUTSIDER);
|
||||
-- }}}
|
||||
|
||||
local OUTSIDER = COMBATLOG_OBJECT_AFFILIATION_OUTSIDER;
|
||||
local HOSTILE_OUTSIDER = bit.bor (COMBATLOG_OBJECT_AFFILIATION_OUTSIDER, COMBATLOG_OBJECT_REACTION_HOSTILE);
|
||||
local FRIENDLY_TARGET = bit.bor (COMBATLOG_OBJECT_TARGET, COMBATLOG_OBJECT_REACTION_FRIENDLY);
|
||||
local ME = COMBATLOG_OBJECT_AFFILIATION_MINE;
|
||||
|
||||
|
||||
local AuraEvents = { -- check if there are some other rare events...
|
||||
["SPELL_AURA_APPLIED"] = 1,
|
||||
["SPELL_AURA_APPLIED_DOSE"] = 1,
|
||||
["SPELL_AURA_REMOVED"] = 0,
|
||||
["SPELL_AURA_APPLIED_DOSE"] = 1,
|
||||
["SPELL_AURA_REMOVED_DOSE"] = 0,
|
||||
["UNIT_DIED"] = 0,
|
||||
--["SPELL_AURA_DISPELLED"] = 0,
|
||||
};
|
||||
|
||||
local SpellEvents = {
|
||||
["SPELL_MISSED"] = true,
|
||||
["SPELL_CAST_START"] = true,
|
||||
["SPELL_CAST_FAILED"] = true,
|
||||
["SPELL_CAST_SUCCESS"] = true,
|
||||
["SPELL_DISPEL_FAILED"] = true,
|
||||
};
|
||||
|
||||
local UnitID;
|
||||
|
||||
function D:DummyDebuff (UnitID)
|
||||
--[=[
|
||||
if self.profile.ShowDebuffsFrame then
|
||||
self.MicroUnitF:UpdateMUFUnit(UnitID);
|
||||
elseif not self.profile.Hide_LiveList then
|
||||
self.LiveList:DelayedGetDebuff(UnitID);
|
||||
end
|
||||
--]=]
|
||||
D:COMBAT_LOG_EVENT_UNFILTERED("COMBAT_LOG_EVENT_UNFILTERED", 0, "SPELL_AURA_APPLIED", nil, nil, COMBATLOG_OBJECT_NONE, UnitGUID(UnitID), (UnitName(UnitID)), PLAYER, 0, "Test item", 0x32, "DEBUFF");
|
||||
end
|
||||
|
||||
local SpecialDebuffs = {
|
||||
[59868] = "SPELL_DAMAGE",
|
||||
};
|
||||
|
||||
local oldest = 0;
|
||||
|
||||
function D:COMBAT_LOG_EVENT_UNFILTERED(selfevent, timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, arg9, arg10, arg11, arg12)
|
||||
|
||||
--@alpha@
|
||||
--[=[
|
||||
if destGUID or destName or arg10 then
|
||||
UnitID = self.Status.Unit_Array_GUIDToUnit[destGUID]; -- get the grouped unit associated to the destGUID if there is none then the unit is not in our group or is filtered out
|
||||
timev = GetTime();
|
||||
|
||||
if timev - oldest > 120 then DetectHistoryIndex = 1 end
|
||||
|
||||
if DetectHistoryIndex == 1 then
|
||||
oldest = timev;
|
||||
end
|
||||
|
||||
if not D.DetectHistory[DetectHistoryIndex] then
|
||||
D.DetectHistory[DetectHistoryIndex] = {timev, UnitID or "NIL", timestamp or "NIL", event or "NIL", sourceGUID or "NIL", sourceName or "NIL", sourceFlags or "NIL", destGUID or "NIL", destName or "NIL", destFlags or "NIL", arg9 or "NIL", arg10 or "NIL", arg11 or "NIL", arg12 or "NIL"};
|
||||
else
|
||||
local temp = D.DetectHistory[DetectHistoryIndex];
|
||||
|
||||
temp[1] = timev;
|
||||
temp[2] = UnitID or "NIL";
|
||||
temp[3] = timestamp or "NIL";
|
||||
temp[4] = event or "NIL";
|
||||
temp[5] = sourceGUID or "NIL";
|
||||
temp[6] = sourceName or "NIL";
|
||||
temp[7] = sourceFlags or "NIL";
|
||||
temp[8] = destGUID or "NIL";
|
||||
temp[9] = destName or "NIL";
|
||||
temp[10] = destFlags or "NIL";
|
||||
temp[11] = arg9 or "NIL";
|
||||
temp[12] = arg10 or "NIL";
|
||||
temp[13] = arg11 or "NIL";
|
||||
temp[14] = arg12 or "NIL";
|
||||
end
|
||||
DetectHistoryIndex = DetectHistoryIndex + 1;
|
||||
end
|
||||
--]=]
|
||||
--@end-alpha@
|
||||
|
||||
|
||||
-- check for exceptions
|
||||
if SpecialDebuffs[arg9] and event == SpecialDebuffs[arg9] then
|
||||
|
||||
--[=[
|
||||
--@alpha@
|
||||
if self.Status.CuringSpells[DC.MAGIC] then
|
||||
UnitID = self.Status.Unit_Array_GUIDToUnit[destGUID]; -- get the grouped unit associated to the destGUID if there is none then the unit is not in our group or is filtered out
|
||||
--self:AddDebugText("CbEvent with DM:", timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, arg9, arg10, arg11, arg12, "Z:", GetZoneText(), "Unit:", UnitID);
|
||||
end
|
||||
--@end-alpha@
|
||||
--]=]
|
||||
|
||||
event = "SPELL_AURA_APPLIED";
|
||||
end
|
||||
|
||||
if destName and AuraEvents[event] then
|
||||
|
||||
if not self.DcrFullyInitialized then
|
||||
self:Println("|cFFFF0000Could not process event: init uncomplete!|r");
|
||||
return;
|
||||
end
|
||||
|
||||
UnitID = self.Status.Unit_Array_GUIDToUnit[destGUID]; -- get the grouped unit associated to the destGUID if there is none then the unit is not in our group or is filtered out
|
||||
|
||||
--D:Print("? (source=%s) (dest=|cFF00AA00%s|r -- %X): |cffff0000%s|r", sourceName, destName, destFlags, event);
|
||||
|
||||
|
||||
-- we don't use the following test because it's unecessary, if a unit is missing, it'll be scanned on addition anyway...
|
||||
--if not UnitID and band (destFlags, OUTSIDER) ~= OUTSIDER then -- we don't have a unit but the flags say it's in our group...
|
||||
--end
|
||||
|
||||
if UnitID then -- this test is enough, if the unit is groupped we definetely need to scan it, whatever is its status...
|
||||
|
||||
--[=[
|
||||
if UnitGUID(UnitID) ~= destGUID then -- sometimes UnitGUID("player") may returns nil... but it's not important since the player GUID is registered once and for all at init time
|
||||
|
||||
self.Groups_datas_are_invalid = true;
|
||||
self:GetUnitArray();
|
||||
UnitID = self.Status.Unit_Array_GUIDToUnit[destGUID];
|
||||
|
||||
if not UnitID then
|
||||
D:Debug("|cFFFF0000No unit for GUID %s|r, in skip list?", destGUID);
|
||||
return;
|
||||
end
|
||||
end
|
||||
--]=]
|
||||
|
||||
if arg12 == "BUFF" and self.profile.Show_Stealthed_Status then
|
||||
|
||||
if DC.IsStealthBuff[arg10] then
|
||||
if AuraEvents[event] == 1 then
|
||||
self.Stealthed_Units[UnitID] = true;
|
||||
else
|
||||
if self.debugging then D:Debug("STEALTH LOST: ", UnitID, arg10); end
|
||||
self.Stealthed_Units[UnitID] = false;
|
||||
end
|
||||
self.MicroUnitF:UpdateMUFUnit(UnitID);
|
||||
end
|
||||
else
|
||||
|
||||
--[===[@debug@
|
||||
if self.debugging then D:Debug("Debuff, UnitId: ", UnitID, arg10, event, time() + (GetTime() % 1), timestamp); end
|
||||
--@end-debug@]===]
|
||||
|
||||
if self.profile.ShowDebuffsFrame then
|
||||
self.MicroUnitF:UpdateMUFUnit(UnitID);
|
||||
|
||||
--@alpha@
|
||||
--D.DetectHistory[DetectHistoryIndex - 1][4] = D.DetectHistory[DetectHistoryIndex - 1][4] .. " DETECTED by cem " .. D.DebuffUpdateRequest;
|
||||
--@end-alpha@
|
||||
|
||||
elseif not self.profile.Hide_LiveList then
|
||||
if self.debugging then D:Debug("(LiveList) Registering delayed GetDebuff for ", destName); end
|
||||
self.LiveList:DelayedGetDebuff(UnitID);
|
||||
end
|
||||
|
||||
if event == "UNIT_DIED" then
|
||||
self.Stealthed_Units[UnitID] = false;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if self.Status.TargetExists and band (destFlags, FRIENDLY_TARGET) == FRIENDLY_TARGET then -- TARGET
|
||||
|
||||
if self.debugging then D:Debug("A Target got something (source=", sourceName, "sFlags:", D:NumToHexStr(sourceFlags), "(dest=|cFF00AA00", destName, "dFlags:", D:NumToHexStr(destFlags), "|r, |cffff0000", event, "|r, |cFF00AAAA", arg10, "|r", arg12); end
|
||||
|
||||
self.LiveList:DelayedGetDebuff("target");
|
||||
|
||||
if arg12 == "BUFF" and self.profile.Show_Stealthed_Status then
|
||||
if DC.IsStealthBuff[arg10] then
|
||||
if AuraEvents[event] == 1 then
|
||||
self.Stealthed_Units["target"] = true;
|
||||
else
|
||||
if self.debugging then D:Debug("TARGET STEALTH LOST: ", "target", arg10); end
|
||||
self.Stealthed_Units["target"] = false;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- SPELL EVENTS {{{
|
||||
elseif self.Status.ClickedMF and SpellEvents[event] and self.Status.CuringSpellsPrio[arg10] and band(sourceFlags, ME) ~= 0 then -- SPELL_MISSED SPELL_CAST_START SPELL_CAST_FAILED SPELL_CAST_SUCCESS DISPEL_FAILED
|
||||
|
||||
if event == "SPELL_CAST_START" then -- useless
|
||||
|
||||
self:Print("|cFFFF0000Starting SPELL: ", arg10, "|r");
|
||||
self:ScheduleDelayedCall("Dcr_UpdatePC"..self.Status.ClickedMF.CurrUnit, self.Status.ClickedMF.Update, 1 + ((select(7, GetSpellInfo(arg9))) / 1000), self.Status.ClickedMF);
|
||||
end
|
||||
|
||||
if event == "SPELL_CAST_SUCCESS" then
|
||||
|
||||
if self.debugging then self:Debug(L["SUCCESSCAST"], arg10, (select(2, GetSpellInfo(arg9))), D:MakePlayerName(destName)); end
|
||||
|
||||
--self:Debug("|cFFFF0000XXXXX|r |cFF11FF11Updating color of clicked frame|r");
|
||||
self:ScheduleDelayedCall("Dcr_UpdatePC"..self.Status.ClickedMF.CurrUnit, self.Status.ClickedMF.Update, 1, self.Status.ClickedMF);
|
||||
self:ScheduleDelayedCall("Dcr_clickedMFreset",
|
||||
function()
|
||||
if D.Status.ClickedMF then
|
||||
D.Status.ClickedMF.SPELL_CAST_SUCCESS = false;
|
||||
D.Status.ClickedMF = false;
|
||||
if self.debugging then D:Debug("ClickedMF to false (sched)"); end
|
||||
end
|
||||
end, 0.1 );
|
||||
|
||||
self.Status.ClickedMF.SPELL_CAST_SUCCESS = true;
|
||||
|
||||
end
|
||||
|
||||
if event == "SPELL_CAST_FAILED" and not D.Status.ClickedMF.SPELL_CAST_SUCCESS then
|
||||
destName = self:PetUnitName( self.Status.ClickedMF.CurrUnit, true);
|
||||
|
||||
D:Println(L["FAILEDCAST"], arg10, (select(2, GetSpellInfo(arg9))), D:MakePlayerName(destName), arg12);
|
||||
|
||||
if (arg12 == SPELL_FAILED_LINE_OF_SIGHT or arg12 == SPELL_FAILED_BAD_TARGETS) then
|
||||
|
||||
if not self.profile.DoNot_Blacklist_Prio_List or not self:IsInPriorList(self.Status.Unit_Array_UnitToGUID[self.Status.ClickedMF.CurrUnit]) then
|
||||
self.Status.Blacklisted_Array[self.Status.ClickedMF.CurrUnit] = self.profile.CureBlacklist;
|
||||
|
||||
self:Debug("|cFFFF0000XXXXX|r |cFF11FF11Updating color of blacklist frame|r");
|
||||
self:ScheduleDelayedCall("Dcr_Update"..self.Status.ClickedMF.CurrUnit, self.Status.ClickedMF.UpdateSkippingSetBuf, self.profile.DebuffsFrameRefreshRate, self.Status.ClickedMF);
|
||||
end
|
||||
|
||||
PlaySoundFile(DC.FailedSound);
|
||||
--[=[
|
||||
elseif arg12 == SPELL_FAILED_BAD_IMPLICIT_TARGETS then
|
||||
self:AddDebugText("ERR_GENERIC_NO_TARGET", "Unit:", self.Status.ClickedMF.CurrUnit, "UE:", UnitExists(self.Status.ClickedMF.CurrUnit), "UiF:", UnitIsFriend("player",self.Status.ClickedMF.CurrUnit), "CBEs:", timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, arg9, arg10, arg11, arg12); --]=]
|
||||
end
|
||||
self.Status.ClickedMF = false;
|
||||
|
||||
elseif event == "SPELL_MISSED" or event == "SPELL_DISPEL_FAILED" then -- XXX to test
|
||||
destName = self:PetUnitName( self.Status.ClickedMF.CurrUnit, true);
|
||||
|
||||
D:Println(L["FAILEDCAST"], arg10, (select(2, GetSpellInfo(arg9))), D:MakePlayerName(destName), arg12);
|
||||
PlaySoundFile(DC.FailedSound);
|
||||
self.Status.ClickedMF = false;
|
||||
end
|
||||
|
||||
|
||||
---- }}}
|
||||
--else
|
||||
-- if self.debugging then D:Debug(sourceName, sourceFlags, destName, destFlags, event, arg10, arg11, arg12, arg13, arg14, arg15, arg16); end
|
||||
-- }}}
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
function D:SPELL_UPDATE_COOLDOWN()
|
||||
D.Status.UpdateCooldown = GetTime();
|
||||
end
|
||||
|
||||
T.LastVCheck = 0;
|
||||
function D:AskVersion()
|
||||
|
||||
if InCombatLockdown() then
|
||||
-- if we are fighting, postpone the call
|
||||
D:AddDelayedFunctionCall ("AskVersion", self.AskVersion);
|
||||
return false;
|
||||
end
|
||||
|
||||
if GetTime() - T.LastVCheck < 60 then
|
||||
D:Debug("AskVersion(): Too early!");
|
||||
return false;
|
||||
end
|
||||
|
||||
T.LastVCheck = GetTime();
|
||||
|
||||
local Distribution = false;
|
||||
-- "PARTY", "RAID", "GUILD", "BATTLEGROUND". As of 2.1, "WHISPER"
|
||||
|
||||
if UnitExists("target") and (UnitFactionGroup("target")) == (UnitFactionGroup("player")) and (tonumber((UnitGUID("target")):sub(5,5), 16) % 8) == 0 then -- the unit exists and is a player of our faction
|
||||
LibStub("AceComm-3.0"):SendCommMessage( "DecursiveVersion", "giveversion", "WHISPER", self:UnitName("target"));
|
||||
D:Debug("Asking version to ", self:UnitName("target"));
|
||||
end
|
||||
|
||||
local inInstance, InstanceType = IsInInstance();
|
||||
|
||||
if InstanceType == "pvp" then
|
||||
Distribution = "BATTLEGROUND";
|
||||
end
|
||||
|
||||
if not Distribution then
|
||||
if GetNumRaidMembers() ~= 0 then
|
||||
Distribution = "RAID";
|
||||
elseif UnitExists("party1") then
|
||||
Distribution = "PARTY";
|
||||
elseif GetGuildInfo("player") then
|
||||
Distribution = "GUILD";
|
||||
end
|
||||
end
|
||||
|
||||
if Distribution then
|
||||
LibStub("AceComm-3.0"):SendCommMessage( "DecursiveVersion", "giveversion", Distribution);
|
||||
end
|
||||
D:Debug("Asking version on ", Distribution);
|
||||
|
||||
return true;
|
||||
|
||||
end
|
||||
|
||||
local LastVersionQueryAnswerPerFrom = {};
|
||||
local LastVersionQueryAnswerPerDist = {};
|
||||
function D:OnCommReceived(message, distribution, from)
|
||||
local alpha = false;
|
||||
--@alpha@
|
||||
alpha = true;
|
||||
--@end-alpha@
|
||||
|
||||
--@alpha@
|
||||
D:Debug("OnCommReceived:", message, distribution, from);
|
||||
--@end-alpha@
|
||||
|
||||
local time = GetTime();
|
||||
|
||||
-- answer version queries but no more than once every 60 seconds to the same player and every 5 seconds to the same chanel
|
||||
-- This avoids a player who would be crafting its own version query messages and sending them repeatidly from causing any damage
|
||||
-- This avoids race conditions where several players would send a version query at the same time on the same chanel
|
||||
if message == "giveversion"
|
||||
and (not LastVersionQueryAnswerPerDist[distribution] or time - LastVersionQueryAnswerPerDist[distribution] > 5 )
|
||||
and (not LastVersionQueryAnswerPerFrom[from] or time - LastVersionQueryAnswerPerFrom[from] > 60 )
|
||||
then
|
||||
|
||||
LibStub("AceComm-3.0"):SendCommMessage("DecursiveVersion", ("Version: %s,%u,%d,%d"):format(D.version, D.VersionTimeStamp, alpha and 1 or 0, D:IsEnabled() and 1 or 0 ), distribution, from )
|
||||
|
||||
LastVersionQueryAnswerPerFrom[from] = time;
|
||||
LastVersionQueryAnswerPerDist[distribution] = time;
|
||||
|
||||
--@alpha@
|
||||
if self.debugging then D:Debug("Version info sent to, ", from, "by", distribution, ("Version: %s,%u,%d,%d"):format(D.version, D.VersionTimeStamp, alpha and 1 or 0, D:IsEnabled() and 1 or 0 )); end
|
||||
--@end-alpha@
|
||||
|
||||
elseif message:sub(1, 8) == "Version:" then
|
||||
|
||||
local version, date, isAlpha, enabled = message:match ("^Version: ([^,]+),(%d+),(%d),(%d)");
|
||||
|
||||
--@alpha@
|
||||
if self.debugging then D:Debug("Version info received from, ", from, "by", distribution, "version:", version, "date:", date, "islpha:", isAlpha, "enabled:", enabled); end
|
||||
--@end-alpha@
|
||||
|
||||
if version then
|
||||
if not D.versions then
|
||||
D.versions = {}
|
||||
end
|
||||
|
||||
D.versions[from] = { version, date, isAlpha, enabled };
|
||||
|
||||
--delayed call to LibStub("AceConfigRegistry-3.0"):NotifyChange(D.name); plus "spam" prevention system (after receiving version info from someone)
|
||||
if not D:DelayedCallExixts ("NewversionDatareceived") then
|
||||
D:ScheduleDelayedCall("NewversionDatareceived", LibStub("AceConfigRegistry-3.0").NotifyChange, 1, LibStub("AceConfigRegistry-3.0"), D.name);
|
||||
T.LastVCheck = time;
|
||||
end
|
||||
else
|
||||
D:Debug("Malformed version string received: ", message);
|
||||
end
|
||||
else
|
||||
D:Debug("Unhandled comm received (spam?)");
|
||||
end
|
||||
end
|
||||
|
||||
function D:ReturnVersions()
|
||||
if not D.versions then
|
||||
return "no data available";
|
||||
end
|
||||
|
||||
local formatedversions = {};
|
||||
for name, versiondetails in pairs(D.versions) do
|
||||
formatedversions[#formatedversions + 1] = ("%s: %s %s (%s)"):format(D:ColorText(name, "FF00AA00"), versiondetails[1], versiondetails[4]==0 and D:ColorText("disabled", "FFFF0000") or "", date("%Y-%m-%d", versiondetails[2]));
|
||||
end
|
||||
|
||||
return table.concat(formatedversions, "\n");
|
||||
end
|
||||
|
||||
T._LoadedFiles["Dcr_Events.lua"] = "2.5.1-6-gd3885c5";
|
||||
|
||||
-- The Great Below
|
||||
@@ -0,0 +1,202 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["DCR_init.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (DCR_init.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local DC = DcrC;
|
||||
local D = Dcr;
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
|
||||
|
||||
local icon = LibStub("LibDBIcon-1.0");
|
||||
|
||||
local LibQTip = LibStub('LibQTip-1.0');
|
||||
|
||||
|
||||
local LDB = LibStub("LibDataBroker-1.1"):NewDataObject("Decursive", {
|
||||
type = "launcher",
|
||||
OnClick = function(Frame, button)
|
||||
D:QuickAccess(Frame, button);
|
||||
end,
|
||||
|
||||
text = "Decursive",
|
||||
label = "Decursive",
|
||||
|
||||
icon = DC.IconOFF,
|
||||
});
|
||||
|
||||
|
||||
local HeadFont;
|
||||
local function CreateFonts()
|
||||
|
||||
Dcr:Debug("create font called");
|
||||
|
||||
-- Create the fonts objects we'll use in the tooltip:
|
||||
-- New font looking like GameTooltipText
|
||||
local HeadFont = CreateFont("DCR_QT_HeadFont")
|
||||
HeadFont:SetFont(GameTooltipText:GetFont(), 16)
|
||||
HeadFont:SetTextColor(0.8,0.8,0.3)
|
||||
|
||||
--[=[
|
||||
|
||||
-- New font looking like defaultFont
|
||||
local CommandFont = CreateFont("DCR_QT_CommandFont")
|
||||
CommandFont:CopyFontObject(defaultFont)
|
||||
CommandFont:SetTextColor(0,1,0)
|
||||
|
||||
--]=]
|
||||
|
||||
return HeadFont;
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function ShowToolTip (frame)
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
--Dcr:Debug("ShowToolTip called");
|
||||
|
||||
if not HeadFont then
|
||||
HeadFont = CreateFonts();
|
||||
end
|
||||
|
||||
local tooltip = LibQTip:Acquire("DecursiveGenInfo", 2, "LEFT", "RIGHT");
|
||||
frame.tooltip = tooltip
|
||||
|
||||
tooltip:SetHeaderFont(HeadFont);
|
||||
|
||||
local x, y;
|
||||
-- 1
|
||||
x, y = tooltip:AddLine();
|
||||
tooltip:SetCell(x,y,'Decursive', HeadFont,"CENTER",2);
|
||||
|
||||
-- 2
|
||||
--tooltip:AddLine( ("|cFF00FF00%s|r: "):format(D.L["HLP_RIGHTCLICK"]),
|
||||
-- D.L["STR_OPTIONS"]);
|
||||
|
||||
-- 3
|
||||
tooltip:AddLine( ("|cFF00FF00%s-%s|r: "):format(D.L["ALT"], D.L["HLP_RIGHTCLICK"]),
|
||||
D.L["BINDING_NAME_DCRSHOWOPTION"]);
|
||||
|
||||
-- 4
|
||||
tooltip:AddLine( ("|cFF00FF00%s-%s|r: "):format(D.L["CTRL"], D.L["HLP_LEFTCLICK"]),
|
||||
D.L["BINDING_NAME_DCRPRSHOW"]);
|
||||
|
||||
-- 5
|
||||
tooltip:AddLine( ("|cFF00FF00%s-%s|r: "):format(D.L["SHIFT"], D.L["HLP_LEFTCLICK"]),
|
||||
D.L["BINDING_NAME_DCRSKSHOW"]);
|
||||
|
||||
-- 6
|
||||
tooltip:AddLine( ("|cFF00FF00%s-%s|r: " ):format(D.L["SHIFT"], D.L["HLP_RIGHTCLICK"]),
|
||||
D.L["BINDING_NAME_DCRSHOW"]);
|
||||
|
||||
if (D.db.global.debugging) then
|
||||
tooltip:AddSeparator();
|
||||
|
||||
x, y = tooltip:AddLine();
|
||||
tooltip:SetCell(x,y,'Debugging', HeadFont,"CENTER",2);
|
||||
|
||||
tooltip:AddLine("Afflicted units count:", D.ForLLDebuffedUnitsNum);
|
||||
|
||||
tooltip:AddLine("Afflicted units count in range:", D.MicroUnitF.UnitsDebuffedInRange);
|
||||
|
||||
tooltip:AddLine("Max Concurrent update events:", D.Status.MaxConcurentUpdateDebuff);
|
||||
|
||||
tooltip:AddSeparator();
|
||||
|
||||
x, y = tooltip:AddLine();
|
||||
tooltip:SetCell(x,y,'Debuff seen history:', HeadFont,"CENTER",2);
|
||||
|
||||
local HistoryIndex = 1;
|
||||
|
||||
while HistoryIndex < 10 do
|
||||
tooltip:AddLine( "|cFFAAFFAA"..HistoryIndex.."|r", (D:Debuff_History_Get (HistoryIndex, true)));
|
||||
|
||||
HistoryIndex = HistoryIndex + 1;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Use smart anchoring code to anchor the tooltip to our frame
|
||||
tooltip:SmartAnchorTo(frame)
|
||||
|
||||
-- Show it
|
||||
tooltip:Show()
|
||||
|
||||
end
|
||||
|
||||
LDB.OnEnter = function(frame)
|
||||
ShowToolTip(frame);
|
||||
end
|
||||
|
||||
LDB.OnLeave = function(frame)
|
||||
LibQTip:Release(frame.tooltip)
|
||||
frame.tooltip = nil
|
||||
|
||||
--Dcr:Debug("Releasing tooltip");
|
||||
end
|
||||
|
||||
|
||||
|
||||
function D:SetIcon (icon)
|
||||
LDB.icon = icon;
|
||||
end
|
||||
|
||||
function D:SetMinimapIcon()
|
||||
if not icon:IsRegistered("Decursive") then
|
||||
icon:Register("Decursive", LDB, D.profile.MiniMapIcon);
|
||||
end
|
||||
end
|
||||
|
||||
function D:HideMiniMapIcon()
|
||||
icon:Hide();
|
||||
end
|
||||
|
||||
T._LoadedFiles["Dcr_LDB.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,575 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_DebuffsFrame.xml"] or not T._LoadedFiles["Dcr_DebuffsFrame.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_DebuffsFrame.xml or Dcr_DebuffsFrame.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-09-16 00:25:13 +0200 (mar., 16 sept. 2008) $", "$Revision: 81755 $");
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
|
||||
--D.LiveList = OOP.Class();
|
||||
|
||||
-- http://www.lua.org/pil/13.4.1.html
|
||||
-- define the namespace
|
||||
D.LiveList = {};
|
||||
local LiveList = D.LiveList;
|
||||
-- a prototype for LiveList objects, empty, defaults are defined in the :New for better performances
|
||||
LiveList.prototype = {};
|
||||
LiveList.metatable ={ __index = LiveList.prototype };
|
||||
|
||||
function LiveList:new(...)
|
||||
local instance = setmetatable({}, self.metatable);
|
||||
instance:init(...);
|
||||
return instance;
|
||||
end
|
||||
|
||||
local MicroUnitF = D.MicroUnitF;
|
||||
|
||||
LiveList.ExistingPerID = {};
|
||||
LiveList.Number = 0;
|
||||
LiveList.NumberShown = 0;
|
||||
D.ForLLDebuffedUnitsNum = 0;
|
||||
|
||||
-- temporary variables often used in function
|
||||
local Debuff, Debuffs, IsCharmed, MF, i, Index, RangeStatus;
|
||||
|
||||
-- local shortcuts to often called global functions
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local next = _G.next;
|
||||
local select = _G.select;
|
||||
local unpack = _G.unpack;
|
||||
local table = _G.table;
|
||||
local UnitExists = _G.UnitExists;
|
||||
local IsSpellInRange = _G.IsSpellInRange;
|
||||
local UnitClass = _G.UnitClass;
|
||||
local UnitIsFriend = _G.UnitIsFriend;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local floor = _G.math.floor;
|
||||
local str_upper = _G.string.upper;
|
||||
local GetRaidTargetIndex= _G.GetRaidTargetIndex;
|
||||
|
||||
|
||||
-- defines what is printed when the object is read as a string
|
||||
function LiveList:ToString() -- {{{
|
||||
return "Decursive Live-List object";
|
||||
end -- }}}
|
||||
|
||||
-- The Factory for LiveList objects
|
||||
function LiveList:Create() -- {{{
|
||||
|
||||
if self.Number + 1 > D.profile.Amount_Of_Afflicted then
|
||||
return false;
|
||||
end
|
||||
|
||||
self.Number = self.Number + 1;
|
||||
|
||||
self.ExistingPerID[self.Number] = self:new(DcrLiveList, self.Number);
|
||||
|
||||
|
||||
return self.ExistingPerID[self.Number];
|
||||
|
||||
end -- }}}
|
||||
|
||||
function LiveList:DisplayItem (ID, UnitID, Debuff) -- {{{
|
||||
|
||||
--D:Debug("(LiveList) Displaying LVItem %d for UnitID %s", ID, UnitID);
|
||||
local LVItem = false;
|
||||
|
||||
if ID > self.Number + 1 then
|
||||
return error(("LiveList:DisplayItem: bad argument #1 'ID (= %d)' must be < LiveList.Number + 1 (LiveList.Number = %d)"):format(ID, self.Number),2);
|
||||
end
|
||||
|
||||
if not self.ExistingPerID[ID] then
|
||||
LVItem=self:Create();
|
||||
else
|
||||
LVItem = self.ExistingPerID[ID];
|
||||
end
|
||||
|
||||
if not LVItem then
|
||||
return false;
|
||||
end
|
||||
|
||||
if not Debuff then
|
||||
Debuff = D.ManagedDebuffUnitCache[UnitID][1];
|
||||
end
|
||||
|
||||
LVItem:SetDebuff(UnitID, Debuff, nil);
|
||||
--D:Debug("XXXX => Updating ll item %d for %s", ID, UnitID);
|
||||
|
||||
if not LVItem.IsShown then
|
||||
--D:Debug("(LiveList) Showing LVItem %d", ID);
|
||||
LVItem.Frame:Show();
|
||||
self.NumberShown = self.NumberShown + 1;
|
||||
LVItem.IsShown = true;
|
||||
end
|
||||
|
||||
end -- }}}
|
||||
|
||||
function LiveList:RestAllPosition () -- {{{
|
||||
for _, LVitem in ipairs(self.ExistingPerID) do
|
||||
LVitem.Frame:ClearAllPoints();
|
||||
LVitem.Frame:SetPoint(LVitem:GiveAnchor());
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
function LiveList.prototype:GiveAnchor() -- {{{
|
||||
|
||||
local ItemHeight = self.Frame:GetHeight();
|
||||
|
||||
if D.profile.ReverseLiveDisplay then
|
||||
end
|
||||
|
||||
if self.ID == 1 then
|
||||
if D.profile.ReverseLiveDisplay then
|
||||
return "BOTTOMLEFT", DecursiveMainBar, "BOTTOMLEFT", 5, -1 * (ItemHeight + 1) * D.profile.Amount_Of_Afflicted;
|
||||
else
|
||||
return "TOPLEFT", DecursiveMainBar, "BOTTOMLEFT", 5, 0;
|
||||
end
|
||||
else
|
||||
if D.profile.ReverseLiveDisplay then
|
||||
return "BOTTOMLEFT", LiveList.ExistingPerID[self.ID - 1].Frame, "TOPLEFT", 0, 1;
|
||||
else
|
||||
return "TOPLEFT", LiveList.ExistingPerID[self.ID - 1].Frame, "BOTTOMLEFT", 0, -1;
|
||||
end
|
||||
end
|
||||
|
||||
end -- }}}
|
||||
|
||||
|
||||
function LiveList.prototype:init(Container,ID) -- {{{
|
||||
|
||||
--LiveList.super.prototype.init(self); -- needed
|
||||
D:Debug("(LiveList) Initializing LiveList object '%s'", ID);
|
||||
|
||||
--ObjectRelated
|
||||
self.ID = ID;
|
||||
self.IsShown = false;
|
||||
self.Parent = Container;
|
||||
|
||||
--Debuff info
|
||||
self.UnitID = false;
|
||||
self.UnitName = false;
|
||||
self.RaidTargetIndex = false;
|
||||
self.PrevUnitName = false;
|
||||
self.PrevUnitID = false;
|
||||
self.PrevRaidTargetIndex= false;
|
||||
self.UnitClass = false;
|
||||
|
||||
self.Debuff = {};
|
||||
|
||||
self.PrevDebuffIndex = false;
|
||||
self.PrevDebuffName = false;
|
||||
self.PrevDebuffTypeName = false;
|
||||
self.PrevDebuffApplicaton = false;
|
||||
self.PrevDebuffTexture = false;
|
||||
|
||||
self.IsCharmed = false;
|
||||
self.PrevIsCharmed = false;
|
||||
|
||||
self.Alpha = false;
|
||||
|
||||
-- Create the frame
|
||||
self.Frame = CreateFrame ("Button", "DcrLiveListItem"..ID, self.Parent, "DcrLVItemTemplate");
|
||||
|
||||
-- Set some basic properties
|
||||
self.Frame:SetFrameStrata("LOW");
|
||||
self.Frame:RegisterForClicks("AnyDown");
|
||||
|
||||
-- Set the anchor of this item
|
||||
self.Frame:SetPoint(self:GiveAnchor());
|
||||
|
||||
-- create the background
|
||||
self.BackGroundTexture = self.Frame:CreateTexture("DcrLiveListItem"..ID.."BackTexture", "BACKGROUND", "DcrLVBackgroundTemplate");
|
||||
|
||||
-- Create the Icon Texture
|
||||
self.IconTexture = self.Frame:CreateTexture("DcrLiveListItem"..ID.."Icon", "ARTWORK", "DcrLVIconTemplate");
|
||||
|
||||
-- Create the Debuff application count font string
|
||||
self.DebuffAppsFontString = self.Frame:CreateFontString("DcrLiveListItem"..ID.."Count", "OVERLAY", "DcrLLAfflictionCountFont");
|
||||
|
||||
-- Create the character name Fontstring
|
||||
self.UnitNameFontString = self.Frame:CreateFontString("DcrLiveListItem"..ID.."UnitName", "OVERLAY", "DcrLLUnitNameFont");
|
||||
|
||||
-- Create the unitID Fontstring
|
||||
self.UnitIDFontString = self.Frame:CreateFontString("DcrLiveListItem"..ID.."UnitID", "OVERLAY", "DcrLLUnitIDFont");
|
||||
--self.UnitIDFontString:SetHeight(3);
|
||||
|
||||
-- Create the debuff type fontstring
|
||||
self.DebuffTypeFontString = self.Frame:CreateFontString("DcrLiveListItem"..ID.."Type", "OVERLAY", "DcrLLDebuffTypeFont");
|
||||
|
||||
-- Create the Raid Target Icon Texture
|
||||
self.RaidIconTexture = self.Frame:CreateTexture("DcrLiveListItem"..ID.."RaidIcon", "ARTWORK", "DcrLVRaidIconTemplate");
|
||||
|
||||
-- Create the debuff name fontstring
|
||||
self.DebuffNameFontString = self.Frame:CreateFontString("DcrLiveListItem"..ID.."Name", "OVERLAY", "DcrLLDebuffNameFont");
|
||||
|
||||
|
||||
-- a reference to this object
|
||||
self.Frame.Object = self;
|
||||
|
||||
self.Frame:Show();
|
||||
|
||||
|
||||
end -- }}}
|
||||
|
||||
function LiveList.prototype:SetDebuff(UnitID, Debuff, IsCharmed) -- {{{
|
||||
self.UnitID = UnitID;
|
||||
self.UnitName = D:PetUnitName(UnitID, true);
|
||||
self.Debuff = Debuff;
|
||||
self.IsCharmed = IsCharmed;
|
||||
self.RaidTargetIndex = GetRaidTargetIndex(UnitID);
|
||||
|
||||
if D.profile.LiveListAlpha ~= self.Alpha then
|
||||
self.Frame:SetAlpha(D.profile.LiveListAlpha);
|
||||
self.Alpha = D.profile.LiveListAlpha;
|
||||
end
|
||||
|
||||
-- Set the graphical elements to the right values
|
||||
-- Icon
|
||||
if self.PrevDebuffTexture ~= Debuff.Texture then
|
||||
self.IconTexture:SetTexture(Debuff.Texture);
|
||||
self.PrevDebuffTexture = Debuff.Texture;
|
||||
end
|
||||
|
||||
-- Raid Icon
|
||||
if self.PrevRaidTargetIndex ~= self.RaidTargetIndex then
|
||||
self.RaidIconTexture:SetTexture(self.RaidTargetIndex and DC.RAID_ICON_TEXTURE_LIST[self.RaidTargetIndex] or nil);
|
||||
self.PrevRaidTargetIndex = self.RaidTargetIndex;
|
||||
end
|
||||
|
||||
-- Applications count
|
||||
if self.PrevDebuffApplicaton ~= Debuff.Applications then
|
||||
if (Debuff.Applications > 1) then
|
||||
self.DebuffAppsFontString:SetText(Debuff.Applications);
|
||||
self.PrevDebuffApplicaton = Debuff.Applications;
|
||||
else
|
||||
self.DebuffAppsFontString:SetText(" ");
|
||||
self.PrevDebuffApplicaton = " ";
|
||||
end
|
||||
end
|
||||
|
||||
-- Unit Name
|
||||
if self.PrevUnitName ~= self.UnitName then
|
||||
self.UnitClass = (select(2, UnitClass(UnitID)));
|
||||
self.UnitNameFontString:SetText(self.UnitName);
|
||||
if self.UnitClass then
|
||||
self.UnitNameFontString:SetTextColor(unpack(DC.ClassesColors[self.UnitClass]));
|
||||
end
|
||||
self.PrevUnitName = self.UnitName;
|
||||
--D:Debug("(LiveList) Updating %d with %s", self.ID, UnitID);
|
||||
end
|
||||
|
||||
-- Unit ID
|
||||
if self.PrevUnitID ~= UnitID then
|
||||
self.UnitIDFontString:SetText("( "..UnitID.." )");
|
||||
self.PrevUnitID = UnitID;
|
||||
end
|
||||
|
||||
-- Debuff Type Name
|
||||
if self.PrevDebuffTypeName ~= Debuff.TypeName then
|
||||
if Debuff.Type then
|
||||
self.DebuffTypeFontString:SetText(D:ColorText(L[str_upper(Debuff.TypeName)], "FF" .. DC.TypeColors[Debuff.Type] ));
|
||||
--self.DebuffTypeFontString:SetTextColor(DC.TypeColors[Debuff.Type]);
|
||||
else
|
||||
self.DebuffTypeFontString:SetText("Unknown");
|
||||
end
|
||||
self.PrevDebuffTypeName = Debuff.TypeName;
|
||||
end
|
||||
|
||||
-- Debuff Name
|
||||
if self.PrevDebuffName ~= Debuff.Name then
|
||||
self.DebuffNameFontString:SetText(Debuff.Name);
|
||||
self.PrevDebuffName = Debuff.Name;
|
||||
end
|
||||
|
||||
end -- }}}
|
||||
|
||||
|
||||
function LiveList:GetDebuff(UnitID) -- {{{
|
||||
-- (note that this function is only called for the mouseover and target if the MUFs are active)
|
||||
|
||||
--D:Debug("(LiveList) Getting Debuff for ", UnitID);
|
||||
if (UnitID == "target" or UnitID == "mouseover") and not UnitIsFriend(UnitID, "player") then
|
||||
if D.ManagedDebuffUnitCache[UnitID] and D.ManagedDebuffUnitCache[UnitID][1] and D.ManagedDebuffUnitCache[UnitID][1].Type then
|
||||
D.ManagedDebuffUnitCache[UnitID][1].Type = false; -- clear target/mouseover debuff
|
||||
D.UnitDebuffed[UnitID] = false; -- XXX changed from 'target' to UnitID on 2010-06-08
|
||||
end
|
||||
--D:Debug("(LiveList) GetDebuff() |cFF00DDDDcanceled|r, unit %s is hostile or gone.", UnitID);
|
||||
return false;
|
||||
end
|
||||
|
||||
-- decrease the total debuff number if the MUFs system isn't already doing it and if it's not the mouseover or target unit
|
||||
if not D.profile.ShowDebuffsFrame and D.UnitDebuffed[UnitID] and UnitID ~= "mouseover" and UnitID ~= "target" then
|
||||
D.ForLLDebuffedUnitsNum = D.ForLLDebuffedUnitsNum - 1;
|
||||
end
|
||||
|
||||
-- Get the unit Debuffs
|
||||
if not D.profile.ShowDebuffsFrame or not MicroUnitF.UnitToMUF[UnitID] or UnitID == "mouseover" or UnitID == "target" then
|
||||
Debuffs, IsCharmed = D:UnitCurableDebuffs(UnitID);
|
||||
--Debuffs, IsCharmed = D:UnitCurableDebuffs(UnitID, true);
|
||||
else -- The MUFs are active and Unit is not mouseover and is not target
|
||||
MF = MicroUnitF.UnitToMUF[UnitID];
|
||||
if MF then
|
||||
Debuffs = MF.Debuffs;
|
||||
--[=[
|
||||
else -- (ticket #6)
|
||||
D:AddDebugText("Sanity check failed in LiveList:GetDebuff() no MUF for unit", UnitID, "MUFs are", D.profile.ShowDebuffsFrame, "MUFnum:", MicroUnitF.Number, "MUFshown:", MicroUnitF.UnitShown, "UnitNum:", D.Status.UnitNum, "UnitExists:", UnitExists(UnitID), "Auto MUF show/hide:", D.profile.AutoHideDebuffsFrame, "InCombatLockdown():", InCombatLockdown());
|
||||
D:AddDebugText("Stack:\n", debugstack(2));
|
||||
--]=]
|
||||
end
|
||||
end
|
||||
|
||||
if (Debuffs and Debuffs[1] and Debuffs[1].Type) then -- there is a Debuff
|
||||
|
||||
D.UnitDebuffed[UnitID] = true; -- register that this unit is debuffed
|
||||
|
||||
-- increase the total debuff number
|
||||
if not D.profile.ShowDebuffsFrame and UnitID ~= "mouseover" and UnitID ~= "target" then
|
||||
|
||||
D.ForLLDebuffedUnitsNum = D.ForLLDebuffedUnitsNum + 1;
|
||||
|
||||
end
|
||||
else
|
||||
D.UnitDebuffed[UnitID] = false; -- unregister this unit
|
||||
end
|
||||
|
||||
return D.UnitDebuffed[UnitID];
|
||||
end -- }}}
|
||||
|
||||
function LiveList:DelayedGetDebuff(UnitID) -- {{{
|
||||
if not D:DelayedCallExixts("Dcr_GetDebuff"..UnitID) then
|
||||
D.DebuffUpdateRequest = D.DebuffUpdateRequest + 1;
|
||||
D:Debug("LiveList: GetDebuff scheduled for, ", UnitID);
|
||||
D:ScheduleDelayedCall("Dcr_GetDebuff"..UnitID, self.GetDebuff, (D.profile.ScanTime / 2) * (1 + floor(D.DebuffUpdateRequest / 7.5)), self, UnitID);
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
local IndexOffset = 0; -- used when target and/or mouseover are found
|
||||
local DebuffedUnitsNumber = 0;
|
||||
local _;
|
||||
function LiveList:Update_Display() -- {{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
-- Update the unit array
|
||||
--[[
|
||||
if (D.Groups_datas_are_invalid) then
|
||||
D:GetUnitArray();
|
||||
end
|
||||
--]]
|
||||
|
||||
Index = 0;
|
||||
|
||||
if D.profile.ShowDebuffsFrame and D.profile.LV_OnlyInRange then -- The MUFs are here and we test for range
|
||||
DebuffedUnitsNumber = MicroUnitF.UnitsDebuffedInRange;
|
||||
else -- the MUFs are not here or we don't test for range
|
||||
DebuffedUnitsNumber = D.ForLLDebuffedUnitsNum;
|
||||
end
|
||||
|
||||
-- Check the units in order of importance:
|
||||
|
||||
-- First the Target
|
||||
if D.Status.TargetExists and not D.Status.Unit_Array_GUIDToUnit[UnitGUID("target")] and self:GetDebuff("target") then -- TargetExists implies that the unit is a friend
|
||||
Index = Index + 1;
|
||||
self:DisplayItem(Index, "target");
|
||||
--D:Debug("frenetic target update");
|
||||
|
||||
DebuffedUnitsNumber = DebuffedUnitsNumber + 1;
|
||||
|
||||
if not D.Status.SoundPlayed then
|
||||
D:PlaySound ("target", "LV target" );
|
||||
end
|
||||
end
|
||||
|
||||
-- Then the MouseOver
|
||||
if not D.Status.MouseOveringMUF and D.UnitDebuffed["mouseover"] and not D.Status.Unit_Array_GUIDToUnit[UnitGUID("mouseover")] and self:GetDebuff("mouseover") then -- this won't catch new debuff if all debuffs disappeard while overing the unit...
|
||||
Index = Index + 1;
|
||||
self:DisplayItem(Index, "mouseover");
|
||||
--D:Debug("frenetic mouseover update");
|
||||
|
||||
DebuffedUnitsNumber = DebuffedUnitsNumber + 1;
|
||||
|
||||
if not D.Status.SoundPlayed then
|
||||
D:PlaySound ("mouseover", "LV mouseover" );
|
||||
end
|
||||
end
|
||||
|
||||
-- the sound played status is reset here because the live list is able to display target and mouseover units and far away ones...
|
||||
if DebuffedUnitsNumber == 0 then
|
||||
D.Status.SoundPlayed = false;
|
||||
end
|
||||
|
||||
IndexOffset = Index;
|
||||
|
||||
-- Then continue with all the remaining units if at least one of them is debuffed
|
||||
-- We need this loop because:
|
||||
-- 1, we have to show an ordered list (always true)
|
||||
-- 2, we want to test if the unit is in spell range (only if the option is active and the MUFs hidden)
|
||||
-- There is no event to do the last and a not simple table.sort() would be needed for the first...
|
||||
if DebuffedUnitsNumber > 0 and Index < D.profile.Amount_Of_Afflicted then
|
||||
for _, UnitID in ipairs(D.Status.Unit_Array) do
|
||||
-- if the unit is debuffed and still exists and is not stealthed check this only if the MUFs engine is not there, redudent tests otherwise...
|
||||
if D.UnitDebuffed[UnitID] and UnitExists(UnitID) then
|
||||
|
||||
-- we don't care about range
|
||||
if not D.profile.LV_OnlyInRange then
|
||||
Index = Index + 1;
|
||||
self:DisplayItem(Index, UnitID);
|
||||
|
||||
-- play the sound if not already done
|
||||
if not D.Status.SoundPlayed then
|
||||
D:PlaySound (UnitID, "LV scan NR" );
|
||||
end
|
||||
|
||||
else -- we care about range
|
||||
|
||||
if D.profile.ShowDebuffsFrame and MicroUnitF.UnitToMUF[UnitID] then
|
||||
RangeStatus = MicroUnitF.UnitToMUF[UnitID].UnitStatus; -- MicroUnitF.UnitToMUF[UnitID] is nil sometimes XXX
|
||||
RangeStatus = (RangeStatus == DC.AFFLICTED or RangeStatus == DC.AFFLICTED_AND_CHARMED) and true or false;
|
||||
else
|
||||
if D.Status.CuringSpells[D.ManagedDebuffUnitCache[UnitID][1].Type] then
|
||||
RangeStatus = IsSpellInRange(D.Status.CuringSpells[D.ManagedDebuffUnitCache[UnitID][1].Type], UnitID);
|
||||
else
|
||||
D:AddDebugText(
|
||||
"LiveList:Update_Display(): couldn't get range, DType:", D.ManagedDebuffUnitCache[UnitID][1].Type,
|
||||
"DTypeName:", D.ManagedDebuffUnitCache[UnitID][1].TypeName,
|
||||
"DName:", D.ManagedDebuffUnitCache[UnitID][1].Name,
|
||||
"MUFs are:", D.profile.ShowDebuffsFrame,
|
||||
"InCombatLockdown():", InCombatLockdown(),
|
||||
"UnitID:", UnitID
|
||||
);
|
||||
RangeStatus = 0;
|
||||
|
||||
end
|
||||
RangeStatus = (RangeStatus and RangeStatus ~= 0) and true or false;
|
||||
end
|
||||
|
||||
if (RangeStatus) then
|
||||
Index = Index + 1;
|
||||
self:DisplayItem(Index, UnitID);
|
||||
-- play the sound if not already done
|
||||
if not D.Status.SoundPlayed then
|
||||
D:PlaySound (UnitID, "LV R" );
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- don't loop if we reach the max displayed unit num or if all debuffed units have been displayed
|
||||
if Index == D.profile.Amount_Of_Afflicted or Index == DebuffedUnitsNumber + IndexOffset then
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- reset the sound if no units were displayed
|
||||
if not D.profile.ShowDebuffsFrame and Index == 0 and D.Status.SoundPlayed then
|
||||
Dcr:Debug("LV: No more unit displayed, sound re-enabled");
|
||||
D.Status.SoundPlayed = false; -- re-enable the sound if no more debuff
|
||||
end
|
||||
|
||||
-- Hide unneeded Items
|
||||
if self.NumberShown > Index then -- if there are more units shown than the actual number of debuffed units
|
||||
for i = Index + 1, self.NumberShown do
|
||||
if self.ExistingPerID[i] and self.ExistingPerID[i].IsShown then
|
||||
--D:Debug("(LiveList) Hidding LVItem %d", i);
|
||||
self.ExistingPerID[i].Frame:Hide();
|
||||
self.ExistingPerID[i].IsShown = false;
|
||||
self.NumberShown = self.NumberShown - 1;
|
||||
else
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end -- }}}
|
||||
|
||||
|
||||
|
||||
function LiveList:DisplayTestItem() -- {{{
|
||||
if not self.TestItemDisplayed and D.Status.Unit_Array[1] then
|
||||
self.TestItemDisplayed = GetTime();
|
||||
D:DummyDebuff(D.Status.Unit_Array[1], "Test item");
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
function LiveList:HideTestItem() -- {{{
|
||||
self.TestItemDisplayed = false;
|
||||
local i = 1;
|
||||
|
||||
for UnitID, Debuffed in pairs(D.UnitDebuffed) do
|
||||
if Debuffed then
|
||||
D:ScheduleDelayedCall("Dcr_rmt"..i, D.DummyDebuff, i * (D.profile.ScanTime / 2), D, UnitID);
|
||||
i = i + 1;
|
||||
end
|
||||
end
|
||||
|
||||
end -- }}}
|
||||
|
||||
|
||||
-- this displays the tooltips of the live-list
|
||||
function LiveList:DebuffTemplate_OnEnter(frame) --{{{
|
||||
if (D.profile.AfflictionTooltips and frame.Object.UnitID) then
|
||||
DcrDisplay_Tooltip:SetOwner(frame, "ANCHOR_CURSOR");
|
||||
DcrDisplay_Tooltip:ClearLines();
|
||||
DcrDisplay_Tooltip:SetUnitDebuff(frame.Object.UnitID,frame.Object.Debuff.index); -- OK
|
||||
DcrDisplay_Tooltip:Show();
|
||||
else
|
||||
D:Debug(D.profile.AfflictionTooltips, frame.Object.UnitID );
|
||||
end
|
||||
end --}}}
|
||||
|
||||
function LiveList:Onclick() -- {{{
|
||||
D:Println(L["HLP_LL_ONCLICK_TEXT"]);
|
||||
end -- }}}
|
||||
|
||||
T._LoadedFiles["Dcr_LiveList.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,211 @@
|
||||
<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/">
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
<Script>
|
||||
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_LiveList.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_LiveList.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
-- Dcr:SetDateAndRevision("$Date: 2007-12-02 22:31:14 +0100 (dim., 02 déc. 2007) $", "$Revision: 56465 $");
|
||||
</Script>
|
||||
|
||||
<Frame name="DcrLiveList" frameStrata="LOW" toplevel="true" enableMouse="true" movable="true" hidden="false" parent="UIParent"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="DecursiveMainBar">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-2"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Frame> <!-- }}} -->
|
||||
|
||||
<Button name="DcrLVItemTemplate" virtual="true" hidden="true"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="180" y="32"/>
|
||||
</Size>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr.LiveList:Onclick();
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr.LiveList:DebuffTemplate_OnEnter(self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button> <!-- }}} -->
|
||||
|
||||
|
||||
<Texture name="DcrLVBackgroundTemplate" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parent" />
|
||||
<Anchor point="BOTTOMRIGHT" relativeTo="$parent" />
|
||||
</Anchors>
|
||||
<Color r="0" g="0" b="0" a="0.75" />
|
||||
</Texture> <!-- }}} -->
|
||||
|
||||
<Texture name="DcrLVIconTemplate" file="Interface\AddOns\Decursive\iconON.tga" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="32" y="32" />
|
||||
</Size>
|
||||
</Texture> <!-- }}} -->
|
||||
|
||||
<Texture name="DcrLVRaidIconTemplate" file="Interface\AddOns\Decursive\iconON.tga" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="-1" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<!--
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentType">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
-->
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
</Texture> <!-- }}} -->
|
||||
|
||||
<FontString name="DcrLLAfflictionCountFont" inherits="NumberFontNormalSmall" maxLines="1" text="1" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="1" y="1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Color r="1.0" g="0.1" b="0.2"/>
|
||||
<Shadow>
|
||||
<offset>
|
||||
<AbsDimension x="1" y="1" />
|
||||
</offset>
|
||||
<color r="0" g="0" b="0" />
|
||||
</Shadow>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
<FontString name="DcrLLUnitNameFont" inherits="GameFontNormalSmall" justifyH="LEFT" maxLines="1" text="Unit Name" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativeTo="$parentIcon" relativePoint="TOPRIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="1" y="-1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="73" />
|
||||
</Size>
|
||||
<Color r="1.0" g="0.1" b="0.2"/>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
<FontString name="DcrLLUnitIDFont" inherits="MasterFont" font="Fonts\FRIZQT__.TTF" justifyH="LEFT" maxLines="1" text="Unit Name" virtual="true"> <!-- {{{ -->
|
||||
<FontHeight>
|
||||
<AbsValue val="7.5"/>
|
||||
</FontHeight>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="$parentUnitName" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="65" />
|
||||
</Size>
|
||||
<Color r=".6" g=".6" b=".6"/>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
<FontString name="DcrLLDebuffTypeFont" inherits="GameFontNormalSmall" justifyH="RIGHT" maxLines="1" text="Debuff Type" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="-1" y="-1"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="73" />
|
||||
</Size>
|
||||
<Color r="1.0" g="0.1" b="1.0"/>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
<FontString name="DcrLLDebuffNameFont" inherits="GameFontNormalSmall" justifyH="LEFT" maxLines="1" text="Name of the afflication" virtual="true"> <!-- {{{ -->
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentIcon">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentUnitID">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-2" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Size>
|
||||
<AbsDimension x="147" />
|
||||
</Size>
|
||||
<Color r="0.1" g="0.5" b="0.4"/>
|
||||
</FontString> <!-- }}} -->
|
||||
|
||||
|
||||
<Script>
|
||||
local T = DecursiveRootTable or {};
|
||||
T._LoadedFiles["Dcr_LiveList.xml"] = "2.5.1-6-gd3885c5";
|
||||
</Script>
|
||||
</Ui>
|
||||
@@ -0,0 +1,783 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_Events.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_Events.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-09-16 00:25:13 +0200 (mar., 16 sept. 2008) $", "$Revision: 81755 $");
|
||||
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
|
||||
local RaidRosterCache = { };
|
||||
local SortingTable = { };
|
||||
D.Status.Unit_Array_GUIDToUnit = { };
|
||||
D.Status.Unit_Array_UnitToGUID = { };
|
||||
|
||||
D.Status.InternalPrioList = { };
|
||||
D.Status.InternalSkipList = { };
|
||||
D.Status.Unit_Array = { };
|
||||
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local type = _G.type;
|
||||
local select = _G.select;
|
||||
local UnitIsFriend = _G.UnitIsFriend;
|
||||
local UnitCanAttack = _G.UnitCanAttack;
|
||||
local GetNumRaidMembers = _G.GetNumRaidMembers;
|
||||
local GetNumPartyMembers = _G.GetNumPartyMembers;
|
||||
local GetRaidRosterInfo = _G.GetRaidRosterInfo;
|
||||
local random = _G.random;
|
||||
local UnitIsUnit = _G.UnitIsUnit;
|
||||
local UnitClass = _G.UnitClass;
|
||||
local UnitExists = _G.UnitExists;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local table = _G.table;
|
||||
local t_insert = _G.table.insert;
|
||||
local str_upper = _G.string.upper;
|
||||
local MAX_RAID_MEMBERS = _G.MAX_RAID_MEMBERS;
|
||||
local setmetatable = _G.setmetatable;
|
||||
local rawget = _G.rawget;
|
||||
local GetTime = _G.GetTime;
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- GROUP STATUS UPDATE, these functions update the UNIT table to scan {{{
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
local function AddToSort (unit, GUID, index) -- // {{{
|
||||
if (D.profile.Random_Order and
|
||||
(not D.Status.InternalPrioList[GUID]) and not GUID~=MyGUID) then
|
||||
index = random (1, 3000);
|
||||
end
|
||||
SortingTable[unit] = index;
|
||||
--D:Debug("Adding to sort: ", unit, index);
|
||||
end --}}}
|
||||
--]=]
|
||||
|
||||
|
||||
-- Raid/Party Name Check Function (a terrible function, need optimising)
|
||||
-- this returns the UnitID that the Name points to
|
||||
-- this does not check "target" or "mouseover"
|
||||
--[=[
|
||||
function D:NameToUnit( Name ) --{{{
|
||||
|
||||
local numRaidMembers = GetNumRaidMembers();
|
||||
local FoundUnit = false;
|
||||
|
||||
|
||||
if (not Name) then
|
||||
return false;
|
||||
end
|
||||
|
||||
if self.Status.Unit_Array_NameToUnit[Name] ~= nil then
|
||||
return self.Status.Unit_Array_NameToUnit[Name];
|
||||
end
|
||||
|
||||
if (numRaidMembers == 0) then
|
||||
if (Name == (self:UnitName("player"))) then
|
||||
FoundUnit = "player";
|
||||
elseif (Name == (self:UnitName("pet"))) then
|
||||
FoundUnit = "pet";
|
||||
elseif GetNumPartyMembers() > 0 then
|
||||
if (Name == (self:UnitName("party1"))) then
|
||||
FoundUnit = "party1";
|
||||
elseif (Name == (self:UnitName("party2"))) then
|
||||
FoundUnit = "party2";
|
||||
elseif (Name == (self:UnitName("party3"))) then
|
||||
FoundUnit = "party3";
|
||||
elseif (Name == (self:UnitName("party4"))) then
|
||||
FoundUnit = "party4";
|
||||
elseif (Name == (self:UnitName("partypet1"))) then
|
||||
FoundUnit = "partypet1";
|
||||
elseif (Name == (self:UnitName("partypet2"))) then
|
||||
FoundUnit = "partypet2";
|
||||
elseif (Name == (self:UnitName("partypet3"))) then
|
||||
FoundUnit = "partypet3";
|
||||
elseif (Name == (self:UnitName("partypet4"))) then
|
||||
FoundUnit = "partypet4";
|
||||
end
|
||||
end
|
||||
else
|
||||
-- we are in a raid
|
||||
local i;
|
||||
local foundmembers = 0;
|
||||
local RaidName;
|
||||
for i=1, MAX_RAID_MEMBERS do
|
||||
RaidName = (GetRaidRosterInfo(i));
|
||||
|
||||
if RaidName then
|
||||
|
||||
foundmembers = foundmembers + 1;
|
||||
|
||||
if ( Name == RaidName) then
|
||||
FoundUnit = "raid"..i;
|
||||
break;
|
||||
end
|
||||
if ( self.profile.Scan_Pets and Name == (self:UnitName("raidpet"..i))) then
|
||||
FoundUnit = "raidpet"..i;
|
||||
break;
|
||||
end
|
||||
|
||||
if foundmembers == numRaidMembers then
|
||||
break;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.Status.Unit_Array_NameToUnit[Name] = FoundUnit;
|
||||
|
||||
return FoundUnit;
|
||||
|
||||
end --}}}
|
||||
--]=]
|
||||
-- }}}
|
||||
|
||||
|
||||
|
||||
DC.ClassNumToLName = {
|
||||
[11] = LC[DC.CLASS_DRUID],
|
||||
[12] = LC[DC.CLASS_HUNTER],
|
||||
[13] = LC[DC.CLASS_MAGE],
|
||||
[14] = LC[DC.CLASS_PALADIN],
|
||||
[15] = LC[DC.CLASS_PRIEST],
|
||||
[16] = LC[DC.CLASS_ROGUE],
|
||||
[17] = LC[DC.CLASS_SHAMAN],
|
||||
[18] = LC[DC.CLASS_WARLOCK],
|
||||
[19] = LC[DC.CLASS_WARRIOR],
|
||||
[20] = LC[DC.CLASS_DEATHKNIGHT],
|
||||
}
|
||||
|
||||
DC.ClassLNameToNum = D:tReverse(DC.ClassNumToLName);
|
||||
|
||||
DC.ClassNumToUName = {
|
||||
[11] = DC.CLASS_DRUID,
|
||||
[12] = DC.CLASS_HUNTER,
|
||||
[13] = DC.CLASS_MAGE,
|
||||
[14] = DC.CLASS_PALADIN,
|
||||
[15] = DC.CLASS_PRIEST,
|
||||
[16] = DC.CLASS_ROGUE,
|
||||
[17] = DC.CLASS_SHAMAN,
|
||||
[18] = DC.CLASS_WARLOCK,
|
||||
[19] = DC.CLASS_WARRIOR,
|
||||
[20] = DC.CLASS_DEATHKNIGHT,
|
||||
}
|
||||
|
||||
DC.ClassUNameToNum = D:tReverse(DC.ClassNumToUName);
|
||||
|
||||
|
||||
-- this gets an array of units for us to check
|
||||
|
||||
do
|
||||
|
||||
local i = 1;
|
||||
local D = D;
|
||||
local _ = false; -- a local dummy trash variable
|
||||
|
||||
local MAX_RAID_MEMBERS = _G.MAX_RAID_MEMBERS;
|
||||
|
||||
local UnitToGUID = {};
|
||||
local GUIDToUnit = {};
|
||||
|
||||
local raidnum = 0;
|
||||
|
||||
local UnitToGUID_mt = { __index = function(self, unit)
|
||||
local GUID = UnitGUID(unit) or false;
|
||||
|
||||
self[unit] = GUID;
|
||||
GUIDToUnit[GUID] = unit;
|
||||
|
||||
--[=[
|
||||
if (D.db.global.debugging) then
|
||||
if not GUID then
|
||||
D:errln("UnitToGUID_mt: no GUID for: ", unit); -- this is not an error, it's to see when raid# ids are not contiguous...
|
||||
end
|
||||
end
|
||||
--]=]
|
||||
|
||||
|
||||
return self[unit];
|
||||
end };
|
||||
|
||||
|
||||
local GUIDToUnit_ScannedAll = false;
|
||||
local lookforpets = true;
|
||||
local GUIDToUnit_mt = { __index = function(self, GUID)
|
||||
-- {{{
|
||||
|
||||
if GUIDToUnit_ScannedAll then
|
||||
self[GUID] = false;
|
||||
D:Debug("GUIDToUnit_mt: %s is not in our group!", GUID);
|
||||
return self[GUID];
|
||||
end
|
||||
|
||||
if (not GUID) then
|
||||
D:errln("GUIDToUnit_mt: no GUID! ");
|
||||
return false;
|
||||
end
|
||||
|
||||
local unit = false;
|
||||
|
||||
|
||||
if GUID == DC.MyGUID then
|
||||
unit = "player";
|
||||
elseif GUID == UnitToGUID["pet"] then
|
||||
unit = "pet";
|
||||
elseif (raidnum == 0) then
|
||||
if GetNumPartyMembers() > 0 then
|
||||
if GUID == UnitToGUID["party1"] then
|
||||
unit = "party1";
|
||||
elseif GUID == UnitToGUID["party2"] then
|
||||
unit = "party2";
|
||||
elseif GUID == UnitToGUID["party3"] then
|
||||
unit = "party3";
|
||||
elseif GUID == UnitToGUID["party4"] then
|
||||
unit = "party4";
|
||||
elseif D.profile.Scan_Pets then
|
||||
if GUID == UnitToGUID["partypet1"] then
|
||||
unit = "partypet1";
|
||||
elseif GUID == UnitToGUID["partypet2"] then
|
||||
unit = "partypet2";
|
||||
elseif GUID == UnitToGUID["partypet3"] then
|
||||
unit = "partypet3";
|
||||
elseif GUID == UnitToGUID["partypet4"] then
|
||||
unit = "partypet4";
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
-- we are in a raid
|
||||
local i;
|
||||
local foundmembers = 0;
|
||||
local RaidGUID;
|
||||
for i=1, MAX_RAID_MEMBERS do
|
||||
RaidGUID = UnitToGUID[ "raid"..i];
|
||||
|
||||
if RaidGUID then
|
||||
|
||||
foundmembers = foundmembers + 1;
|
||||
|
||||
if GUID == RaidGUID then
|
||||
unit = "raid"..i;
|
||||
break;
|
||||
end
|
||||
|
||||
if lookforpets and D.profile.Scan_Pets and GUID == UnitToGUID["raidpet"..i] then
|
||||
unit = "raidpet"..i;
|
||||
break;
|
||||
end
|
||||
|
||||
if foundmembers == raidnum then
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not unit then
|
||||
GUIDToUnit_ScannedAll = true;
|
||||
end
|
||||
|
||||
self[GUID] = unit;
|
||||
|
||||
return self[GUID];
|
||||
end };
|
||||
--}}}
|
||||
|
||||
|
||||
local function IsInSkipList ( GUID, group, classNum ) -- {{{
|
||||
if (D.Status.InternalSkipList[GUID] or D.Status.InternalSkipList[group] or D.Status.InternalSkipList[classNum]) then
|
||||
return true;
|
||||
end
|
||||
|
||||
return false;
|
||||
end -- }}}
|
||||
|
||||
local function IsInSkipOrPriorList( GUID, group, classNum ) --{{{
|
||||
|
||||
if (IsInSkipList ( GUID, group, classNum )) then
|
||||
return true;
|
||||
end
|
||||
|
||||
if (D.Status.InternalPrioList[GUID] or D.Status.InternalPrioList[group] or D.Status.InternalPrioList[classNum]) then
|
||||
return true;
|
||||
end
|
||||
|
||||
return false;
|
||||
end --}}}
|
||||
|
||||
|
||||
local ClassPrio = { };
|
||||
local GroupsPrio = { };
|
||||
|
||||
local currentGroup = 0; -- the group we are in
|
||||
|
||||
local function GetUnitDefaultPriority (RaidId, UnitGroup) -- {{{
|
||||
|
||||
if (not UnitGroup) then
|
||||
return RaidId;
|
||||
end
|
||||
|
||||
if (UnitGroup >= currentGroup) then
|
||||
return ( 8 - ( UnitGroup - currentGroup ) ) * 100 + (41 - RaidId);
|
||||
end
|
||||
|
||||
if (UnitGroup < currentGroup) then
|
||||
return (currentGroup - UnitGroup) * 100 + (41 - RaidId);
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
local function GetUnitPriority(Unit, RaidId, UnitGroup, UNClass, IsPet) -- {{{
|
||||
|
||||
-- A little explanation of the principle behind this function {{{
|
||||
--[=[ ****************************************************************************
|
||||
levels of priority:
|
||||
|
||||
0 --> PriorityList
|
||||
1 --> Group
|
||||
2 --> Class
|
||||
3 --> Default (Decursive "natural" order: our group, groups after, groups before)
|
||||
4 --> Pets
|
||||
|
||||
- 8 groups with 5 persons maximum per group
|
||||
- 10 classes with 80 persons max for each class (Pets may be counted)
|
||||
- 80 persons for default (including possible pets)
|
||||
|
||||
Priority list: 1,000,000 till 100,000,000
|
||||
Group indexes: 10,000, 20,000, 30,000, till 80,000
|
||||
class indexes: 1,000, 2,000, 3,000, till 10,000
|
||||
default indexes: 100 to 800 (player's index will be 900)
|
||||
pet indexes: Same as above but * -1
|
||||
|
||||
We make additions, exemple:
|
||||
- Our current group is the group 7
|
||||
- The resulting default groups priorities are:
|
||||
7:800 8: 700, 1:600, 2: 500, 3: 400, 4: 300, 5: 200, 6:100
|
||||
- Archarodim, Mage from Group 5 (23rd unit of the raid)
|
||||
- Unit Archarodim priority is 223
|
||||
- Class Mage priority is 4000
|
||||
- Group 5 priority is 20000
|
||||
|
||||
--> Archarodim priority is 200 + 23 + 4000 + 20000 = 24223
|
||||
**************************************************************************** }}} ]=]
|
||||
|
||||
-- Get Decursive's natural default priority of the unit
|
||||
local UnitPriority = GetUnitDefaultPriority(RaidId, UnitGroup);
|
||||
|
||||
-- Get the class priority if available
|
||||
if ( UNClass and ClassPrio[ DC.ClassUNameToNum [UNClass] ] ) then
|
||||
UnitPriority = UnitPriority + ( 10 + 1 - ClassPrio[DC.ClassUNameToNum [UNClass]]) * 1000; -- XXX 10 (Deathknight) is no good
|
||||
end
|
||||
|
||||
-- Get the group priority if available
|
||||
if (UnitGroup and GroupsPrio[UnitGroup]) then
|
||||
UnitPriority = UnitPriority + (8 + 1 - GroupsPrio[UnitGroup]) * 10000;
|
||||
end
|
||||
|
||||
-- Get the priority list index if available
|
||||
if not IsPet then
|
||||
local Unit_GUID = UnitToGUID[Unit];
|
||||
|
||||
local PrioListIndex = 100;
|
||||
|
||||
-- get the higher of the three...
|
||||
if (D.Status.InternalPrioList[Unit_GUID] and D.Status.InternalPrioList[Unit_GUID] < PrioListIndex) then
|
||||
PrioListIndex = D.Status.InternalPrioList[Unit_GUID];
|
||||
end
|
||||
|
||||
if (D.Status.InternalPrioList[UnitGroup] and D.Status.InternalPrioList[UnitGroup] < PrioListIndex) then
|
||||
PrioListIndex = D.Status.InternalPrioList[UnitGroup];
|
||||
end
|
||||
|
||||
if (D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ] and D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ] < PrioListIndex) then
|
||||
PrioListIndex = D.Status.InternalPrioList[ DC.ClassUNameToNum [UNClass] ];
|
||||
end
|
||||
|
||||
|
||||
if ( PrioListIndex < 100) then
|
||||
UnitPriority = UnitPriority + (100 + 1 - PrioListIndex) * 1000000;
|
||||
end
|
||||
end
|
||||
|
||||
if IsPet then
|
||||
UnitPriority = UnitPriority * -1;
|
||||
end
|
||||
|
||||
return UnitPriority;
|
||||
end -- }}}
|
||||
|
||||
|
||||
local RaidRosterCache = {};
|
||||
|
||||
local pet;
|
||||
function D:GetUnitArray() --{{{
|
||||
-- if the groups composition did not changed
|
||||
if not self.Groups_datas_are_invalid or not self.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
self.Groups_datas_are_invalid = false;
|
||||
|
||||
self:Debug ("|cFFFF44FF-->|r Updating Units Array");
|
||||
|
||||
local pGUID;
|
||||
raidnum = GetNumRaidMembers();
|
||||
|
||||
if DC.MyGUID == "NONE" then
|
||||
|
||||
self:Debug("|cFFFF0000DC.MyGUID was nil!!|r");
|
||||
|
||||
DC.MyGUID = (UnitGUID("player"));
|
||||
|
||||
if not DC.MyGUID then
|
||||
DC.MyGUID = "NONE";
|
||||
self:Debug("|cFFFF0000DC.MyGUID is STILL nil!!|r");
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local MyGUID = DC.MyGUID;
|
||||
|
||||
-- clear all the arrays
|
||||
local Status = self.Status;
|
||||
Status.InternalPrioList = {}; -- these lists contains only units currently present
|
||||
Status.InternalSkipList = {};
|
||||
SortingTable = {};
|
||||
Status.Unit_Array_GUIDToUnit = {};
|
||||
Status.Unit_Array_UnitToGUID = {};
|
||||
|
||||
UnitToGUID = setmetatable(UnitToGUID, UnitToGUID_mt); -- we could simply erase this one to prevent garbage
|
||||
GUIDToUnit = setmetatable(GUIDToUnit, GUIDToUnit_mt); -- this one cannot be erased (memory leak due to GUID...)
|
||||
GUIDToUnit_ScannedAll = false;
|
||||
|
||||
if Status.TestLayout then
|
||||
D:GetFakeUnit_array ();
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
local unit;
|
||||
|
||||
|
||||
-- ############### PARSE PRIO AND SKIP LIST ###############
|
||||
|
||||
GroupsPrio, ClassPrio = D:MakeGroupsAndClassPrio();
|
||||
|
||||
lookforpets = false;
|
||||
|
||||
-- First clean and load the prioritylist (remove missing units)
|
||||
for i, ListEntry in ipairs(self.profile.PriorityList) do
|
||||
|
||||
-- first add GUIDs present in our raid group
|
||||
if (type(ListEntry) == "string") then
|
||||
unit = GUIDToUnit[ListEntry];
|
||||
if (unit) then
|
||||
Status.InternalPrioList[ListEntry] = i;
|
||||
end
|
||||
|
||||
else -- if ListEntry is not a string, then it's a number
|
||||
-- representing the groups or the classes
|
||||
|
||||
Status.InternalPrioList[ListEntry] = i;
|
||||
end
|
||||
end
|
||||
|
||||
-- Get a cleaned skip list
|
||||
for i, ListEntry in ipairs(self.profile.SkipList) do
|
||||
if (type(ListEntry) == "string") then
|
||||
unit = GUIDToUnit[ListEntry];
|
||||
if (unit) then
|
||||
Status.InternalSkipList[ListEntry] = i;
|
||||
end
|
||||
else
|
||||
Status.InternalSkipList[ListEntry] = i;
|
||||
end
|
||||
end
|
||||
lookforpets = true;
|
||||
|
||||
|
||||
-- if we are not in a raid but in a party
|
||||
if (raidnum == 0) then
|
||||
currentGroup = 1; -- this is used to compute the default priorities
|
||||
-- Add the player to the main list if needed
|
||||
if not IsInSkipOrPriorList(MyGUID, false, DC.ClassUNameToNum[DC.MyClass]) then
|
||||
-- the player is not in a priority state, add to default prio
|
||||
SortingTable["player"] = 900;
|
||||
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
||||
|
||||
|
||||
elseif not IsInSkipList(MyGUID, false, DC.ClassUNameToNum[DC.MyClass]) then
|
||||
-- The player is contained within a priority rule
|
||||
SortingTable["player"] = GetUnitPriority ("player", 1, 1, DC.MyClass );
|
||||
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
||||
|
||||
end
|
||||
|
||||
local unit = "";
|
||||
|
||||
-- add the party members and their pets... if they exist
|
||||
for i = 1, 4 do
|
||||
unit = "party"..i;
|
||||
|
||||
if (UnitExists(unit)) then
|
||||
|
||||
pGUID = UnitToGUID[unit];
|
||||
|
||||
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
||||
pGUID = unit;
|
||||
end
|
||||
|
||||
-- check the GUID to see if we skip
|
||||
if (not IsInSkipList(pGUID, nil, DC.ClassUNameToNum[(select(2, UnitClass(unit)))])) then
|
||||
|
||||
Status.Unit_Array_GUIDToUnit[pGUID] = unit;
|
||||
|
||||
SortingTable[unit] = GetUnitPriority (unit, i + 1, 1, (select(2, UnitClass(unit)) ) );
|
||||
|
||||
end
|
||||
|
||||
if ( self.profile.Scan_Pets ) then
|
||||
|
||||
pet = "partypet"..i;
|
||||
|
||||
if (UnitExists(pet)) then
|
||||
pGUID = UnitToGUID[pet];
|
||||
|
||||
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
||||
pGUID = pet;
|
||||
end
|
||||
|
||||
SortingTable[pet] = GetUnitPriority (pet, i + 1, 1, (select(2, UnitClass(pet))), true);
|
||||
Status.Unit_Array_GUIDToUnit[pGUID] = pet;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- add our own pet
|
||||
if ( self.profile.Scan_Pets ) then
|
||||
if (UnitExists("pet")) then
|
||||
SortingTable["pet"] = -900;
|
||||
Status.Unit_Array_GUIDToUnit[UnitToGUID["pet"]] = "pet";
|
||||
end
|
||||
end
|
||||
|
||||
if ( raidnum > 0 ) then -- if we are in a raid
|
||||
currentGroup = 0;
|
||||
local rName, rGroup, rClass, GUID;
|
||||
local CaheID = 1; -- make an ordered table
|
||||
local excluded = 0;
|
||||
local playerPrio = 900;
|
||||
|
||||
-- Cache the raid roster info eliminating useless info and already listed members
|
||||
for i = 1, MAX_RAID_MEMBERS do
|
||||
rName, _, rGroup, _, _, rClass = GetRaidRosterInfo(i);
|
||||
GUID = UnitToGUID["raid"..i];
|
||||
|
||||
-- add all except member to skip
|
||||
if not IsInSkipList(GUID, rGroup, DC.ClassUNameToNum[rClass]) then
|
||||
|
||||
if (rName) then -- (at log-in GetRaidRosterInfo() returns garbage)
|
||||
|
||||
if (not RaidRosterCache[CaheID]) then
|
||||
RaidRosterCache[CaheID] = {};
|
||||
end
|
||||
|
||||
RaidRosterCache[CaheID].rName = rName;
|
||||
RaidRosterCache[CaheID].rGroup = rGroup;
|
||||
RaidRosterCache[CaheID].rClass = rClass;
|
||||
RaidRosterCache[CaheID].rIndex = i;
|
||||
RaidRosterCache[CaheID].rGUID = GUID;
|
||||
CaheID = CaheID + 1;
|
||||
end
|
||||
else
|
||||
excluded = excluded + 1;
|
||||
end
|
||||
|
||||
-- find our group (a whole iteration is required, raid info are not ordered) -- wrong, the player is always the last now but never trust Blizzard...
|
||||
if currentGroup==0 and GUID == MyGUID then -- anyway they do the same thing in PlayerFrame.lua...
|
||||
currentGroup = rGroup;
|
||||
playerPrio = GetUnitPriority ("player", i, rGroup, rClass, false);
|
||||
end
|
||||
|
||||
if CaheID + excluded > raidnum then -- we found all the units
|
||||
RaidRosterCache[CaheID] = false;
|
||||
break;
|
||||
end
|
||||
end
|
||||
|
||||
-- Add the player to the main list if needed
|
||||
if (not IsInSkipOrPriorList(MyGUID, currentGroup, DC.ClassUNameToNum[DC.MyClass])) then
|
||||
SortingTable["player"] = 900;
|
||||
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
||||
else -- well let's see if people complains that they cannot exclude themself...
|
||||
SortingTable["player"] = playerPrio;
|
||||
Status.Unit_Array_GUIDToUnit[MyGUID] = "player";
|
||||
end
|
||||
|
||||
-- Now we have a cache without the units we want to skip
|
||||
local TempID;
|
||||
for _, raidMember in ipairs(RaidRosterCache) do
|
||||
|
||||
if not raidMember then break; end;
|
||||
|
||||
-- put each raid member with the right priority in our sorting table
|
||||
if not Status.Unit_Array_GUIDToUnit[raidMember.rGUID] then
|
||||
|
||||
TempID = "raid"..raidMember.rIndex;
|
||||
|
||||
SortingTable[TempID] = GetUnitPriority (TempID, raidMember.rIndex, raidMember.rGroup, raidMember.rClass, false);
|
||||
Status.Unit_Array_GUIDToUnit[raidMember.rGUID] = TempID;
|
||||
end
|
||||
|
||||
if ( self.profile.Scan_Pets ) then
|
||||
local pet = "";
|
||||
pet = "raidpet"..raidMember.rIndex;
|
||||
|
||||
if ( UnitExists(pet) ) then
|
||||
|
||||
pGUID = UnitToGUID[pet];
|
||||
|
||||
if (not pGUID) then -- at logon sometimes pGUID is nil...
|
||||
pGUID = pet;
|
||||
end
|
||||
|
||||
-- add it only if not already in (could be the player pet...)
|
||||
if (not Status.Unit_Array_GUIDToUnit[pGUID]) then
|
||||
SortingTable[pet] = GetUnitPriority (pet, raidMember.rIndex, raidMember.rGroup, (select(2,UnitClass(pet))), true);
|
||||
Status.Unit_Array_GUIDToUnit[pGUID] = pet;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end -- END if we are in a raid
|
||||
|
||||
-- NEW focus management
|
||||
-- there is a focus and its not hostile in the first place
|
||||
if UnitExists("focus") and (not UnitCanAttack("focus", "player") or UnitIsFriend("focus", "player")) then
|
||||
pGUID = UnitToGUID["focus"]
|
||||
-- the unit is not registered somewhere else yet
|
||||
if not Status.Unit_Array_GUIDToUnit[pGUID] then
|
||||
SortingTable["focus"] = -1; -- add it at the end...
|
||||
Status.Unit_Array_GUIDToUnit[pGUID] = "focus";
|
||||
end
|
||||
end
|
||||
|
||||
-- we use a hash-key style table for Status.Unit_Array_GUIDToUnit because it allows us
|
||||
-- to not care if we add a same unit several times (speed optimization)
|
||||
-- but we cannot use sort unless indexes are integer so:
|
||||
Status.Unit_Array = {}
|
||||
local GUID;
|
||||
for GUID, unit in pairs(Status.Unit_Array_GUIDToUnit) do -- /!\ PAIRS not iPAIRS
|
||||
t_insert(Status.Unit_Array, unit);
|
||||
|
||||
Status.Unit_Array_UnitToGUID[unit] = GUID; -- just a useful table, not used here :)
|
||||
end
|
||||
|
||||
table.sort(Status.Unit_Array, function (a,b)
|
||||
if (not (SortingTable[a] < 0 and SortingTable[b] < 0)) then -- one of the values is > 0
|
||||
return SortingTable[b] < SortingTable[a];
|
||||
else -- both are < 0
|
||||
return SortingTable[a] < SortingTable[b];
|
||||
end
|
||||
end);
|
||||
|
||||
|
||||
Status.UnitNum = #Status.Unit_Array;
|
||||
|
||||
UnitToGUID = {};
|
||||
GUIDToUnit = {};
|
||||
D.Status.GroupUpdatedOn = D:NiceTime(); -- It's used in UNIT_AURA event handler to trigger a rescan if the array is found inacurate
|
||||
|
||||
self:Debug ("|cFFFF44FF-->|r Update complete!", Status.UnitNum);
|
||||
return;
|
||||
end
|
||||
|
||||
function D:GetFakeUnit_array ()
|
||||
|
||||
if not D.Status.TestLayout then
|
||||
return;
|
||||
end
|
||||
|
||||
self:Debug ("|cFFFF22FF-->|r Creating fake Units Array");
|
||||
|
||||
local Status = self.Status;
|
||||
Status.Unit_Array_GUIDToUnit[DC.MyGUID] = "player";
|
||||
|
||||
Status.Unit_Array = {}
|
||||
|
||||
for i = 1, D.Status.TestLayoutUNum - 1 do -- the player is always in so we remove one here.
|
||||
Status.Unit_Array_GUIDToUnit["raid" .. i .. "GUID"] = "raid" .. i;
|
||||
end
|
||||
|
||||
local GUID;
|
||||
for GUID, unit in pairs(Status.Unit_Array_GUIDToUnit) do -- /!\ PAIRS not iPAIRS
|
||||
t_insert(Status.Unit_Array, unit);
|
||||
|
||||
Status.Unit_Array_UnitToGUID[unit] = GUID; -- just a useful table, not used here :)
|
||||
end
|
||||
|
||||
table.sort(Status.Unit_Array);
|
||||
|
||||
Status.UnitNum = #Status.Unit_Array;
|
||||
D.Status.GroupUpdatedOn = D:NiceTime(); -- It's used in UNIT_AURA event handler to trigger a rescan if the array is found inacurate
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--}}}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
T._LoadedFiles["Dcr_Raid.lua"] = "2.5.1-6-gd3885c5";
|
||||
|
||||
-- "Your God is dead and no one cares"
|
||||
-- "If there is a Hell I'll see you there"
|
||||
@@ -0,0 +1,601 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Decursive.xml"] or not T._LoadedFiles["Decursive.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Decursive.xml or Decursive.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-08-12 04:50:10 +0200 (mar., 12 août 2008) $", "$Revision: 80230 $");
|
||||
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
local _;
|
||||
local _G = _G;
|
||||
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local table = _G.table;
|
||||
local str_format = _G.string.format;
|
||||
local str_sub = _G.string.gsub;
|
||||
local t_insert = _G.table.insert;
|
||||
|
||||
-- Dcr_ListFrameTemplate specific internal functions {{{
|
||||
function D.ListFrameTemplate_OnLoad(frame)
|
||||
frame.ScrollFrame = _G[frame:GetName().."ScrollFrame"];
|
||||
frame.ScrollBar = _G[frame.ScrollFrame:GetName().."ScrollBar"];
|
||||
frame.ScrollFrame.offset = 0;
|
||||
end
|
||||
|
||||
function D:ListFrameScrollFrameTemplate_OnMouseWheel(frame, value)
|
||||
local scrollBar = _G[frame:GetName().."ScrollBar"];
|
||||
local min, max = scrollBar:GetMinMaxValues();
|
||||
if ( value > 0 ) then
|
||||
if (IsShiftKeyDown() ) then
|
||||
scrollBar:SetValue(min);
|
||||
else
|
||||
scrollBar:SetValue(scrollBar:GetValue() - scrollBar:GetValueStep());
|
||||
end
|
||||
else
|
||||
if (IsShiftKeyDown() ) then
|
||||
scrollBar:SetValue(max);
|
||||
else
|
||||
scrollBar:SetValue(scrollBar:GetValue() + scrollBar:GetValueStep());
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
-- Dcr_ListFrameTemplate specific handlers {{{
|
||||
|
||||
function D.PrioSkipListFrame_OnUpdate(frame) --{{{
|
||||
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
if (frame.UpdateYourself) then
|
||||
frame.UpdateYourself = false;
|
||||
local baseName = frame:GetName();
|
||||
local size;
|
||||
|
||||
if (frame.Priority) then
|
||||
size = table.getn(D.profile.PriorityList);
|
||||
else
|
||||
size = table.getn(D.profile.SkipList);
|
||||
end
|
||||
-- D:Debug("PrioSkipListFrame_OnUpdate executed", size, this.ScrollFrame.offset);
|
||||
|
||||
local i;
|
||||
for i = 1, 10 do
|
||||
local id = ""..i;
|
||||
if (i < 10) then
|
||||
id = "0"..i;
|
||||
end
|
||||
local btn = _G[baseName.."Index"..id];
|
||||
|
||||
btn:SetID( i + frame.ScrollFrame.offset);
|
||||
D:PrioSkipListEntry_Update(btn);
|
||||
|
||||
if (i <= size) then
|
||||
btn:Show();
|
||||
else
|
||||
btn:Hide();
|
||||
end
|
||||
end
|
||||
frame.ScrollUpdateFunc(_G[baseName.."ScrollFrame"], true);
|
||||
end
|
||||
|
||||
end --}}}
|
||||
|
||||
function D:PrioSkipListEntryTemplate_OnClick(frame) --{{{
|
||||
-- D:PrintLiteral(arg1);
|
||||
|
||||
local list;
|
||||
local UnitNum;
|
||||
if (frame:GetParent().Priority) then
|
||||
list = D.profile.PriorityList;
|
||||
UnitNum = getn(D.profile.PriorityList);
|
||||
else
|
||||
list = D.profile.SkipList;
|
||||
UnitNum = getn(D.profile.SkipList);
|
||||
end
|
||||
|
||||
|
||||
local id = frame:GetID();
|
||||
if (id) then
|
||||
if (IsControlKeyDown()) then
|
||||
if (frame:GetParent().Priority) then
|
||||
D:RemoveIDFromPriorityList(id);
|
||||
else
|
||||
D:RemoveIDFromSkipList(id);
|
||||
end
|
||||
elseif (UnitNum > 1) then
|
||||
local previousUnit_ID, previousUnit, nextUnit_ID, nextUnit, currentUnit;
|
||||
|
||||
--if (id == 0) then
|
||||
-- previousUnit_ID = UnitNum; else
|
||||
previousUnit_ID = id - 1;
|
||||
--end
|
||||
--if (id == UnitNum - 1) then
|
||||
--nextUnit_ID = 0; else
|
||||
nextUnit_ID = id + 1;
|
||||
--end
|
||||
|
||||
previousUnit = list[previousUnit_ID];
|
||||
nextUnit = list[nextUnit_ID ];
|
||||
currentUnit = list[id];
|
||||
|
||||
|
||||
if (arg1=="RightButton" and IsShiftKeyDown()) then -- move at the bottom
|
||||
table.remove(list, id);
|
||||
table.insert(list, UnitNum, currentUnit);
|
||||
|
||||
elseif (arg1=="LeftButton" and IsShiftKeyDown()) then -- move at the top
|
||||
table.remove(list, id);
|
||||
table.insert(list, 1, currentUnit);
|
||||
elseif (arg1=="LeftButton" and id ~= 1) then -- unit gets higher
|
||||
D:Debug("upping %s of id %d", list[id], id);
|
||||
list[previousUnit_ID] = list[id];
|
||||
list[id] = previousUnit;
|
||||
elseif (arg1=="RightButton" and id ~= UnitNum) then -- unit gets lower
|
||||
D:Debug("downing %s of id %d", list[id], id);
|
||||
list[nextUnit_ID] = list[id];
|
||||
list[id] = nextUnit;
|
||||
elseif (arg1=="MiddleButton") then
|
||||
|
||||
end
|
||||
frame:GetParent().UpdateYourself = true;
|
||||
end
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("PrioSkipListEntryTemplate_OnClick");
|
||||
else
|
||||
D:Debug("No ID");
|
||||
end
|
||||
|
||||
end --}}}
|
||||
|
||||
function D:PrioSkipListEntry_Update(Entry) --{{{
|
||||
local id = Entry:GetID();
|
||||
if (id) then
|
||||
--D:Debug("PrioSkipListEntry_Update executed");
|
||||
local name, classname, GUIDorNum;
|
||||
if (Entry:GetParent().Priority) then
|
||||
GUIDorNum = D.profile.PriorityList[id];
|
||||
classname = D.profile.PriorityListClass[GUIDorNum];
|
||||
name = D.profile.PrioGUIDtoNAME[GUIDorNum];
|
||||
else
|
||||
GUIDorNum = D.profile.SkipList[id];
|
||||
classname = D.profile.SkipListClass[GUIDorNum];
|
||||
name = D.profile.SkipGUIDtoNAME[GUIDorNum];
|
||||
end
|
||||
if not classname then
|
||||
classname = "WARRIOR";
|
||||
end
|
||||
if (GUIDorNum) then
|
||||
if (type(GUIDorNum) == "number") then
|
||||
if (GUIDorNum < 10) then
|
||||
name = str_format("[ %s %s ]", L["STR_GROUP"], GUIDorNum);
|
||||
else
|
||||
name = str_format("[ %s ]", DC.ClassNumToLName[GUIDorNum]);
|
||||
end
|
||||
end
|
||||
Entry:SetText(id.." - "..D:ColorText(name, "FF"..DC.HexClassColor[classname]));
|
||||
else
|
||||
Entry:SetText("Error - NO name!");
|
||||
end
|
||||
else
|
||||
Entry:SetText("Error - No ID!");
|
||||
end
|
||||
end --}}}
|
||||
|
||||
function D.PrioSkipList_ScrollFrame_Update (ScrollFrame) -- {{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
local maxentry;
|
||||
local UpdateListOnceDone = true;
|
||||
local DirectCall = false;
|
||||
|
||||
D:Debug("ScrollFrame is a %s", type(ScrollFrame));
|
||||
if (not ScrollFrame) then
|
||||
--ScrollFrame = this; -- Called from the scrollbar frame handler
|
||||
else
|
||||
--UpdateListOnceDone = false; -- The function was called from the list update function
|
||||
DirectCall = true;
|
||||
end
|
||||
|
||||
if (not ScrollFrame.UpdateYourself) then
|
||||
ScrollFrame.UpdateYourself = true;
|
||||
return;
|
||||
end
|
||||
|
||||
if (ScrollFrame:GetParent().Priority) then
|
||||
maxentry = table.getn(D.profile.PriorityList);
|
||||
else
|
||||
maxentry = table.getn(D.profile.SkipList);
|
||||
end
|
||||
|
||||
FauxScrollFrame_Update(ScrollFrame,maxentry,10,16);
|
||||
|
||||
|
||||
if (UpdateListOnceDone) then
|
||||
ScrollFrame.UpdateYourself = false; -- prevent this function to re-execute unecessarily
|
||||
ScrollFrame:GetParent().UpdateYourself = true;
|
||||
end
|
||||
D:Debug("PrioSkipList_ScrollFrame_Update executed for %s", ScrollFrame:GetName());
|
||||
end -- }}}
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
-- list specific management functions {{{
|
||||
-------------------------------------------------------------------------------
|
||||
D.Status.GroupsPrio = { };
|
||||
D.Status.ClassPrio = { };
|
||||
function D:MakeGroupsAndClassPrio ()
|
||||
|
||||
if D.Status.PrioChanged then
|
||||
local GroupsPrio = {};
|
||||
local ClassPrio = {};
|
||||
|
||||
for i, ListEntry in ipairs(self.profile.PriorityList) do
|
||||
if (type(ListEntry) ~= "string") then
|
||||
if (ListEntry < 10) then
|
||||
t_insert(GroupsPrio, ListEntry);
|
||||
else
|
||||
t_insert(ClassPrio, ListEntry);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Reverse GroupsPrio and ClassPrio so we can have something useful...
|
||||
D.Status.GroupsPrio = self:tReverse(GroupsPrio);
|
||||
D.Status.ClassPrio = self:tReverse(ClassPrio);
|
||||
D.Status.PrioChanged = false;
|
||||
end
|
||||
|
||||
return D.Status.GroupsPrio, D.Status.ClassPrio;
|
||||
end
|
||||
|
||||
|
||||
function D:AddTargetToPriorityList() --{{{
|
||||
D:Debug( "Adding the target to the priority list");
|
||||
return D:AddUnitToPriorityList("target", true);
|
||||
end --}}}
|
||||
|
||||
function D:AddUnitToPriorityList( unit, check ) --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return false;
|
||||
end
|
||||
|
||||
if (#D.profile.PriorityList > 99) then
|
||||
return false;
|
||||
end
|
||||
|
||||
if (not check or UnitExists(unit)) then
|
||||
if (type(unit) == "number" or UnitIsPlayer(unit)) then
|
||||
D:Debug("adding %s", unit);
|
||||
|
||||
--local name;
|
||||
local GUIDorNum;
|
||||
|
||||
if type(unit) == "number" then
|
||||
GUIDorNum = unit;
|
||||
else
|
||||
--name = (D:UnitName(unit));
|
||||
GUIDorNum = UnitGUID(unit);
|
||||
--if name == DC.UNKNOWN then
|
||||
if not GUIDorNum then
|
||||
return false;
|
||||
end
|
||||
end
|
||||
|
||||
if D.profile.PrioGUIDtoNAME[GUIDorNum] then
|
||||
return false;
|
||||
end
|
||||
--[[
|
||||
for _, pname in pairs(D.profile.PriorityList) do
|
||||
if (name == pname) then
|
||||
return false;
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
table.insert(D.profile.PriorityList,GUIDorNum);
|
||||
|
||||
|
||||
|
||||
if (type(unit) == "string") then
|
||||
_, D.profile.PriorityListClass[GUIDorNum] = UnitClass(unit);
|
||||
D.profile.PrioGUIDtoNAME[GUIDorNum] = (D:UnitName(unit));
|
||||
elseif unit > 10 then
|
||||
D.profile.PriorityListClass[unit] = DC.ClassNumToUName[unit];
|
||||
D.profile.PrioGUIDtoNAME[GUIDorNum] = str_format("[ %s ]", DC.ClassNumToLName[GUIDorNum]);
|
||||
else
|
||||
D.profile.PrioGUIDtoNAME[GUIDorNum] = str_format("[ %s %s ]", L["STR_GROUP"], GUIDorNum);
|
||||
end
|
||||
|
||||
DecursivePriorityListFrame.UpdateYourself = true;
|
||||
D:Debug("Unit %s added to the prio list", GUIDorNum);
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("AddUnitToPriorityList");
|
||||
return true;
|
||||
else
|
||||
D:Debug("Unit is not a player:", unit, check, UnitExists(unit));
|
||||
if (not unit) then
|
||||
error("D:AddUnitToPriorityList: bad argument #1 'unit' must be!",2);
|
||||
end
|
||||
end
|
||||
else
|
||||
D:Debug("Unit does not exist");
|
||||
end
|
||||
return false;
|
||||
end --}}}
|
||||
|
||||
function D:RemoveIDFromPriorityList(id) --{{{
|
||||
|
||||
D.profile.PriorityListClass[ D.profile.PriorityList[id] ] = nil; -- remove it from the table
|
||||
D.profile.PrioGUIDtoNAME[ D.profile.PriorityList[id]] = nil;
|
||||
|
||||
table.remove( D.profile.PriorityList, id );
|
||||
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("RemoveIDFromPriorityList");
|
||||
DecursivePriorityListFrame.UpdateYourself = true;
|
||||
end --}}}
|
||||
|
||||
function D:ClearPriorityList() --{{{
|
||||
D.profile.PriorityList = {};
|
||||
D.profile.PriorityListClass = {};
|
||||
D.profile.PrioGUIDtoNAME = {};
|
||||
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("ClearPriorityList");
|
||||
DecursivePriorityListFrame.UpdateYourself = true;
|
||||
end --}}}
|
||||
|
||||
function D:AddTargetToSkipList() --{{{
|
||||
D:Debug( "Adding the target to the Skip list");
|
||||
return D:AddUnitToSkipList("target");
|
||||
end --}}}
|
||||
|
||||
function D:AddUnitToSkipList( unit) --{{{
|
||||
|
||||
if (#D.profile.SkipList > 99) then
|
||||
return false;
|
||||
end
|
||||
|
||||
if (not check or UnitExists(unit)) then
|
||||
if (type(unit) == "number" or UnitIsPlayer(unit)) then
|
||||
D:Debug("adding %s", unit);
|
||||
|
||||
--local name;
|
||||
local GUIDorNum;
|
||||
|
||||
|
||||
if type(unit) == "number" then
|
||||
GUIDorNum = unit;
|
||||
else
|
||||
--name = (D:UnitName( unit));
|
||||
GUIDorNum = UnitGUID(unit);
|
||||
--if name == DC.UNKNOWN then
|
||||
if not GUIDorNum then
|
||||
return false;
|
||||
end
|
||||
end
|
||||
|
||||
if D.profile.SkipGUIDtoNAME[GUIDorNum] then
|
||||
return false;
|
||||
end
|
||||
--[[
|
||||
for _, pname in pairs(D.profile.SkipList) do
|
||||
if (name == pname) then
|
||||
return false;
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
table.insert(D.profile.SkipList,GUIDorNum);
|
||||
|
||||
if (type(unit) == "string") then
|
||||
_, D.profile.SkipListClass[GUIDorNum] = UnitClass(unit);
|
||||
D.profile.SkipGUIDtoNAME[GUIDorNum] = (D:UnitName(unit));
|
||||
elseif unit > 10 then
|
||||
D.profile.SkipListClass[unit] = DC.ClassNumToUName[unit];
|
||||
D.profile.SkipGUIDtoNAME[GUIDorNum] = str_format("[ %s ]", DC.ClassNumToLName[GUIDorNum]);
|
||||
else
|
||||
D.profile.SkipGUIDtoNAME[GUIDorNum] = str_format("[ %s %s ]", L["STR_GROUP"], GUIDorNum);
|
||||
end
|
||||
|
||||
DecursiveSkipListFrame.UpdateYourself = true;
|
||||
D:Debug("Unit %s added to the skip list", GUIDorNum);
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("AddUnitToSkipList");
|
||||
return true;
|
||||
else
|
||||
D:Debug("Unit is not a player:", unit);
|
||||
end
|
||||
else
|
||||
D:Debug("Unit does not exist");
|
||||
end
|
||||
return false;
|
||||
end --}}}
|
||||
|
||||
function D:RemoveIDFromSkipList(id) --{{{
|
||||
|
||||
D.profile.SkipListClass[ D.profile.SkipList[id] ] = nil; -- remove it from the table
|
||||
D.profile.SkipGUIDtoNAME[ D.profile.SkipList[id]] = nil;
|
||||
|
||||
|
||||
table.remove( D.profile.SkipList, id );
|
||||
|
||||
D.Status.PrioChanged = true;
|
||||
D:GroupChanged ("RemoveIDFromSkipList");
|
||||
DecursiveSkipListFrame.UpdateYourself = true;
|
||||
end --}}}
|
||||
|
||||
function D:ClearSkipList() --{{{
|
||||
local i;
|
||||
|
||||
D.profile.SkipList = {};
|
||||
D.profile.SkipListClass = {};
|
||||
D.profile.SkipGUIDtoNAME = {};
|
||||
|
||||
D.Status.PrioChanged = true;
|
||||
D.Groups_datas_are_invalid = true;
|
||||
D:GroupChanged ("ClearSkipList");
|
||||
DecursiveSkipListFrame.UpdateYourself = true;
|
||||
end --}}}
|
||||
|
||||
|
||||
function D:IsInPriorList (GUID) --{{{
|
||||
return self.Status.InternalPrioList[GUID] or false;
|
||||
|
||||
--[=[
|
||||
for _, PriorName in pairs(D.profile.PrioGUIDtoNAME) do
|
||||
if (PriorName == name) then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
return false;
|
||||
--]=]
|
||||
end --}}}
|
||||
|
||||
function D:IsInSkipList (name) --{{{
|
||||
return self.Status.InternalSkipList[GUID] or false;
|
||||
--[=[
|
||||
for _, SkipName in pairs(D.profile.SkipGUIDtoNAME) do
|
||||
if (SkipName == name) then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
return false
|
||||
--]=]
|
||||
end --}}}
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
|
||||
|
||||
function D:PopulateButtonPress(frame) --{{{
|
||||
local PopulateFrame = frame:GetParent();
|
||||
local UppedClass = "";
|
||||
|
||||
if (IsShiftKeyDown() and frame.ClassType) then
|
||||
|
||||
-- UnitClass returns uppercased class...
|
||||
UppedClass = string.upper(frame.ClassType);
|
||||
|
||||
D:Debug("Populate called for %s", frame.ClassType);
|
||||
-- for the class type stuff... we do party
|
||||
|
||||
local _, pclass = UnitClass("player");
|
||||
if (pclass == UppedClass) then
|
||||
PopulateFrame:addFunction("player");
|
||||
end
|
||||
|
||||
_, pclass = UnitClass("party1");
|
||||
if (pclass == UppedClass) then
|
||||
PopulateFrame:addFunction("party1");
|
||||
end
|
||||
_, pclass = UnitClass("party2");
|
||||
if (pclass == UppedClass) then
|
||||
PopulateFrame:addFunction("party2");
|
||||
end
|
||||
_, pclass = UnitClass("party3");
|
||||
if (pclass == UppedClass) then
|
||||
PopulateFrame:addFunction("party3");
|
||||
end
|
||||
_, pclass = UnitClass("party4");
|
||||
if (pclass == UppedClass) then
|
||||
PopulateFrame:addFunction("party4");
|
||||
end
|
||||
end
|
||||
|
||||
local i, pgroup, pclass;
|
||||
|
||||
|
||||
if (IsShiftKeyDown() and frame.ClassType) then
|
||||
D:Debug("Finding raid units with a macthing class");
|
||||
for index, unit in ipairs(D.Status.Unit_Array) do
|
||||
_, pclass = UnitClass(unit);
|
||||
|
||||
if (pclass == UppedClass) then
|
||||
D:Debug("found %s", pclass);
|
||||
PopulateFrame:addFunction(unit);
|
||||
end
|
||||
|
||||
end
|
||||
elseif (frame.ClassType) then
|
||||
PopulateFrame:addFunction(DC.ClassUNameToNum[string.upper(frame.ClassType)]);
|
||||
end
|
||||
|
||||
|
||||
local max = GetNumRaidMembers();
|
||||
|
||||
if (IsShiftKeyDown() and frame.GroupNumber and max > 0) then
|
||||
D:Debug("Finding raid units with a macthing group number");
|
||||
for i = 1, max do
|
||||
_, _, pgroup, _, _, pclass = GetRaidRosterInfo(i);
|
||||
|
||||
if (pgroup == frame.GroupNumber) then
|
||||
D:Debug("found %s in group %d", pclass, max);
|
||||
PopulateFrame:addFunction("raid"..i);
|
||||
end
|
||||
end
|
||||
elseif (not IsShiftKeyDown() and frame.GroupNumber) then
|
||||
PopulateFrame:addFunction(frame.GroupNumber);
|
||||
end
|
||||
|
||||
end --}}}
|
||||
|
||||
T._LoadedFiles["Dcr_lists.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,913 @@
|
||||
<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/">
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
<Script>
|
||||
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_lists.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_lists.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
-- Dcr:SetDateAndRevision("$Date: 2008-08-12 04:50:10 +0200 (mar., 12 août 2008) $", "$Revision: 80230 $");
|
||||
</Script>
|
||||
|
||||
<Button name="DcrSimpleTextOnlyButton" hidden="true" virtual="true">
|
||||
|
||||
<ButtonText name="$parentText" justifyH="LEFT" />
|
||||
|
||||
<NormalFont inherits="GameFontNormal" style="GameFontNormal" justifyH="LEFT" />
|
||||
<HighlightFont inherits="GameFontHighlight" style="GameFontHighlight" justifyH="LEFT" />
|
||||
<DisabledFont inherits="GameFontDisable" style="GameFontDisable" justifyH="LEFT" />
|
||||
|
||||
</Button>
|
||||
|
||||
<!-- Dcr_ListEntryTemplate {{{ -->
|
||||
<Button name="Dcr_ListEntryTemplate" inherits="DcrSimpleTextOnlyButton" hidden="true" virtual="true">
|
||||
|
||||
<Size>
|
||||
<AbsDimension x="140" y="16"/>
|
||||
</Size>
|
||||
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
self:RegisterForClicks('LeftButtonUp', 'RightButtonUp', 'MiddleButtonUp');
|
||||
</OnLoad>
|
||||
<OnClick>
|
||||
self:GetParent():EntryOnclick(self);
|
||||
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(Dcr.L["LIST_ENTRY_ACTIONS"], self:GetParent());
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<!-- }}} -->
|
||||
|
||||
<!-- Dcr_ListFrameTemplate {{{ -->
|
||||
<Frame name="Dcr_ListFrameTemplate" frameStrata="LOW" toplevel="true" enableMouse="true" EnableMouseWheel="true" movable="true" hidden="true" virtual="true" parent="UIParent">
|
||||
<Size>
|
||||
<AbsDimension x="170" y="210" />
|
||||
</Size>
|
||||
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" />
|
||||
</Anchors>
|
||||
|
||||
<TitleRegion setAllPoints="true"/>
|
||||
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
</Backdrop>
|
||||
|
||||
<Scripts>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(self.ListTitle, self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
Dcr.ListFrameTemplate_OnLoad(self);
|
||||
</OnLoad>
|
||||
<OnShow>
|
||||
self.UpdateYourself = true;
|
||||
</OnShow>
|
||||
|
||||
<OnUpdate>
|
||||
self.OnUpdate(self);
|
||||
</OnUpdate>
|
||||
</Scripts>
|
||||
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString name="$parentText" inherits="GameFontNormal" text="STR_DCR_PRIO">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
|
||||
<Frames>
|
||||
|
||||
<Button name="$parentClear" inherits="GameMenuButtonTemplate" text="C">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-20" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnShow>
|
||||
self:SetText(self:GetParent().ClearButtonText);
|
||||
</OnShow>
|
||||
<OnClick>
|
||||
self:GetParent().ClearFunction();
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(self:GetParent().ClearButtonTip, self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentClose" inherits="GameMenuButtonTemplate" text="X">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" relativeTo="$parentClear"/>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self:GetParent():Hide();
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(self:GetParent().CloseButtonTip, self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
|
||||
<Button name="$parentPopulate" inherits="GameMenuButtonTemplate" text="P">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativePoint="TOPLEFT" relativeTo="$parentClear"/>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["POPULATE"]);
|
||||
</OnLoad>
|
||||
<OnClick>
|
||||
DecursivePopulateListFrame.addFunction = self:GetParent().PopulateAddFunction;
|
||||
DecursivePopulateListFrameText:SetText(self:GetParent().PopulateFrameTitle);
|
||||
DecursivePopulateListFrame:Show();
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(Dcr.L["POPULATE_LIST"], self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentAdd" inherits="GameMenuButtonTemplate" text="+">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativePoint="TOPLEFT" relativeTo="$parentPopulate"/>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
if (self:GetParent():AddTargetFunc()) then
|
||||
|
||||
-- put the scroll bar at the bottom
|
||||
|
||||
local Slider = self:GetParent().ScrollBar;
|
||||
|
||||
local Scrollmin, scrollmax = Slider:GetMinMaxValues();
|
||||
|
||||
Slider:SetMinMaxValues(Scrollmin, scrollmax + Slider:GetValueStep());
|
||||
|
||||
Slider:SetValue(scrollmax + Slider:GetValueStep());
|
||||
end
|
||||
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
Dcr:DisplayTooltip(Dcr.L["BINDING_NAME_DCRPRADD"], self);
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<!-- our scrollbar-->
|
||||
<ScrollFrame name="$parentScrollFrame" inherits="FauxScrollFrameTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOMLEFT" relativeTo="$parentClear" >
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="LEFT">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
<Anchor point="BOTTOMRIGHT">
|
||||
<Offset>
|
||||
<AbsDimension x="-30" y="8"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnVerticalScroll>
|
||||
FauxScrollFrame_OnVerticalScroll(self, offset, 16, self:GetParent().ScrollUpdateFunc);
|
||||
</OnVerticalScroll>
|
||||
<OnShow>
|
||||
self.UpdateYourself = true;
|
||||
self:GetParent().ScrollUpdateFunc(self)
|
||||
</OnShow>
|
||||
<OnMouseWheel>
|
||||
Dcr:ListFrameScrollFrameTemplate_OnMouseWheel(self, delta);
|
||||
</OnMouseWheel>
|
||||
</Scripts>
|
||||
</ScrollFrame>
|
||||
<!-- end of our ScrollFrame-->
|
||||
|
||||
<Button name="$parentIndex01" id="1" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeTo="$parent" >
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="-40" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex02" id="2" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex01"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex03" id="3" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex02"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex04" id="4" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex03"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex05" id="5" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex04"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex06" id="6" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex05"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex07" id="7" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex06"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex08" id="8" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex07"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex09" id="9" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex08"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
<Button name="$parentIndex10" id="10" inherits="Dcr_ListEntryTemplate">
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="BOTTOMLEFT" relativeTo="$parentIndex09"/>
|
||||
</Anchors>
|
||||
</Button>
|
||||
|
||||
</Frames>
|
||||
</Frame>
|
||||
<!-- }}} -->
|
||||
|
||||
|
||||
<!-- DecursivePriorityListFrame {{{ -->
|
||||
<Frame name="DecursivePriorityListFrame" inherits="Dcr_ListFrameTemplate">
|
||||
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
Dcr.ListFrameTemplate_OnLoad(self);
|
||||
|
||||
self.ScrollUpdateFunc = Dcr.PrioSkipList_ScrollFrame_Update;
|
||||
|
||||
self.Priority = true;
|
||||
self.ListTitle = Dcr.L["PRIORITY_LIST"];
|
||||
_G[self:GetName().."Text"]:SetText(Dcr.L["STR_DCR_PRIO"]);
|
||||
|
||||
self.OnUpdate = Dcr.PrioSkipListFrame_OnUpdate;
|
||||
|
||||
self.ClearButtonText = Dcr.L["CLEAR_PRIO"];
|
||||
self.ClearButtonTip = Dcr.L["BINDING_NAME_DCRPRCLEAR"];
|
||||
self.ClearFunction = Dcr.ClearPriorityList;
|
||||
|
||||
self.CloseButtonTip = Dcr.L["BINDING_NAME_DCRPRSHOW"];
|
||||
|
||||
self.PopulateAddFunction = Dcr.AddUnitToPriorityList;
|
||||
self.PopulateFrameTitle = Dcr.L["PRIORITY_LIST"];
|
||||
|
||||
self.AddTargetFunc = Dcr.AddTargetToPriorityList;
|
||||
self.EntryOnclick = Dcr.PrioSkipListEntryTemplate_OnClick;
|
||||
|
||||
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- }}} -->
|
||||
|
||||
<!-- DecursiveSkipListFrame {{{ -->
|
||||
<Frame name="DecursiveSkipListFrame" inherits="Dcr_ListFrameTemplate">
|
||||
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
Dcr.ListFrameTemplate_OnLoad(self);
|
||||
|
||||
self.ScrollUpdateFunc = Dcr.PrioSkipList_ScrollFrame_Update;
|
||||
|
||||
self.Priority = false;
|
||||
self.ListTitle = Dcr.L["SKIP_LIST_STR"];
|
||||
|
||||
_G[self:GetName().."Text"]:SetText(Dcr.L["STR_DCR_SKIP"]);
|
||||
|
||||
self.OnUpdate = Dcr.PrioSkipListFrame_OnUpdate;
|
||||
|
||||
self.ClearButtonText = Dcr.L["CLEAR_SKIP"];
|
||||
self.ClearButtonTip = Dcr.L["BINDING_NAME_DCRSKCLEAR"];
|
||||
self.ClearFunction = Dcr.ClearSkipList;
|
||||
|
||||
self.CloseButtonTip = Dcr.L["BINDING_NAME_DCRSKSHOW"];
|
||||
|
||||
self.PopulateAddFunction = Dcr.AddUnitToSkipList;
|
||||
self.PopulateFrameTitle = Dcr.L["SKIP_LIST_STR"];
|
||||
|
||||
self.AddTargetFunc = Dcr.AddTargetToSkipList;
|
||||
self.EntryOnclick = Dcr.PrioSkipListEntryTemplate_OnClick;
|
||||
|
||||
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Frame>
|
||||
<!-- }}} -->
|
||||
|
||||
|
||||
<!-- DecursivePopulateListFrame {{{ -->
|
||||
<Frame name="DecursivePopulateListFrame" frameStrata="LOW" toplevel="true" enableMouse="true" movable="true" hidden="true" parent="UIParent">
|
||||
<Size>
|
||||
<AbsDimension x="168" y="265" />
|
||||
</Size>
|
||||
|
||||
<Anchors>
|
||||
<Anchor point="CENTER" />
|
||||
</Anchors>
|
||||
|
||||
<TitleRegion setAllPoints="true"/>
|
||||
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
</Backdrop>
|
||||
|
||||
<Scripts>
|
||||
<OnShow>
|
||||
_G[self:GetName().."Title"]:SetText(Dcr.L["STR_QUICK_POP"]);
|
||||
</OnShow>
|
||||
</Scripts>
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString name="$parentTitle" inherits="GameFontNormal" text="STR_QUICK_POP">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-10" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
<FontString name="$parentText" inherits="GameFontNormal" text="STR_POP">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentTitle">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
|
||||
<Button name="$parentGroup1" inherits="GameMenuButtonTemplate" text="Group 1">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPLEFT" relativePoint="TOPLEFT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="5" y="-45" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 1;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '1');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup2" inherits="GameMenuButtonTemplate" text="Group 2">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="-5" y="-45" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 2;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '2');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup3" inherits="GameMenuButtonTemplate" text="Group 3">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup1">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 3;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '3');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup4" inherits="GameMenuButtonTemplate" text="Group 4">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup2">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 4;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '4');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup5" inherits="GameMenuButtonTemplate" text="Group 5">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup3">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 5;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '5');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup6" inherits="GameMenuButtonTemplate" text="Group 6">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup4">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 6;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '6');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup7" inherits="GameMenuButtonTemplate" text="Group 7">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup5">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 7;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '7');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentGroup8" inherits="GameMenuButtonTemplate" text="Group 8">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup6">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
self.GroupNumber = 8;
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_GROUP"] .. '8');
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentWarrior" inherits="GameMenuButtonTemplate" text="Warrior">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup7">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_WARRIOR;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentPriest" inherits="GameMenuButtonTemplate" text="Priest">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentGroup8">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_PRIEST;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentMage" inherits="GameMenuButtonTemplate" text="Mage">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentWarrior">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_MAGE;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentWarlock" inherits="GameMenuButtonTemplate" text="Warlock">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentPriest">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_WARLOCK;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentHunter" inherits="GameMenuButtonTemplate" text="Hunter">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentMage">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_HUNTER;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentRogue" inherits="GameMenuButtonTemplate" text="Rogue">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentWarlock">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_ROGUE;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentDruid" inherits="GameMenuButtonTemplate" text="Druid">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentHunter">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_DRUID;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentShaman" inherits="GameMenuButtonTemplate" text="Shaman">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentRogue">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_SHAMAN;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentPaladin" inherits="GameMenuButtonTemplate" text="Paladin">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentDruid">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_PALADIN;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
<Button name="$parentDeathknight" inherits="GameMenuButtonTemplate" text="Deathknight">
|
||||
<Size>
|
||||
<AbsDimension x="80" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="BOTTOM" relativeTo="$parentShaman">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
Dcr:PopulateButtonPress(self);
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self.ClassType = DcrC.CLASS_DEATHKNIGHT;
|
||||
self:SetText(Dcr:ColorText(Dcr.LC[self.ClassType], "FF"..Dcr:GetClassHexColor(self.ClassType)));
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
|
||||
<Button name="$parentClose" inherits="GameMenuButtonTemplate" text="Close">
|
||||
<Size>
|
||||
<AbsDimension x="100" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="BOTTOM" relativePoint="BOTTOM" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="10" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
DecursivePopulateListFrame:Hide();
|
||||
</OnClick>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["STR_CLOSE"]);
|
||||
</OnLoad>
|
||||
</Scripts>
|
||||
</Button>
|
||||
</Frames>
|
||||
</Frame>
|
||||
<!-- DecursivePopulateListFrame }}} -->
|
||||
|
||||
|
||||
<Script>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
T._LoadedFiles["Dcr_lists.xml"] = "2.5.1-6-gd3885c5";
|
||||
</Script>
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,525 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_LDB.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_LDB.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-09-16 00:48:59 +0200 (mar., 16 sept. 2008) $", "$Revision: 81756 $");
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local type = _G.type;
|
||||
local unpack = _G.unpack;
|
||||
local select = _G.select;
|
||||
local str_sub = _G.string.sub;
|
||||
local str_upper = _G.string.upper;
|
||||
local str_lower = _G.string.lower;
|
||||
local str_format = _G.string.format;
|
||||
local table = _G.table;
|
||||
local t_remove = _G.table.remove;
|
||||
local t_insert = _G.table.insert;
|
||||
local UnitName = _G.UnitName;
|
||||
local UnitIsPlayer = _G.UnitIsPlayer;
|
||||
local string = _G.string;
|
||||
local tonumber = _G.tonumber;
|
||||
local UnitGUID = _G.UnitGUID;
|
||||
local band = _G.bit.band;
|
||||
local GetTime = _G.GetTime;
|
||||
|
||||
|
||||
function D:ColorText (text, color) --{{{
|
||||
return "|c".. color .. text .. "|r";
|
||||
end --}}}
|
||||
|
||||
function D:RemoveColor (text)
|
||||
return str_sub(text, 11, -3);
|
||||
end
|
||||
|
||||
function D:MakePlayerName (name) --{{{
|
||||
if not name then name = "NONAME" end
|
||||
return "|cFFFFAA22|Hplayer:" .. name .. "|h" .. str_upper(name) .. "|h|r";
|
||||
end --}}}
|
||||
|
||||
function D:UnitIsPet (Unit)
|
||||
local GUID = UnitGUID(Unit);
|
||||
|
||||
if not GUID then return end
|
||||
|
||||
if band(tonumber(GUID:sub(0,5), 16), 0x00f)==0x004 then
|
||||
return true;
|
||||
end
|
||||
return false;
|
||||
|
||||
end
|
||||
|
||||
function D:PetUnitName (Unit, Check) -- {{{
|
||||
local Name = (self:UnitName(Unit));
|
||||
|
||||
if not Name or Name == DC.UNKNOWN then
|
||||
Name = DC.UNKNOWN .. "-" .. Unit;
|
||||
D:Debug("PetUnitName(): Name of %s is unknown", Unit);
|
||||
end
|
||||
|
||||
if not Check or (self:UnitIsPet(Unit)) then
|
||||
Name = ("%s-%s"):format (DC.PET,Name);
|
||||
end
|
||||
|
||||
return Name;
|
||||
|
||||
end -- }}}
|
||||
|
||||
function D:UnitName(Unit)
|
||||
local name, server = UnitName(Unit);
|
||||
if ( server and server ~= "" ) then
|
||||
return name.."-"..server;
|
||||
else
|
||||
return name;
|
||||
end
|
||||
end
|
||||
|
||||
local function isFormattedString(string)
|
||||
return type(string)=='string' and (string:find("%%[cdEefgGiouXxsq]")) or false;
|
||||
end
|
||||
|
||||
local function UseFormatIfPresent(...)
|
||||
if not isFormattedString((select(1,...))) then
|
||||
return ...;
|
||||
else
|
||||
return (select(1,...)):format(select(2, ...));
|
||||
end
|
||||
end
|
||||
|
||||
function D:NumToHexStr(number)
|
||||
if type(number) == 'number' then
|
||||
return ("%X"):format(number);
|
||||
else
|
||||
return tostring(number);
|
||||
end
|
||||
end
|
||||
|
||||
Dcr.UseFormatIfPresent = UseFormatIfPresent;
|
||||
|
||||
local function debugStyle(...)
|
||||
return "|cFF00AAAADebug:|r", ...;
|
||||
end
|
||||
|
||||
function D:Println( ... ) --{{{
|
||||
|
||||
if D.profile.Print_ChatFrame then
|
||||
self:Print(D.Status.OutputWindow, UseFormatIfPresent(...));
|
||||
end
|
||||
if D.profile.Print_CustomFrame then
|
||||
self:Print(DecursiveTextFrame, UseFormatIfPresent(...));
|
||||
end
|
||||
end --}}}
|
||||
|
||||
function D:ColorPrint (r,g,b, ... ) --XXX
|
||||
|
||||
local datas = {UseFormatIfPresent(...)};
|
||||
|
||||
local ColorHeader = ("|cff%02x%02x%02x"):format(r * 255, g * 255, b * 255);
|
||||
|
||||
t_insert(datas, 1, ColorHeader);
|
||||
t_insert(datas, #datas + 1, "|r");
|
||||
|
||||
if D.profile.Print_ChatFrame then
|
||||
self:Print(D.Status.OutputWindow, ColorHeader, unpack(datas));
|
||||
end
|
||||
|
||||
if D.profile.Print_CustomFrame then
|
||||
self:Print(DecursiveTextFrame, ColorHeader, unpack(datas));
|
||||
end
|
||||
|
||||
if not Dcr.db then
|
||||
self:Print(ColorHeader, unpack(datas));
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function D:errln( ... ) --{{{
|
||||
if not D.db or D.profile.Print_Error then
|
||||
self:ColorPrint(1,0,0,...);
|
||||
|
||||
end
|
||||
end --}}}
|
||||
|
||||
|
||||
function D:Debug(...)
|
||||
if self.debugging then
|
||||
self:Print(debugStyle(UseFormatIfPresent(...)));
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function D:tremovebyval(tab, val) -- {{{
|
||||
local k;
|
||||
local v;
|
||||
for k,v in pairs(tab) do
|
||||
if(v==val) then
|
||||
t_remove(tab, k);
|
||||
return true;
|
||||
end
|
||||
end
|
||||
return false;
|
||||
end -- }}}
|
||||
|
||||
function D:tcheckforval(tab, val) -- {{{
|
||||
local k;
|
||||
local v;
|
||||
if tab then
|
||||
for k,v in pairs(tab) do
|
||||
if v==val then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
end
|
||||
return false;
|
||||
end -- }}}
|
||||
|
||||
-- tcopy: recursively copy contents of one table to another
|
||||
function D:tcopy(to, from) -- "to" must be a table (possibly empty)
|
||||
if (type(from) ~= "table") then
|
||||
return error(("D:tcopy: bad argument #2 'from' must be a table, got '%s' instead"):format(type(from)),2);
|
||||
end
|
||||
|
||||
if (type(to) ~= "table") then
|
||||
return error(("D:tcopy: bad argument #1 'to' must be a table, got '%s' instead"):format(type(to)),2);
|
||||
end
|
||||
for k,v in pairs(from) do
|
||||
if(type(v)=="table") then
|
||||
to[k] = {}; -- this generate garbage
|
||||
D:tcopy(to[k], v);
|
||||
else
|
||||
to[k] = v;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- tcopycallback: recursively copy contents of one table to another calling a callback before storing the new values
|
||||
function D:tcopycallback(to, from, CallBack) -- "to" must be a table (possibly empty)
|
||||
if (type(from) ~= "table") then
|
||||
return error(("D:tcopycallback: bad argument #2 'from' must be a table, got '%s' instead"):format(type(from)),2);
|
||||
end
|
||||
|
||||
if (type(to) ~= "table") then
|
||||
return error(("D:tcopycallback: bad argument #1 'to' must be a table, got '%s' instead"):format(type(to)),2);
|
||||
end
|
||||
if (type(CallBack) ~= "function") then
|
||||
return error(("D:tcopycallback: bad argument #3 'CallBack' must be a function ref, got '%s' instead"):format(type(CallBack)),2);
|
||||
end
|
||||
for k,v in pairs(from) do
|
||||
if(type(v)=="table") then
|
||||
to[k] = {}; -- this generate garbage
|
||||
D:tcopycallback(to[k], v, CallBack);
|
||||
else
|
||||
to[k] = CallBack(v);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function D:tGiveValueIndex(tab, val)
|
||||
for k,v in pairs(tab) do
|
||||
if v==val then
|
||||
return k;
|
||||
end
|
||||
end
|
||||
return false;
|
||||
end
|
||||
|
||||
function D:tSortUsingKeys(tab)
|
||||
local SortedTable = {};
|
||||
local Keys = {};
|
||||
|
||||
-- store all the keys in a table
|
||||
for k,v in pairs(tab) do
|
||||
t_insert(Keys, k);
|
||||
end
|
||||
|
||||
-- sort the table
|
||||
table.sort(Keys);
|
||||
|
||||
-- we now have a sorted table containing the keys
|
||||
for pos, k in pairs(Keys) do
|
||||
-- insert the values in a new table using the position of each key
|
||||
t_insert(SortedTable, pos, tab[k]);
|
||||
end
|
||||
|
||||
-- we return a new sorted table with new keys but with the same values
|
||||
return SortedTable;
|
||||
end
|
||||
|
||||
function D:tReverse(tab)
|
||||
local ReversedTable = {};
|
||||
|
||||
for k,v in pairs(tab) do
|
||||
ReversedTable[v] = k;
|
||||
end
|
||||
|
||||
return ReversedTable;
|
||||
end
|
||||
|
||||
function D:Pack(...)
|
||||
local args = {};
|
||||
for i=1,select("#",...), 1 do
|
||||
args[i]=select(i, ...);
|
||||
end
|
||||
return args;
|
||||
end
|
||||
|
||||
function D:tSwap(t, i1, i2)
|
||||
|
||||
if i1 == i2 then
|
||||
return false;
|
||||
end
|
||||
|
||||
local i1c= t[i1];
|
||||
local i2c= t[i2];
|
||||
|
||||
if i1 <= i2 then
|
||||
t_remove(t, i2) -- remove the greater one first
|
||||
t_remove(t, i1)
|
||||
t_insert(t, i1, i2c) -- insert the smaller one first
|
||||
t_insert(t, i2, i1c)
|
||||
else
|
||||
t_remove(t, i1) -- remove the greater one first
|
||||
t_remove(t, i2)
|
||||
t_insert(t, i2, i1c) -- insert the smaller one first
|
||||
t_insert(t, i1, i2c)
|
||||
end
|
||||
|
||||
return true;
|
||||
end
|
||||
|
||||
|
||||
function D:ThisSetText(text) --{{{
|
||||
_G[this:GetName().."Text"]:SetText(text);
|
||||
end --}}}
|
||||
|
||||
function D:ThisSetParentText(frame, text) --{{{
|
||||
_G[this:GetParent():GetName().."Text"]:SetText(text);
|
||||
end --}}}
|
||||
|
||||
do
|
||||
local DefaultAnchorTab = {"ANCHOR_LEFT"};
|
||||
function D:DisplayTooltip(Message, RelativeTo, AnchorTab) --{{{
|
||||
if (not AnchorTab) then
|
||||
AnchorTab = DefaultAnchorTab;
|
||||
end
|
||||
DcrDisplay_Tooltip:SetOwner(RelativeTo, unpack(AnchorTab));
|
||||
DcrDisplay_Tooltip:ClearLines();
|
||||
DcrDisplay_Tooltip:SetText(Message);
|
||||
DcrDisplay_Tooltip:Show();
|
||||
end --}}}
|
||||
end
|
||||
|
||||
function D:DisplayGameTooltip(frame, Message) --{{{
|
||||
GameTooltip_SetDefaultAnchor(GameTooltip, frame);
|
||||
GameTooltip:SetText(Message);
|
||||
GameTooltip:Show();
|
||||
end --}}}
|
||||
|
||||
|
||||
|
||||
function D:NumToHexColor(ColorTable)
|
||||
return str_format("%02x%02x%02x%02x", ColorTable[4] * 255, ColorTable[1] * 255, ColorTable[2] * 255, ColorTable[3] * 255)
|
||||
end
|
||||
|
||||
-- function taken from http://www.wowwiki.com/SetTexCoord_Transformations
|
||||
function D:SetCoords(t, A, B, C, D, E, F)
|
||||
local det = A*E - B*D;
|
||||
local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy;
|
||||
|
||||
ULx, ULy = ( B*F - C*E ) / det, ( -(A*F) + C*D ) / det;
|
||||
LLx, LLy = ( -B + B*F - C*E ) / det, ( A - A*F + C*D ) / det;
|
||||
URx, URy = ( E + B*F - C*E ) / det, ( -D - A*F + C*D ) / det;
|
||||
LRx, LRy = ( E - B + B*F - C*E ) / det, ( -D + A -(A*F) + C*D ) / det;
|
||||
|
||||
t:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy);
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
DC.ClassesColors = { };
|
||||
|
||||
function D:GetClassColor (EnglishClass)
|
||||
if not DC.ClassesColors[EnglishClass] then
|
||||
if RAID_CLASS_COLORS and RAID_CLASS_COLORS[EnglishClass] then
|
||||
DC.ClassesColors[EnglishClass] = { RAID_CLASS_COLORS[EnglishClass].r, RAID_CLASS_COLORS[EnglishClass].g, RAID_CLASS_COLORS[EnglishClass].b };
|
||||
else
|
||||
DC.ClassesColors[EnglishClass] = { 0.63, 0.63, 0.63 };
|
||||
end
|
||||
DC.ClassesColors[LC[EnglishClass]] = DC.ClassesColors[EnglishClass];
|
||||
end
|
||||
return unpack(DC.ClassesColors[EnglishClass]);
|
||||
end
|
||||
|
||||
DC.HexClassColor = { };
|
||||
|
||||
function D:GetClassHexColor(EnglishClass)
|
||||
if not DC.HexClassColor[EnglishClass] then
|
||||
local r, g, b = self:GetClassColor(EnglishClass)
|
||||
DC.HexClassColor[EnglishClass] = str_format("%02x%02x%02x", r * 255, g * 255, b * 255);
|
||||
DC.HexClassColor[LC[EnglishClass]] = DC.HexClassColor[EnglishClass];
|
||||
end
|
||||
|
||||
return DC.HexClassColor[EnglishClass];
|
||||
end
|
||||
|
||||
|
||||
function D:CreateClassColorTables ()
|
||||
if RAID_CLASS_COLORS then
|
||||
local class, colors;
|
||||
for class in pairs(RAID_CLASS_COLORS) do
|
||||
if LC[class] then -- Some badly coded add-ons are modifying RAID_CLASS_COLORS causing multiple problems...
|
||||
D:GetClassHexColor(class);
|
||||
D:GetClassColor(class);
|
||||
else
|
||||
RAID_CLASS_COLORS[class] = nil; -- Eat that!
|
||||
--@alpha@
|
||||
D:AddDebugText("Strange class found in RAID_CLASS_COLORS:", class);
|
||||
--@end-alpha@
|
||||
print("Decursive: |cFFFF0000Stupid value found in _G.RAID_CLASS_COLORS table|r\nThis will cause many issues (tainting), Decursive will display this message until the culprit add-on is fixed or removed, the Stupid value is: '", class, "'");
|
||||
end
|
||||
end
|
||||
else
|
||||
D:AddDebugText("global RAID_CLASS_COLORS does not exist...");
|
||||
T._FatalError("global RAID_CLASS_COLORS does not exist...");
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function D:MakeError(something)
|
||||
local testlocal = "test local";
|
||||
|
||||
testErrorCapturing(testlocal);
|
||||
end
|
||||
|
||||
function D:NiceTime()
|
||||
return tonumber(("%.4f"):format(GetTime() - DC.StartTime));
|
||||
end
|
||||
|
||||
local DcrTimers = {};
|
||||
function D:TimerExixts(RefName)
|
||||
return DcrTimers[RefName] and DcrTimers[RefName][1] or false;
|
||||
end
|
||||
|
||||
function D:DelayedCallExixts(RefName)
|
||||
return DcrTimers[RefName] and DcrTimers[RefName][1] or false;
|
||||
end
|
||||
|
||||
local ObjectWithArgs = {["obj"]=false, ["arg"]=false,};
|
||||
function D:ScheduleDelayedCall(RefName, FunctionRef, Delay, arg1, ...)
|
||||
|
||||
if DcrTimers[RefName] and DcrTimers[RefName][1] then
|
||||
self:CancelTimer(DcrTimers[RefName][1]);
|
||||
end
|
||||
|
||||
if not DcrTimers[RefName] then
|
||||
DcrTimers[RefName] = {};
|
||||
end
|
||||
|
||||
if select('#', ...) > 0 then
|
||||
-- arg table
|
||||
DcrTimers[RefName][2] = {arg1};
|
||||
|
||||
local i;
|
||||
for i = 1, select('#', ...) do
|
||||
DcrTimers[RefName][2][i + 1] = (select(i, ...));
|
||||
end
|
||||
|
||||
DcrTimers[RefName][1] = self:ScheduleTimer (
|
||||
function(arg)
|
||||
FunctionRef(unpack(arg));
|
||||
DcrTimers[RefName][1] = false;
|
||||
end
|
||||
, Delay, DcrTimers[RefName][2]
|
||||
);
|
||||
else
|
||||
DcrTimers[RefName][1] = self:ScheduleTimer (
|
||||
function(arg)
|
||||
FunctionRef(arg);
|
||||
DcrTimers[RefName][1] = false;
|
||||
end
|
||||
, Delay, arg1
|
||||
);
|
||||
end
|
||||
|
||||
return DcrTimers[RefName][1];
|
||||
end
|
||||
|
||||
function D:ScheduleRepeatedCall(RefName, FunctionRef, Delay, arg)
|
||||
if DcrTimers[RefName] and DcrTimers[RefName][1] then
|
||||
self:CancelTimer(DcrTimers[RefName][1]);
|
||||
end
|
||||
|
||||
if not DcrTimers[RefName] then
|
||||
DcrTimers[RefName] = {};
|
||||
end
|
||||
|
||||
DcrTimers[RefName][1] = self:ScheduleRepeatingTimer(FunctionRef, Delay, arg);
|
||||
|
||||
return DcrTimers[RefName][1];
|
||||
end
|
||||
|
||||
function D:CancelDelayedCall(RefName)
|
||||
if DcrTimers[RefName] and DcrTimers[RefName][1] then
|
||||
local cancelHandle = DcrTimers[RefName][1];
|
||||
DcrTimers[RefName][1] = false;
|
||||
return self:CancelTimer(cancelHandle);
|
||||
end
|
||||
end
|
||||
|
||||
function D:CancelAllTimedCalls()
|
||||
for RefName in pairs(DcrTimers) do
|
||||
self:CancelDelayedCall(RefName);
|
||||
end
|
||||
end
|
||||
|
||||
T._LoadedFiles["Dcr_utils.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,889 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_Raid.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_Raid.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local D = Dcr;
|
||||
--D:SetDateAndRevision("$Date: 2008-09-16 00:25:13 +0200 (mar., 16 sept. 2008) $", "$Revision: 81755 $");
|
||||
|
||||
local L = D.L;
|
||||
local LC = D.LC;
|
||||
local DC = DcrC;
|
||||
local DS = DC.DS;
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local pairs = _G.pairs;
|
||||
local ipairs = _G.ipairs;
|
||||
local type = _G.type;
|
||||
local table = _G.table;
|
||||
local t_sort = _G.table.sort;
|
||||
local PlaySoundFile = _G.PlaySoundFile;
|
||||
local UnitName = _G.UnitName;
|
||||
local UnitDebuff = _G.UnitDebuff;
|
||||
local UnitBuff = _G.UnitBuff;
|
||||
local UnitIsCharmed = _G.UnitIsCharmed;
|
||||
local UnitCanAttack = _G.UnitCanAttack;
|
||||
local UnitClass = _G.UnitClass;
|
||||
local UnitExists = _G.UnitExists;
|
||||
local GetNetStats = _G.GetNetStats;
|
||||
local _;
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- The UI functions {{{
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- The printing functions {{{
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
function D:Show_Cure_Order() --{{{
|
||||
self:Println("printing cure order:");
|
||||
for index, unit in ipairs(self.Status.Unit_Array) do
|
||||
self:Println( unit, " - ", self:MakePlayerName((self:UnitName(unit))) , " Index: ", index);
|
||||
end
|
||||
end --}}}
|
||||
|
||||
-- }}}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- Show Hide FUNCTIONS -- {{{
|
||||
|
||||
function D:ShowHideLiveList(hide) --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
-- if hide is requested or if hide is not set and the live-list is shown
|
||||
if (hide==1 or (not hide and DcrLiveList:IsVisible())) then
|
||||
D.profile.Hide_LiveList = true;
|
||||
DcrLiveList:Hide();
|
||||
D:CancelDelayedCall("Dcr_LLupdate");
|
||||
else
|
||||
D.profile.Hide_LiveList = false;
|
||||
DcrLiveList:ClearAllPoints();
|
||||
DcrLiveList:SetPoint("TOPLEFT", "DecursiveMainBar", "BOTTOMLEFT");
|
||||
DcrLiveList:Show();
|
||||
|
||||
D:ScheduleRepeatedCall("Dcr_LLupdate", D.LiveList.Update_Display, D.profile.ScanTime, D.LiveList);
|
||||
end
|
||||
|
||||
end --}}}
|
||||
|
||||
-- This functions hides or shows the "Decursive" bar depending on its current
|
||||
-- state, it's also able hide/show the live-list if the "tie live-list" option is active
|
||||
function D:HideBar(hide) --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
if (hide==1 or (not hide and DecursiveMainBar:IsVisible())) then
|
||||
if (D.profile.LiveListTied) then
|
||||
D:ShowHideLiveList(1);
|
||||
end
|
||||
D.profile.Hidden = true;
|
||||
DecursiveMainBar:Hide();
|
||||
else
|
||||
if (D.profile.LiveListTied) then
|
||||
D:ShowHideLiveList(0);
|
||||
end
|
||||
D.profile.Hidden = false;
|
||||
DecursiveMainBar:Show();
|
||||
end
|
||||
|
||||
if DecursiveMainBar:IsVisible() and DcrLiveList:IsVisible() then
|
||||
DcrLiveList:ClearAllPoints();
|
||||
DcrLiveList:SetPoint("TOPLEFT", "DecursiveMainBar", "BOTTOMLEFT");
|
||||
else
|
||||
D:ColorPrint(0.3, 0.5, 1, L["SHOW_MSG"]);
|
||||
end
|
||||
|
||||
LibStub("AceConfigRegistry-3.0"):NotifyChange(D.name);
|
||||
end --}}}
|
||||
|
||||
function D:ShowHidePriorityListUI() --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
if (DecursivePriorityListFrame:IsVisible()) then
|
||||
DecursivePriorityListFrame:Hide();
|
||||
else
|
||||
DecursivePriorityListFrame:Show();
|
||||
end
|
||||
end --}}}
|
||||
|
||||
function D:ShowHideSkipListUI() --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
if (DecursiveSkipListFrame:IsVisible()) then
|
||||
DecursiveSkipListFrame:Hide();
|
||||
else
|
||||
DecursiveSkipListFrame:Show();
|
||||
end
|
||||
end --}}}
|
||||
|
||||
-- This shows/hides the buttons near the "Decursive" bar
|
||||
function D:ShowHideButtons(UseCurrentValue) --{{{
|
||||
|
||||
if not D.DcrFullyInitialized then
|
||||
return;
|
||||
end
|
||||
|
||||
if not D.profile then
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
local DcrFrame = "DecursiveMainBar";
|
||||
local buttons = {
|
||||
DcrFrame .. "Priority",
|
||||
DcrFrame .. "Skip",
|
||||
DcrFrame .. "Hide",
|
||||
}
|
||||
|
||||
local DCRframeObject = _G[DcrFrame];
|
||||
|
||||
if (not UseCurrentValue) then
|
||||
D.profile.HideButtons = (not D.profile.HideButtons);
|
||||
end
|
||||
|
||||
for _, ButtonName in pairs(buttons) do
|
||||
local Button = _G[ButtonName];
|
||||
|
||||
if (D.profile.HideButtons) then
|
||||
Button:Hide();
|
||||
DCRframeObject.isLocked = 1;
|
||||
else
|
||||
Button:Show();
|
||||
DCRframeObject.isLocked = 0;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end --}}}
|
||||
|
||||
-- }}}
|
||||
|
||||
|
||||
-- this resets the location of the windows
|
||||
function D:ResetWindow() --{{{
|
||||
|
||||
DecursiveMainBar:ClearAllPoints();
|
||||
DecursiveMainBar:SetPoint("CENTER", UIParent);
|
||||
DecursiveMainBar:Show();
|
||||
|
||||
DcrLiveList:ClearAllPoints();
|
||||
DcrLiveList:SetPoint("TOPLEFT", DecursiveMainBar, "BOTTOMLEFT");
|
||||
DcrLiveList:Show();
|
||||
|
||||
DecursivePriorityListFrame:ClearAllPoints();
|
||||
DecursivePriorityListFrame:SetPoint("CENTER", UIParent);
|
||||
|
||||
DecursiveSkipListFrame:ClearAllPoints();
|
||||
DecursiveSkipListFrame:SetPoint("CENTER", UIParent);
|
||||
|
||||
DecursivePopulateListFrame:ClearAllPoints();
|
||||
DecursivePopulateListFrame:SetPoint("CENTER", UIParent);
|
||||
|
||||
D.MFContainer:ClearAllPoints();
|
||||
D.MFContainer:SetPoint("CENTER", UIParent, "CENTER", 0, 0);
|
||||
|
||||
DecursiveAnchor:ClearAllPoints();
|
||||
DecursiveAnchor:SetPoint("TOP", UIErrorsFrame, "BOTTOM", 0, 0);
|
||||
|
||||
end --}}}
|
||||
|
||||
|
||||
function D:PlaySound (UnitID, Caller) --{{{
|
||||
if self.profile.PlaySound and not self.Status.SoundPlayed then
|
||||
local Debuffs = self:UnitCurableDebuffs(UnitID, true);
|
||||
if Debuffs and Debuffs[1] and Debuffs[1].Type then
|
||||
|
||||
-- good sounds: Sound\\Doodad\\BellTollTribal.wav
|
||||
-- Sound\\interface\\AuctionWindowOpen.wav
|
||||
-- Sound\\interface\\AlarmClockWarning3.wav
|
||||
PlaySoundFile(self.profile.SoundFile);
|
||||
self:Debug("Sound Played! by %s", Caller);
|
||||
self.Status.SoundPlayed = true;
|
||||
else
|
||||
self.UnitDebuffed[UnitID] = false;
|
||||
end
|
||||
end
|
||||
end --}}}
|
||||
|
||||
-- LIVE-LIST DISPLAY functions {{{
|
||||
|
||||
|
||||
|
||||
-- Those set the scalling of the LIVELIST container
|
||||
-- SACALING FUNCTIONS {{{
|
||||
-- Place the LIVELIST container according to its scale
|
||||
function D:PlaceLL () -- {{{
|
||||
local UIScale = UIParent:GetEffectiveScale()
|
||||
local FrameScale = DecursiveMainBar:GetEffectiveScale();
|
||||
local x, y = D.profile.MainBarX, D.profile.MainBarY;
|
||||
|
||||
-- check if the coordinates are correct
|
||||
if x and y and (x + 10 > UIParent:GetWidth() * UIScale or x < 0 or (-1 * y + 10) > UIParent:GetHeight() * UIScale or y > 0) then
|
||||
x = false; -- reset to default position
|
||||
T._FatalError("Decursive's bar position reset to default");
|
||||
end
|
||||
|
||||
-- Executed for the very first time, then put it in the top right corner of the screen
|
||||
if (not x or not y) then
|
||||
x = (UIParent:GetWidth() * UIScale) / 2;
|
||||
y = - (UIParent:GetHeight() * UIScale) / 8;
|
||||
|
||||
D.profile.MainBarX = x;
|
||||
D.profile.MainBarY = y;
|
||||
end
|
||||
|
||||
-- set to the scaled position
|
||||
DecursiveMainBar:ClearAllPoints();
|
||||
DecursiveMainBar:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x/FrameScale , y/FrameScale);
|
||||
DcrLiveList:ClearAllPoints();
|
||||
DcrLiveList:SetPoint("TOPLEFT", DecursiveMainBar, "BOTTOMLEFT");
|
||||
end -- }}}
|
||||
|
||||
-- Save the position of the frame without its scale
|
||||
function D:SaveLLPos () -- {{{
|
||||
if self.profile and DecursiveMainBar:IsVisible() then
|
||||
-- We save the unscalled position (no problem if the sacale is changed behind our back)
|
||||
self.profile.MainBarX = DecursiveMainBar:GetEffectiveScale() * DecursiveMainBar:GetLeft();
|
||||
self.profile.MainBarY = DecursiveMainBar:GetEffectiveScale() * DecursiveMainBar:GetTop() - UIParent:GetHeight() * UIParent:GetEffectiveScale();
|
||||
|
||||
|
||||
if self.profile.MainBarX < 0 then
|
||||
self.profile.MainBarX = 0;
|
||||
end
|
||||
|
||||
if self.profile.MainBarY > 0 then
|
||||
self.profile.MainBarY = 0;
|
||||
end
|
||||
|
||||
end
|
||||
end -- }}}
|
||||
|
||||
-- set the scaling of the LIVELIST container according to the user settings
|
||||
function D:SetLLScale (NewScale) -- {{{
|
||||
|
||||
-- save the current position without any scaling
|
||||
D:SaveLLPos ();
|
||||
-- Set the new scale
|
||||
DecursiveMainBar:SetScale(NewScale);
|
||||
DcrLiveList:SetScale(NewScale);
|
||||
-- Place the frame adapting its position to the news cale
|
||||
D:PlaceLL ();
|
||||
|
||||
end -- }}}
|
||||
-- }}}
|
||||
|
||||
|
||||
-- }}}
|
||||
|
||||
-- // }}}
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
do
|
||||
local iterator = 1;
|
||||
local DebuffHistHashTable = {};
|
||||
|
||||
function D:Debuff_History_Add( DebuffName, DebuffType )
|
||||
|
||||
if not DebuffHistHashTable[DebuffName] then
|
||||
|
||||
-- reset iterator if out of boundaries
|
||||
if iterator > DC.DebuffHistoryLength then
|
||||
iterator = 1;
|
||||
end
|
||||
|
||||
-- clean hastable if necessary before adding a new entry
|
||||
if DebuffHistHashTable[D.DebuffHistory[iterator]] then
|
||||
DebuffHistHashTable[D.DebuffHistory[iterator]] = nil;
|
||||
end
|
||||
|
||||
-- Register the name in the HashTable using the debuff type
|
||||
DebuffHistHashTable[DebuffName] = (DebuffType and DC.NameToTypes[DebuffType] or DC.NOTYPE);
|
||||
--D:Debug(DebuffName, DebuffHistHashTable[DebuffName]);
|
||||
|
||||
-- Put this debuff in our history
|
||||
D.DebuffHistory[iterator] = DebuffName;
|
||||
|
||||
-- This is a useless comment
|
||||
iterator = iterator + 1;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function D:Debuff_History_Get (Index, Colored)
|
||||
|
||||
local HumanIndex = iterator - Index;
|
||||
|
||||
if HumanIndex < 1 then
|
||||
HumanIndex = HumanIndex + DC.DebuffHistoryLength;
|
||||
end
|
||||
|
||||
if not D.DebuffHistory[HumanIndex] then
|
||||
return "|cFF777777Empty|r", false;
|
||||
end
|
||||
|
||||
if Colored then
|
||||
--D:Debug(D.DebuffHistory[HumanIndex], DebuffHistHashTable[D.DebuffHistory[HumanIndex]]);
|
||||
return D:ColorText(D.DebuffHistory[HumanIndex], "FF" .. DC.TypeColors[DebuffHistHashTable[D.DebuffHistory[HumanIndex]]]), true;
|
||||
else
|
||||
return D.DebuffHistory[HumanIndex], true;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Scanning functionalities {{{
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
do
|
||||
|
||||
local Name, rank, Texture, Applications, TypeName, Duration, expirationTime;
|
||||
local D = _G.Dcr;
|
||||
local UnitAura = _G.UnitAura;
|
||||
|
||||
-- This function only returns interesting values of UnitDebuff()
|
||||
local function GetUnitDebuff (Unit, i) --{{{
|
||||
|
||||
if D.LiveList.TestItemDisplayed and i == 1 and Unit ~= "target" and Unit ~= "mouseover" and UnitExists(Unit) then
|
||||
D:Debug("|cFFFF0000Setting test debuff for %s (debuff %d)|r", Unit, i);
|
||||
return "Test item", DC.TypeNames[D.Status.ReversedCureOrder[1]], 2, "Interface\\AddOns\\Decursive\\iconON.tga", D.LiveList.TestItemDisplayed + 70;
|
||||
end
|
||||
|
||||
--D:Debug("|cFFFF0000Getting debuffs for %s , id = %d|r", Unit, i);
|
||||
|
||||
|
||||
-- Name, rank, Texture, Applications, TypeName, duration, expirationTime, unitCaster, isStealable = UnitAura("unit", index or ["name", "rank"][, "filter"])
|
||||
|
||||
local Name, rank, Texture, Applications, TypeName, Duration, expirationTime = UnitAura(Unit, i, "HARMFUL");
|
||||
|
||||
--local Name, rank, Texture, Applications, TypeName, Duration = UnitDebuff(Unit, i);
|
||||
|
||||
if Name then
|
||||
return Name, TypeName, Applications, Texture, expirationTime;
|
||||
else
|
||||
return false, false, false, false, false;
|
||||
end
|
||||
end --}}}
|
||||
|
||||
-- there is a known maximum number of unit and a known maximum debuffs per unit so lets allocate the memory needed only once. Memory will be allocated when needed and re-used...
|
||||
local DebuffUnitCache = {};
|
||||
|
||||
-- Variables are declared outside so that Lua doesn't initialize them at each call
|
||||
local Name, Type, i, StoredDebuffIndex, CharmFound, IsCharmed;
|
||||
|
||||
local DcrC = DcrC; -- for faster access
|
||||
|
||||
local UnitIsCharmed = _G.UnitIsCharmed;
|
||||
local UnitCanAttack = _G.UnitCanAttack;
|
||||
local GetTime = _G.GetTime;
|
||||
local IsSpellInRange = _G.IsSpellInRange;
|
||||
|
||||
-- This is the core debuff scanning function of Decursive
|
||||
-- This function does more than just reporting Debuffs. it also detects charmed units
|
||||
|
||||
function D:GetUnitDebuffAll (Unit) --{{{
|
||||
|
||||
-- create a Debuff table for this unit if there is not already one
|
||||
if (not DebuffUnitCache[Unit]) then
|
||||
DebuffUnitCache[Unit] = {};
|
||||
end
|
||||
|
||||
-- This is just a shortcut for easier readability
|
||||
local ThisUnitDebuffs = DebuffUnitCache[Unit];
|
||||
|
||||
i = 1; -- => to index all debuffs
|
||||
StoredDebuffIndex = 1; -- => this index only debuffs with a type
|
||||
CharmFound = false; -- => avoid to find that the unit is charmed again and again...
|
||||
|
||||
|
||||
-- test if the unit is mind controlled once
|
||||
if (UnitIsCharmed(Unit) and (UnitCanAttack("player", Unit) or UnitIsCharmed("player"))) then
|
||||
IsCharmed = true;
|
||||
else
|
||||
IsCharmed = false;
|
||||
end
|
||||
|
||||
-- iterate all available debuffs
|
||||
while (true) do
|
||||
Name, TypeName, Applications, Texture, expirationTime = GetUnitDebuff(Unit, i);
|
||||
|
||||
if not Name then
|
||||
break;
|
||||
end
|
||||
|
||||
|
||||
-- test for a type (Magic Curse Disease or Poison)
|
||||
if (TypeName and TypeName ~= "") then
|
||||
Type = DC.NameToTypes[TypeName];
|
||||
else
|
||||
Type = false;
|
||||
end
|
||||
|
||||
-- implement the test for DominateMind I HATE stupid exceptions like this one... so many hours lost because of this :/
|
||||
--[=[
|
||||
if Name == DS["YOGGG_DOMINATE_MIND"] and Type == DC.MAGIC then
|
||||
|
||||
if DC.MyClass == "PALADIN" then
|
||||
IsCharmed = false;
|
||||
CharmFound = false;
|
||||
else
|
||||
IsCharmed = true;
|
||||
end
|
||||
|
||||
if DC.MyClass == "PALADIN" or DC.MyClass == "SHAMAN" then
|
||||
|
||||
YoggReport = true;
|
||||
|
||||
D:AddDebugText("|cFFFF9955Decursive Yoggy Debug (try 6):|r", Unit, TypeName, Applications,
|
||||
"PC:",DC.MyClass,"IsOvering:", self.Status.MouseOveringMUF, "DN",i, "SDi",StoredDebuffIndex,
|
||||
"UICp:",UnitIsCharmed( "player"), "UICu:",UnitIsCharmed(Unit),
|
||||
"UCApu:",UnitCanAttack("player", Unit), "IsCharmed:", IsCharmed
|
||||
-- "UCAup:",UnitCanAttack(Unit, "player"), "UCApu:",UnitCanAttack("player", Unit), "UIFpu:",UnitIsFriend( "player", Unit), "UIEpu:",UnitIsEnemy( "player", Unit)
|
||||
);
|
||||
end
|
||||
|
||||
end
|
||||
--]=]
|
||||
|
||||
-- if the unit is charmed and we didn't took care of this information yet
|
||||
if IsCharmed and (not CharmFound or Type == DC.MAGIC) then
|
||||
-- If the unit has a magical debuff and we can cure it
|
||||
-- (note that the target is not friendly in that case)
|
||||
if (Type == DC.MAGIC and self.Status.CuringSpells[DC.ENEMYMAGIC]) then
|
||||
Type = DC.ENEMYMAGIC;
|
||||
|
||||
-- NOTE: if a unit is charmed and has another magical debuff
|
||||
-- this block will be executed...
|
||||
else -- the unit doesn't have a magical debuff or we can't remove magical debuffs
|
||||
Type = DC.CHARMED; -- The player can't remove it anyway so just say the unit is afflicted by a charming effect
|
||||
TypeName = DC.TypeNames[DC.CHARMED];
|
||||
end
|
||||
CharmFound = true;
|
||||
end
|
||||
|
||||
--[=[
|
||||
if YoggReport then
|
||||
local IsInRange;
|
||||
if self.Status.CuringSpells[Type] then
|
||||
IsInRange = IsSpellInRange(self.Status.CuringSpells[Type], Unit)
|
||||
end
|
||||
D:AddDebugText("CharmFound:", CharmFound, "TN:", DC.TypeNames[Type], "ISIR", IsInRange);
|
||||
end
|
||||
--]=]
|
||||
|
||||
|
||||
-- If we found a type, register the Debuff
|
||||
if (Type) then
|
||||
-- Create a Debuff index entry if necessary
|
||||
if (not ThisUnitDebuffs[StoredDebuffIndex]) then
|
||||
ThisUnitDebuffs[StoredDebuffIndex] = {};
|
||||
end
|
||||
|
||||
ThisUnitDebuffs[StoredDebuffIndex].expirationTime = expirationTime;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].Texture = Texture;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].Applications = Applications;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].TypeName = TypeName;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].Type = Type;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].Name = Name;
|
||||
ThisUnitDebuffs[StoredDebuffIndex].index = i;
|
||||
|
||||
-- we can't use i, else we wouldn't have contiguous indexes in the table
|
||||
StoredDebuffIndex = StoredDebuffIndex + 1;
|
||||
end
|
||||
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
-- erase remaining unused entries without freeing the memory (less garbage)
|
||||
while (ThisUnitDebuffs[StoredDebuffIndex]) do
|
||||
ThisUnitDebuffs[StoredDebuffIndex].Type = false;
|
||||
StoredDebuffIndex = StoredDebuffIndex + 1;
|
||||
end
|
||||
|
||||
-- if no debuff on the unit then it can't be charmed... FUCKING LAG!!
|
||||
if i == 1 then
|
||||
IsCharmed = false;
|
||||
end
|
||||
|
||||
return ThisUnitDebuffs, IsCharmed;
|
||||
end --}}}
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
-- see the comment about DebuffUnitCache
|
||||
local ManagedDebuffUnitCache = D.ManagedDebuffUnitCache;
|
||||
|
||||
|
||||
local D = D;
|
||||
local _ = false;
|
||||
local CureOrder;
|
||||
local sorting = function (a, b)
|
||||
|
||||
CureOrder = D.classprofile.CureOrder; -- LUA is too simple, lets do the access optimization...
|
||||
|
||||
local cura = (a.Type and CureOrder[a.Type] and CureOrder[a.Type] > 0) and CureOrder[a.Type] or 1024;
|
||||
local curb = (b.Type and CureOrder[b.Type] and CureOrder[b.Type] > 0) and CureOrder[b.Type] or 1024;
|
||||
|
||||
return cura < curb;
|
||||
end
|
||||
|
||||
-- This function will return a table containing only the Debuffs we can cure excepts the one we have to ignore
|
||||
-- in different conditions.
|
||||
function D:UnitCurableDebuffs (Unit, JustOne) -- {{{
|
||||
|
||||
if not Unit then
|
||||
self:Debug("No unit supplied to UnitCurableDebuffs()");
|
||||
return false;
|
||||
end
|
||||
|
||||
if (not ManagedDebuffUnitCache[Unit]) then
|
||||
ManagedDebuffUnitCache[Unit] = {};
|
||||
end
|
||||
|
||||
local AllUnitDebuffs, IsCharmed = self:GetUnitDebuffAll(Unit); -- always return a table, may be empty though
|
||||
|
||||
if not (AllUnitDebuffs[1] and AllUnitDebuffs[1].Type ) then -- if there is no curable debuff (a debuff with a type)
|
||||
return false, IsCharmed;
|
||||
end
|
||||
|
||||
local Spells = self.Status.CuringSpells; -- shortcut to available spells by debuff type
|
||||
|
||||
|
||||
local ManagedDebuffs = ManagedDebuffUnitCache[Unit]; -- shortcut for readability
|
||||
|
||||
--self:Debug("Debuffs were found");
|
||||
|
||||
local DebuffNum = 1; -- number of found debuff (used for indexing)
|
||||
|
||||
local continue_ = true; -- if we have to ignore a debuff, this will become false
|
||||
|
||||
|
||||
|
||||
for _, Debuff in ipairs(AllUnitDebuffs) do
|
||||
|
||||
if (not Debuff.Type) then -- useless test, only debuffs with a type are returned...
|
||||
break;
|
||||
end
|
||||
continue_ = true;
|
||||
|
||||
-- test if we have to ignore this debuf {{{ --
|
||||
|
||||
if self.Status.PlayerOnlyTypes[Debuff.Type] and Unit ~= "player" then -- if this type is curable on the player only
|
||||
continue_ = false;
|
||||
end
|
||||
|
||||
if (self.profile.DebuffsToIgnore[Debuff.Name]) then
|
||||
-- these are the BAD ones... the ones that make the target immune... abort this unit
|
||||
--D:Debug("UnitCurableDebuffs(): %s is ignored", Debuff.Name);
|
||||
break; -- exit here
|
||||
end
|
||||
|
||||
if (self.profile.BuffDebuff[Debuff.Name]) then
|
||||
-- these are just ones you don't care about (sleepless deam etc...)
|
||||
continue_ = false;
|
||||
--D:Debug("UnitCurableDebuffs(): %s is not a real debuff", Debuff.Name);
|
||||
end
|
||||
|
||||
if (self.Status.Combat or self.profile.DebuffAlwaysSkipList[Debuff.Name]) then
|
||||
local _, EnUClass = UnitClass(Unit);
|
||||
if (self.profile.skipByClass[EnUClass]) then
|
||||
if (self.profile.skipByClass[EnUClass][Debuff.Name]) then
|
||||
-- these are just ones you don't care about by class while in combat
|
||||
|
||||
-- This lead to a problem because once the fight is finished there are no event to trigger
|
||||
-- a rescan of this unit, so the debuff does not appear...
|
||||
|
||||
-- solution to the above problem:
|
||||
|
||||
if not self.profile.DebuffAlwaysSkipList[Debuff.Name] then
|
||||
self:AddDelayedFunctionCall("ReScan"..Unit, D.MicroUnitF.UpdateMUFUnit, D.MicroUnitF, Unit);
|
||||
end
|
||||
|
||||
D:Debug("UnitCurableDebuffs(): %s is configured to be skipped", Debuff.Name);
|
||||
continue_ = false;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- }}}
|
||||
|
||||
|
||||
if continue_ then
|
||||
-- self:Debug("Debuffs matters");
|
||||
-- If we are still here it means that this Debuff is something not to be ignored...
|
||||
|
||||
|
||||
-- We have a match for this type and we decided (checked) to
|
||||
-- cure it NOTE: self.classprofile.CureOrder[DEBUFF_TYPE] is set
|
||||
-- to FALSE when the type is unchecked and to < 0 when there is
|
||||
-- no spell available for the type or when the spell is gone
|
||||
-- (it happens for warlocks or when using the same profile with
|
||||
-- several characters)
|
||||
--if (self.classprofile.CureOrder[Debuff.Type] and self.classprofile.CureOrder[Debuff.Type] > 0) then
|
||||
if (self:GetCureCheckBoxStatus(Debuff.Type)) then
|
||||
|
||||
|
||||
-- self:Debug("we can cure it");
|
||||
|
||||
-- if we do have a spell to cure
|
||||
if (Spells[Debuff.Type]) then
|
||||
-- The user doesn't want to cure a unit afllicted by poison or disease if the unit
|
||||
-- is beeing cured by an abolish spell
|
||||
|
||||
if (self.profile.Check_For_Abolish and (Debuff.Type == DC.POISON and self:CheckUnitForBuffs(Unit, DS["SPELL_ABOLISH_POISON"]) or Debuff.Type == DC.DISEASE and self:CheckUnitForBuffs(Unit, DS["SPELL_ABOLISH_DISEASE"]))) then
|
||||
self:Debug("Abolish buff found, skipping");
|
||||
else
|
||||
-- self:Debug("It's managed");
|
||||
|
||||
-- create an entry for this debuff index if necessary
|
||||
if (not ManagedDebuffs[DebuffNum]) then
|
||||
ManagedDebuffs[DebuffNum] = {};
|
||||
end
|
||||
|
||||
-- copy the debuff information to this table.
|
||||
self:tcopy(ManagedDebuffs[DebuffNum], Debuff);
|
||||
|
||||
DebuffNum = DebuffNum + 1;
|
||||
|
||||
-- the live-list only reports the first debuf found and set JustOne to true
|
||||
if (JustOne) then
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end -- for END
|
||||
|
||||
-- erase unused entries without freeing the memory (less garbage)
|
||||
if (not JustOne or DebuffNum == 1) then -- if JustOne is set don't clear anything except if we found nothing
|
||||
while (ManagedDebuffs[DebuffNum]) do
|
||||
ManagedDebuffs[DebuffNum].Type = false;
|
||||
-- ManagedDebuffs[DebuffNum].TimeStamp = false;
|
||||
DebuffNum = DebuffNum + 1;
|
||||
end
|
||||
end
|
||||
|
||||
-- sort the table only if it's not 'empty' and only if there is at least two debuffs
|
||||
if (ManagedDebuffs[1] and ManagedDebuffs[1].Type) then
|
||||
|
||||
-- order Debuffs according to type priority order
|
||||
if (not JustOne and ManagedDebuffs[2] and ManagedDebuffs[2].Type) then
|
||||
t_sort(ManagedDebuffs, sorting); -- uses memory..
|
||||
end
|
||||
return ManagedDebuffs, IsCharmed;
|
||||
else
|
||||
return false, IsCharmed;
|
||||
end
|
||||
|
||||
end -- // }}}
|
||||
|
||||
local GetTime = _G.GetTime;
|
||||
local Debuffs = {}; local IsCharmed = false; local Unit; local MUF; local IsDebuffed= false; local CheckStealth = false;
|
||||
local NoScanStatuses = false;
|
||||
function D:ScanEveryBody()
|
||||
|
||||
if not NoScanStatuses then
|
||||
NoScanStatuses = {[DC.ABSENT] = true, [DC.FAR] = true, [DC.BLACKLISTED] = true};
|
||||
end
|
||||
|
||||
local UnitArray = self.Status.Unit_Array; local i = 1;
|
||||
local CheckStealth = self.profile.Show_Stealthed_Status;
|
||||
|
||||
--[===[@debug@
|
||||
local start = GetTime();
|
||||
--@end-debug@]===]
|
||||
|
||||
while UnitArray[i] do
|
||||
Unit = UnitArray[i];
|
||||
MUF = self.MicroUnitF.UnitToMUF[Unit];
|
||||
|
||||
if MUF and not NoScanStatuses[MUF.UnitStatus] then
|
||||
Debuffs, IsCharmed = self:UnitCurableDebuffs(Unit, true);
|
||||
|
||||
if CheckStealth then
|
||||
self.Stealthed_Units[Unit] = self:CheckUnitStealth(Unit); -- update stealth status
|
||||
end
|
||||
|
||||
IsDebuffed = (Debuffs and true) or IsCharmed;
|
||||
-- If MUF disagrees
|
||||
if IsDebuffed ~= MUF.IsDebuffed and not D:DelayedCallExixts("Dcr_Update" .. Unit) then
|
||||
--[===[@debug@
|
||||
if IsDebuffed then
|
||||
self:AddDebugText("delayed debuff found by scaneveryone, scheduling analysis in 1s");
|
||||
--D:ScheduleDelayedCall("Dcr_lateanalysis" .. Unit, self.MicroUnitF.LateAnalysis, 1, self.MicroUnitF, "ScanEveryone", Debuffs, MUF, MUF.UnitStatus);
|
||||
else
|
||||
self:AddDebugText("delayed UNdebuff found by scaneveryone on", Unit);
|
||||
end
|
||||
--@end-debug@]===]
|
||||
|
||||
self.MicroUnitF:UpdateMUFUnit(Unit, true);
|
||||
|
||||
--[===[@debug@
|
||||
D:Println("HAAAAAAA!!!!!");
|
||||
--@end-debug@]===]
|
||||
end
|
||||
end
|
||||
|
||||
i = i + 1;
|
||||
end
|
||||
--[===[@debug@
|
||||
--D:Debug("|cFF777777Scanning everybody...", i - 1, "units scanned in ", GetTime() - start, "seconds|r");
|
||||
--@end-debug@]===]
|
||||
end
|
||||
|
||||
|
||||
-- a little test... the ".." way wins (6x faster than the format solution) when both sides are strings
|
||||
function D:tests()
|
||||
|
||||
local test = "test1";
|
||||
local start = GetTime();
|
||||
local strings = {"string1", "string2", "strring3"};
|
||||
local teststring = "unitraid5"
|
||||
for i =1, 1000000 do
|
||||
teststring = strings[i%3 + 1];
|
||||
test = "test_"..teststring;
|
||||
end
|
||||
D:Debug("pass (\"\".. completed in:", GetTime() - start, test);
|
||||
|
||||
start = GetTime();
|
||||
for i =1, 1000000 do
|
||||
local t = strings[i%3 + 1];
|
||||
test = ("test_%s"):format(teststring);
|
||||
end
|
||||
D:Debug("pass format completed in:", GetTime() - start, test);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local UnitBuffsCache = {};
|
||||
|
||||
-- this function returns true if one of the debuff(s) passed to it is found on the specified unit
|
||||
function D:CheckUnitForBuffs(Unit, BuffNamesToCheck) --{{{
|
||||
|
||||
-- --[=[
|
||||
if (not UnitBuffsCache[Unit]) then
|
||||
UnitBuffsCache[Unit] = {};
|
||||
end
|
||||
|
||||
local UnitBuffs = UnitBuffsCache[Unit];
|
||||
local i = 1;
|
||||
local buff_name = "";
|
||||
|
||||
-- Get all the unit's buffs
|
||||
while true do
|
||||
|
||||
buff_name = UnitBuff(Unit, i)
|
||||
|
||||
if not buff_name then
|
||||
break;
|
||||
end
|
||||
|
||||
UnitBuffs[i] = buff_name;
|
||||
i = i + 1;
|
||||
end
|
||||
|
||||
while UnitBuffs[i] do -- clean the rest of the cache
|
||||
UnitBuffs[i] = false;
|
||||
i = i + 1;
|
||||
end
|
||||
--]=]
|
||||
|
||||
if type(BuffNamesToCheck) ~= "table" then
|
||||
|
||||
if self:tcheckforval(UnitBuffs, BuffNamesToCheck) then
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
end
|
||||
else
|
||||
local Buff;
|
||||
for _, Buff in pairs(BuffNamesToCheck) do
|
||||
|
||||
if self:tcheckforval(UnitBuffs, Buff) then
|
||||
return true;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
return false;
|
||||
|
||||
end --}}}
|
||||
|
||||
|
||||
D.Stealthed_Units = {};
|
||||
|
||||
do
|
||||
local Stealthed = {DS["Prowl"], DS["Stealth"], DS["Shadowmeld"], DS["Invisibility"], DS["Lesser Invisibility"]}; --, DS["Ice Armor"],};
|
||||
|
||||
DC.IsStealthBuff = D:tReverse(Stealthed);
|
||||
|
||||
function D:CheckUnitStealth(Unit)
|
||||
if self:CheckUnitForBuffs(Unit, Stealthed) then
|
||||
-- self:Debug("Sealth found !");
|
||||
return true;
|
||||
end
|
||||
return false;
|
||||
end
|
||||
end
|
||||
-- }}}
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["Decursive.lua"] = "2.5.1-6-gd3885c5";
|
||||
|
||||
-- Sin
|
||||
@@ -0,0 +1,73 @@
|
||||
## Interface: 30300
|
||||
## X-Curse-Packaged-Version: 2.5.1-6-gd3885c5
|
||||
## X-Curse-Project-Name: Decursive
|
||||
## X-Curse-Project-ID: decursive
|
||||
## X-Curse-Repository-ID: wow/decursive/mainline
|
||||
|
||||
## Title: Decursive |cffff00ff -Ace3-|r
|
||||
## Notes: Afflictions display and cleaning for solo, group and raids with advanced filtering and priority system.
|
||||
## Notes-frFR: Affichage et guérison des afflictions avec un système évolué de filtrage et de priorité.
|
||||
## Notes-ruRU: Отображение и лечение недугов с расширенной фильтрацией и системой приоритетов.
|
||||
## Notes-koKR: 쏠로, 파티, 공격대를 위한 고급화된 필터링과 시스템 우선권으로 고통들의 표시와 제거를 합니다.
|
||||
## Notes-zhTW: 當單獨、小隊和團隊時清除有害狀態,並可使用高級過濾和優先等級系統。
|
||||
## Notes-zhCN: 当单独、小队和团队时清除有害状态,并可使用高级过滤和优先等级系统。
|
||||
|
||||
## X-Compatible-With: 40000
|
||||
## X-Max-Interface: 40000
|
||||
## X-Min-Interface: 30300
|
||||
|
||||
## SavedVariables: DecursiveDB
|
||||
|
||||
## Version: 2.5.1-6-gd3885c5
|
||||
## Author: Archarodim
|
||||
|
||||
## X-License: All Rights Reserved
|
||||
|
||||
## OptionalDeps: Ace3, CallbackHandler-1.0, LibQTip-1.0, LibDataBroker-1.1, LibDBIcon-1.0
|
||||
|
||||
## LoadManagers: AddonLoader
|
||||
## X-LoadOn-Class: Mage, Priest, Paladin, Druid, Hunter, Warlock, Shaman
|
||||
|
||||
|
||||
## X-Embeds: Ace3, LibStub, CallbackHandler-1.0, LibQTip-1.0, LibDataBroker-1.1, LibDBIcon-1.0
|
||||
|
||||
## X-ReleaseDate: "2010-09-06T22:38:15Z"
|
||||
## X-Category: Combat
|
||||
## X-Website: http://www.2072productions.com/to/decursive.php
|
||||
## X-Credits: Sylvin (Full french translation), Peter Sun, Ananhaid (ZhTW and zhCN translation), Fenlis, Chkid (koKR translation), Hemathio, Swix, Athariel, StingerSoft (Russian Translation), Freydis88, Floyddotnet, Vilogity, Dessa, Farook (German translation)
|
||||
|
||||
## X-AceForum: 4195
|
||||
|
||||
## X-eMail: archarodim@teaser.fr
|
||||
|
||||
LibStub\LibStub.lua
|
||||
|
||||
embeds.xml
|
||||
|
||||
Dcr_DIAG.lua
|
||||
Dcr_DIAG.xml
|
||||
|
||||
Localization\load.xml
|
||||
|
||||
DCR_init.lua
|
||||
Dcr_LDB.lua
|
||||
Dcr_utils.lua
|
||||
|
||||
|
||||
Dcr_opt.lua
|
||||
Dcr_Events.lua
|
||||
|
||||
Dcr_Raid.lua
|
||||
|
||||
Decursive.lua
|
||||
Decursive.xml
|
||||
|
||||
Dcr_lists.lua
|
||||
Dcr_lists.xml
|
||||
|
||||
Dcr_DebuffsFrame.lua
|
||||
Dcr_DebuffsFrame.xml
|
||||
|
||||
Dcr_LiveList.lua
|
||||
Dcr_LiveList.xml
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
<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/">
|
||||
<!--
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/to/decursive.php )
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author, Decursive
|
||||
is no longer free software, all rights are reserved to its author (John Wellesz).
|
||||
|
||||
The only official and allowed distribution means are www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is required.
|
||||
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
-->
|
||||
<Script>
|
||||
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Decursive.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Decursive.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
end
|
||||
|
||||
</Script>
|
||||
|
||||
|
||||
<Frame name="DecursiveMainBar" clampedToScreen="true" frameStrata="LOW" toplevel="true" enableMouse="true" movable="true" hidden="true" parent="UIParent"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="80" y="25" />
|
||||
</Size>
|
||||
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-50"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
</Backdrop>
|
||||
|
||||
<Layers>
|
||||
<Layer level="OVERLAY">
|
||||
<FontString name="$parentText" inherits="GameFontNormal" text="BINDING_HEADER_DECURSIVE">
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativePoint="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
|
||||
<Scripts>
|
||||
<OnEnter>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic() ~= 2 then
|
||||
|
||||
Dcr:DisplayTooltip(
|
||||
string.format(
|
||||
"|cFF0055AA%s|r %s by %s|r\n" ..
|
||||
--"|cFF11FF11%s|r: %s\n" ..
|
||||
"|cFF11FF11%s|r / |cFF11FF11%s|r-|cFF11FF11%s|r: %s"
|
||||
, Dcr.name, Dcr.version, Dcr.author,
|
||||
--Dcr.L["HLP_RIGHTCLICK"], Dcr.L["STR_OPTIONS"],
|
||||
Dcr.L["HLP_MIDDLECLICK"], Dcr.L["SHIFT"], Dcr.L["HLP_LEFTCLICK"],
|
||||
Dcr.L["HIDESHOW_BUTTONS"]
|
||||
)
|
||||
, self);
|
||||
end
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
|
||||
<OnMouseUp>
|
||||
if ( self.isMoving ) then
|
||||
self:StopMovingOrSizing();
|
||||
self.isMoving = false;
|
||||
end
|
||||
Dcr:SaveLLPos();
|
||||
</OnMouseUp>
|
||||
<OnMouseDown>
|
||||
if ( ( ( not self.isLocked ) or ( self.isLocked == 0 ) or IsAltKeyDown()) and ( button == "LeftButton" ) ) then
|
||||
self:StartMoving();
|
||||
self.isMoving = true;
|
||||
end
|
||||
if (button == "MiddleButton" or button == "LeftButton" and IsShiftKeyDown()) then
|
||||
Dcr:ShowHideButtons();
|
||||
end
|
||||
</OnMouseDown>
|
||||
<OnHide>
|
||||
if ( self.isMoving ) then
|
||||
self:StopMovingOrSizing();
|
||||
self.isMoving = false;
|
||||
end
|
||||
</OnHide>
|
||||
<OnLOad>
|
||||
self:RegisterEvent("ADDON_LOADED");
|
||||
</OnLOad>
|
||||
<OnEvent>
|
||||
if event == "ADDON_LOADED" and (...) == "Decursive" then
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
T._SelfDiagnostic();
|
||||
self:UnregisterEvent("ADDON_LOADED");
|
||||
end
|
||||
</OnEvent>
|
||||
</Scripts>
|
||||
|
||||
<Frames>
|
||||
<Button name="$parentPriority" inherits="GameMenuButtonTemplate" text="P"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["PRIORITY_SHOW"]);
|
||||
</OnLoad>
|
||||
<OnClick>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic(true) ~= 2 then
|
||||
Dcr:ShowHidePriorityListUI();
|
||||
end
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic() ~= 2 then
|
||||
Dcr:DisplayTooltip(Dcr.L["PRIORITY_LIST"], self);
|
||||
end
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button> <!-- }}} -->
|
||||
|
||||
<Button name="$parentSkip" inherits="GameMenuButtonTemplate" text="S"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentPriority">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnLoad>
|
||||
if DecursiveInstallCorrupted then return end
|
||||
self:SetText(Dcr.L["SKIP_SHOW"]);
|
||||
</OnLoad>
|
||||
<OnClick>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic(true) ~= 2 then
|
||||
Dcr:ShowHideSkipListUI();
|
||||
end
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic() ~= 2 then
|
||||
Dcr:DisplayTooltip(Dcr.L["SKIP_LIST_STR"], self);
|
||||
end
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button> <!-- }}} -->
|
||||
|
||||
<Button name="$parentHide" inherits="GameMenuButtonTemplate" text="X"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="20" y="20" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="LEFT" relativePoint="RIGHT" relativeTo="$parentSkip">
|
||||
<Offset>
|
||||
<AbsDimension x="2" y="0" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
<OnClick>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic(true) ~= 2 then
|
||||
Dcr:HideBar(false);
|
||||
end
|
||||
</OnClick>
|
||||
<OnEnter>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
if T._SelfDiagnostic() ~= 2 then
|
||||
Dcr:DisplayTooltip(Dcr.L["HIDE_MAIN"], self);
|
||||
end
|
||||
</OnEnter>
|
||||
<OnLeave>
|
||||
DcrDisplay_Tooltip:Hide();
|
||||
</OnLeave>
|
||||
</Scripts>
|
||||
</Button> <!-- }}} -->
|
||||
</Frames>
|
||||
|
||||
</Frame> <!-- }}} -->
|
||||
|
||||
<!-- ================================================================== -->
|
||||
|
||||
<Frame name="DecursiveAnchor" frameStrata="HIGH" toplevel="true" enableMouse="true" movable="true" hidden="true" parent="UIParent"> <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="180" y="25"/>
|
||||
</Size>
|
||||
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="UIErrorsFrame" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
|
||||
<TitleRegion setAllPoints="true"/>
|
||||
|
||||
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
|
||||
<EdgeSize>
|
||||
<AbsValue val="16"/>
|
||||
</EdgeSize>
|
||||
<TileSize>
|
||||
<AbsValue val="16"/>
|
||||
</TileSize>
|
||||
<BackgroundInsets>
|
||||
<AbsInset left="5" right="5" top="5" bottom="5"/>
|
||||
</BackgroundInsets>
|
||||
</Backdrop>
|
||||
|
||||
<Layers>
|
||||
<Layer level="BACKGROUND">
|
||||
<FontString name="$parentText" inherits="GameFontNormal" text="ANCHOR">
|
||||
<Anchors>
|
||||
<Anchor point="TOP">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="-5"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
</FontString>
|
||||
</Layer>
|
||||
</Layers>
|
||||
<Frames>
|
||||
<Button name="$parentDirection" inherits="GameMenuButtonTemplate" text=".">
|
||||
<Size>
|
||||
<AbsDimension x="20" y="17" />
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOPRIGHT" relativePoint="TOPRIGHT" relativeTo="$parent">
|
||||
<Offset>
|
||||
<AbsDimension x="-10" y="-4" />
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
<Scripts>
|
||||
|
||||
<OnClick>
|
||||
Dcr.profile.CustomeFrameInsertBottom = (not Dcr.profile.CustomeFrameInsertBottom);
|
||||
Dcr:ChangeTextFrameDirection(Dcr.profile.CustomeFrameInsertBottom);
|
||||
|
||||
Dcr:Println("|cFFAAAAAATEST");
|
||||
|
||||
</OnClick>
|
||||
<OnShow>
|
||||
Dcr:ThisSetParentText(self, Dcr.L["ANCHOR"]);
|
||||
</OnShow>
|
||||
</Scripts>
|
||||
</Button>
|
||||
</Frames>
|
||||
</Frame> <!-- }}} -->
|
||||
|
||||
<MessageFrame name="DecursiveTextFrame" insertMode="TOP" parent="UIParent" frameStrata="HIGH" toplevel="true" > <!-- {{{ -->
|
||||
<Size>
|
||||
<AbsDimension x="600" y="140"/>
|
||||
</Size>
|
||||
<Anchors>
|
||||
<Anchor point="TOP" relativeTo="DecursiveAnchor" relativePoint="BOTTOM">
|
||||
<Offset>
|
||||
<AbsDimension x="0" y="0"/>
|
||||
</Offset>
|
||||
</Anchor>
|
||||
</Anchors>
|
||||
|
||||
<FontString inherits="GameFontNormal" justifyH="CENTER"/>
|
||||
</MessageFrame> <!-- }}} -->
|
||||
|
||||
<GameTooltip name="DcrDisplay_Tooltip" hidden="true" inherits="GameTooltipTemplate" parent="UIParent" />
|
||||
|
||||
<Frame name="Decursive" />
|
||||
|
||||
<Script>
|
||||
local T = DecursiveRootTable or {};
|
||||
|
||||
T._LoadedFiles["Decursive.xml"] = "2.5.1-6-gd3885c5";
|
||||
</Script>
|
||||
|
||||
|
||||
</Ui>
|
||||
@@ -0,0 +1,23 @@
|
||||
|
||||
Decursive add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr
|
||||
Official Website: http://www.2072productions.com/to/decursive.php
|
||||
|
||||
Starting from 2009-10-31 and until said otherwise by its author,
|
||||
Decursive
|
||||
is no longer free software, all rights are reserved to its author (John
|
||||
Wellesz).
|
||||
|
||||
The only official and allowed distribution means are
|
||||
www.2072productions.com, www.wowace.com and curse.com.
|
||||
To distribute Decursive through other means a special authorization is
|
||||
required.
|
||||
|
||||
Decursive is provided free of charge and is free to use, if you paid for
|
||||
it you should ask for a refund.
|
||||
|
||||
Decursive is inspired from the original "Decursive v1.9.4" by Quu.
|
||||
The original "Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
||||
@@ -0,0 +1,30 @@
|
||||
-- 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
|
||||
@@ -0,0 +1,642 @@
|
||||
--- **AceAddon-3.0** provides a template for creating addon objects.
|
||||
-- It'll provide you with a set of callback functions that allow you to simplify the loading
|
||||
-- process of your addon.\\
|
||||
-- Callbacks provided are:\\
|
||||
-- * **OnInitialize**, which is called directly after the addon is fully loaded.
|
||||
-- * **OnEnable** which gets called during the PLAYER_LOGIN event, when most of the data provided by the game is already present.
|
||||
-- * **OnDisable**, which is only called when your addon is manually being disabled.
|
||||
-- @usage
|
||||
-- -- A small (but complete) addon, that doesn't do anything,
|
||||
-- -- but shows usage of the callbacks.
|
||||
-- local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
|
||||
--
|
||||
-- function MyAddon:OnInitialize()
|
||||
-- -- do init tasks here, like loading the Saved Variables,
|
||||
-- -- or setting up slash commands.
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- -- Do more initialization here, that really enables the use of your addon.
|
||||
-- -- Register Events, Hook functions, Create Frames, Get information from
|
||||
-- -- the game that wasn't available in OnInitialize
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:OnDisable()
|
||||
-- -- Unhook, Unregister Events, Hide frames that you created.
|
||||
-- -- You would probably only use an OnDisable if you want to
|
||||
-- -- build a "standby" mode, or be able to toggle modules on/off.
|
||||
-- end
|
||||
-- @class file
|
||||
-- @name AceAddon-3.0.lua
|
||||
-- @release $Id: AceAddon-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
|
||||
|
||||
local MAJOR, MINOR = "AceAddon-3.0", 5
|
||||
local AceAddon, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceAddon then return end -- No Upgrade needed.
|
||||
|
||||
AceAddon.frame = AceAddon.frame or CreateFrame("Frame", "AceAddon30Frame") -- Our very own frame
|
||||
AceAddon.addons = AceAddon.addons or {} -- addons in general
|
||||
AceAddon.statuses = AceAddon.statuses or {} -- statuses of addon.
|
||||
AceAddon.initializequeue = AceAddon.initializequeue or {} -- addons that are new and not initialized
|
||||
AceAddon.enablequeue = AceAddon.enablequeue or {} -- addons that are initialized and waiting to be enabled
|
||||
AceAddon.embeds = AceAddon.embeds or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end }) -- contains a list of libraries embedded in an addon
|
||||
|
||||
-- Lua APIs
|
||||
local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
|
||||
local fmt, tostring = string.format, tostring
|
||||
local select, pairs, next, type, unpack = select, pairs, next, type, unpack
|
||||
local loadstring, assert, error = loadstring, assert, error
|
||||
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: LibStub, IsLoggedIn, geterrorhandler
|
||||
|
||||
--[[
|
||||
xpcall safecall implementation
|
||||
]]
|
||||
local xpcall = xpcall
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
|
||||
local function CreateDispatcher(argCount)
|
||||
local code = [[
|
||||
local xpcall, eh = ...
|
||||
local method, ARGS
|
||||
local function call() return method(ARGS) end
|
||||
|
||||
local function dispatch(func, ...)
|
||||
method = func
|
||||
if not method then return end
|
||||
ARGS = ...
|
||||
return xpcall(call, eh)
|
||||
end
|
||||
|
||||
return dispatch
|
||||
]]
|
||||
|
||||
local ARGS = {}
|
||||
for i = 1, argCount do ARGS[i] = "arg"..i end
|
||||
code = code:gsub("ARGS", tconcat(ARGS, ", "))
|
||||
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
|
||||
end
|
||||
|
||||
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
|
||||
local dispatcher = CreateDispatcher(argCount)
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end})
|
||||
Dispatchers[0] = function(func)
|
||||
return xpcall(func, errorhandler)
|
||||
end
|
||||
|
||||
local function safecall(func, ...)
|
||||
-- we check to see if the func is passed is actually a function here and don't error when it isn't
|
||||
-- this safecall is used for optional functions like OnInitialize OnEnable etc. When they are not
|
||||
-- present execution should continue without hinderance
|
||||
if type(func) == "function" then
|
||||
return Dispatchers[select('#', ...)](func, ...)
|
||||
end
|
||||
end
|
||||
|
||||
-- local functions that will be implemented further down
|
||||
local Enable, Disable, EnableModule, DisableModule, Embed, NewModule, GetModule, GetName, SetDefaultModuleState, SetDefaultModuleLibraries, SetEnabledState, SetDefaultModulePrototype
|
||||
|
||||
-- used in the addon metatable
|
||||
local function addontostring( self ) return self.name end
|
||||
|
||||
--- Create a new AceAddon-3.0 addon.
|
||||
-- Any libraries you specified will be embeded, and the addon will be scheduled for
|
||||
-- its OnInitialize and OnEnable callbacks.
|
||||
-- The final addon object, with all libraries embeded, will be returned.
|
||||
-- @paramsig [object ,]name[, lib, ...]
|
||||
-- @param object Table to use as a base for the addon (optional)
|
||||
-- @param name Name of the addon object to create
|
||||
-- @param lib List of libraries to embed into the addon
|
||||
-- @usage
|
||||
-- -- Create a simple addon object
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceEvent-3.0")
|
||||
--
|
||||
-- -- Create a Addon object based on the table of a frame
|
||||
-- local MyFrame = CreateFrame("Frame")
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon(MyFrame, "MyAddon", "AceEvent-3.0")
|
||||
function AceAddon:NewAddon(objectorname, ...)
|
||||
local object,name
|
||||
local i=1
|
||||
if type(objectorname)=="table" then
|
||||
object=objectorname
|
||||
name=...
|
||||
i=2
|
||||
else
|
||||
name=objectorname
|
||||
end
|
||||
if type(name)~="string" then
|
||||
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2)
|
||||
end
|
||||
if self.addons[name] then
|
||||
error(("Usage: NewAddon([object,] name, [lib, lib, lib, ...]): 'name' - Addon '%s' already exists."):format(name), 2)
|
||||
end
|
||||
|
||||
object = object or {}
|
||||
object.name = name
|
||||
|
||||
local addonmeta = {}
|
||||
local oldmeta = getmetatable(object)
|
||||
if oldmeta then
|
||||
for k, v in pairs(oldmeta) do addonmeta[k] = v end
|
||||
end
|
||||
addonmeta.__tostring = addontostring
|
||||
|
||||
setmetatable( object, addonmeta )
|
||||
self.addons[name] = object
|
||||
object.modules = {}
|
||||
object.defaultModuleLibraries = {}
|
||||
Embed( object ) -- embed NewModule, GetModule methods
|
||||
self:EmbedLibraries(object, select(i,...))
|
||||
|
||||
-- add to queue of addons to be initialized upon ADDON_LOADED
|
||||
tinsert(self.initializequeue, object)
|
||||
return object
|
||||
end
|
||||
|
||||
|
||||
--- Get the addon object by its name from the internal AceAddon registry.
|
||||
-- Throws an error if the addon object cannot be found (except if silent is set).
|
||||
-- @param name unique name of the addon object
|
||||
-- @param silent if true, the addon is optional, silently return nil if its not found
|
||||
-- @usage
|
||||
-- -- Get the Addon
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
function AceAddon:GetAddon(name, silent)
|
||||
if not silent and not self.addons[name] then
|
||||
error(("Usage: GetAddon(name): 'name' - Cannot find an AceAddon '%s'."):format(tostring(name)), 2)
|
||||
end
|
||||
return self.addons[name]
|
||||
end
|
||||
|
||||
-- - Embed a list of libraries into the specified addon.
|
||||
-- This function will try to embed all of the listed libraries into the addon
|
||||
-- and error if a single one fails.
|
||||
--
|
||||
-- **Note:** This function is for internal use by :NewAddon/:NewModule
|
||||
-- @paramsig addon, [lib, ...]
|
||||
-- @param addon addon object to embed the libs in
|
||||
-- @param lib List of libraries to embed into the addon
|
||||
function AceAddon:EmbedLibraries(addon, ...)
|
||||
for i=1,select("#", ... ) do
|
||||
local libname = select(i, ...)
|
||||
self:EmbedLibrary(addon, libname, false, 4)
|
||||
end
|
||||
end
|
||||
|
||||
-- - Embed a library into the addon object.
|
||||
-- This function will check if the specified library is registered with LibStub
|
||||
-- and if it has a :Embed function to call. It'll error if any of those conditions
|
||||
-- fails.
|
||||
--
|
||||
-- **Note:** This function is for internal use by :EmbedLibraries
|
||||
-- @paramsig addon, libname[, silent[, offset]]
|
||||
-- @param addon addon object to embed the library in
|
||||
-- @param libname name of the library to embed
|
||||
-- @param silent marks an embed to fail silently if the library doesn't exist (optional)
|
||||
-- @param offset will push the error messages back to said offset, defaults to 2 (optional)
|
||||
function AceAddon:EmbedLibrary(addon, libname, silent, offset)
|
||||
local lib = LibStub:GetLibrary(libname, true)
|
||||
if not lib and not silent then
|
||||
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Cannot find a library instance of %q."):format(tostring(libname)), offset or 2)
|
||||
elseif lib and type(lib.Embed) == "function" then
|
||||
lib:Embed(addon)
|
||||
tinsert(self.embeds[addon], libname)
|
||||
return true
|
||||
elseif lib then
|
||||
error(("Usage: EmbedLibrary(addon, libname, silent, offset): 'libname' - Library '%s' is not Embed capable"):format(libname), offset or 2)
|
||||
end
|
||||
end
|
||||
|
||||
--- Return the specified module from an addon object.
|
||||
-- Throws an error if the addon object cannot be found (except if silent is set)
|
||||
-- @name //addon//:GetModule
|
||||
-- @paramsig name[, silent]
|
||||
-- @param name unique name of the module
|
||||
-- @param silent if true, the module is optional, silently return nil if its not found (optional)
|
||||
-- @usage
|
||||
-- -- Get the Addon
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- -- Get the Module
|
||||
-- MyModule = MyAddon:GetModule("MyModule")
|
||||
function GetModule(self, name, silent)
|
||||
if not self.modules[name] and not silent then
|
||||
error(("Usage: GetModule(name, silent): 'name' - Cannot find module '%s'."):format(tostring(name)), 2)
|
||||
end
|
||||
return self.modules[name]
|
||||
end
|
||||
|
||||
local function IsModuleTrue(self) return true end
|
||||
|
||||
--- Create a new module for the addon.
|
||||
-- The new module can have its own embeded libraries and/or use a module prototype to be mixed into the module.\\
|
||||
-- A module has the same functionality as a real addon, it can have modules of its own, and has the same API as
|
||||
-- an addon object.
|
||||
-- @name //addon//:NewModule
|
||||
-- @paramsig name[, prototype|lib[, lib, ...]]
|
||||
-- @param name unique name of the module
|
||||
-- @param prototype object to derive this module from, methods and values from this table will be mixed into the module (optional)
|
||||
-- @param lib List of libraries to embed into the addon
|
||||
-- @usage
|
||||
-- -- Create a module with some embeded libraries
|
||||
-- MyModule = MyAddon:NewModule("MyModule", "AceEvent-3.0", "AceHook-3.0")
|
||||
--
|
||||
-- -- Create a module with a prototype
|
||||
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
|
||||
-- MyModule = MyAddon:NewModule("MyModule", prototype, "AceEvent-3.0", "AceHook-3.0")
|
||||
function NewModule(self, name, prototype, ...)
|
||||
if type(name) ~= "string" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - string expected got '%s'."):format(type(name)), 2) end
|
||||
if type(prototype) ~= "string" and type(prototype) ~= "table" and type(prototype) ~= "nil" then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'prototype' - table (prototype), string (lib) or nil expected got '%s'."):format(type(prototype)), 2) end
|
||||
|
||||
if self.modules[name] then error(("Usage: NewModule(name, [prototype, [lib, lib, lib, ...]): 'name' - Module '%s' already exists."):format(name), 2) end
|
||||
|
||||
-- modules are basically addons. We treat them as such. They will be added to the initializequeue properly as well.
|
||||
-- NewModule can only be called after the parent addon is present thus the modules will be initialized after their parent is.
|
||||
local module = AceAddon:NewAddon(fmt("%s_%s", self.name or tostring(self), name))
|
||||
|
||||
module.IsModule = IsModuleTrue
|
||||
module:SetEnabledState(self.defaultModuleState)
|
||||
module.moduleName = name
|
||||
|
||||
if type(prototype) == "string" then
|
||||
AceAddon:EmbedLibraries(module, prototype, ...)
|
||||
else
|
||||
AceAddon:EmbedLibraries(module, ...)
|
||||
end
|
||||
AceAddon:EmbedLibraries(module, unpack(self.defaultModuleLibraries))
|
||||
|
||||
if not prototype or type(prototype) == "string" then
|
||||
prototype = self.defaultModulePrototype or nil
|
||||
end
|
||||
|
||||
if type(prototype) == "table" then
|
||||
local mt = getmetatable(module)
|
||||
mt.__index = prototype
|
||||
setmetatable(module, mt) -- More of a Base class type feel.
|
||||
end
|
||||
|
||||
safecall(self.OnModuleCreated, self, module) -- Was in Ace2 and I think it could be a cool thing to have handy.
|
||||
self.modules[name] = module
|
||||
|
||||
return module
|
||||
end
|
||||
|
||||
--- Returns the real name of the addon or module, without any prefix.
|
||||
-- @name //addon//:GetName
|
||||
-- @paramsig
|
||||
-- @usage
|
||||
-- print(MyAddon:GetName())
|
||||
-- -- prints "MyAddon"
|
||||
function GetName(self)
|
||||
return self.moduleName or self.name
|
||||
end
|
||||
|
||||
--- Enables the Addon, if possible, return true or false depending on success.
|
||||
-- This internally calls AceAddon:EnableAddon(), thus dispatching a OnEnable callback
|
||||
-- and enabling all modules of the addon (unless explicitly disabled).\\
|
||||
-- :Enable() also sets the internal `enableState` variable to true
|
||||
-- @name //addon//:Enable
|
||||
-- @paramsig
|
||||
-- @usage
|
||||
-- -- Enable MyModule
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyModule = MyAddon:GetModule("MyModule")
|
||||
-- MyModule:Enable()
|
||||
function Enable(self)
|
||||
self:SetEnabledState(true)
|
||||
return AceAddon:EnableAddon(self)
|
||||
end
|
||||
|
||||
--- Disables the Addon, if possible, return true or false depending on success.
|
||||
-- This internally calls AceAddon:DisableAddon(), thus dispatching a OnDisable callback
|
||||
-- and disabling all modules of the addon.\\
|
||||
-- :Disable() also sets the internal `enableState` variable to false
|
||||
-- @name //addon//:Disable
|
||||
-- @paramsig
|
||||
-- @usage
|
||||
-- -- Disable MyAddon
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyAddon:Disable()
|
||||
function Disable(self)
|
||||
self:SetEnabledState(false)
|
||||
return AceAddon:DisableAddon(self)
|
||||
end
|
||||
|
||||
--- Enables the Module, if possible, return true or false depending on success.
|
||||
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Enable` on the module object.
|
||||
-- @name //addon//:EnableModule
|
||||
-- @paramsig name
|
||||
-- @usage
|
||||
-- -- Enable MyModule using :GetModule
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyModule = MyAddon:GetModule("MyModule")
|
||||
-- MyModule:Enable()
|
||||
--
|
||||
-- -- Enable MyModule using the short-hand
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyAddon:EnableModule("MyModule")
|
||||
function EnableModule(self, name)
|
||||
local module = self:GetModule( name )
|
||||
return module:Enable()
|
||||
end
|
||||
|
||||
--- Disables the Module, if possible, return true or false depending on success.
|
||||
-- Short-hand function that retrieves the module via `:GetModule` and calls `:Disable` on the module object.
|
||||
-- @name //addon//:DisableModule
|
||||
-- @paramsig name
|
||||
-- @usage
|
||||
-- -- Disable MyModule using :GetModule
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyModule = MyAddon:GetModule("MyModule")
|
||||
-- MyModule:Disable()
|
||||
--
|
||||
-- -- Disable MyModule using the short-hand
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):GetAddon("MyAddon")
|
||||
-- MyAddon:DisableModule("MyModule")
|
||||
function DisableModule(self, name)
|
||||
local module = self:GetModule( name )
|
||||
return module:Disable()
|
||||
end
|
||||
|
||||
--- Set the default libraries to be mixed into all modules created by this object.
|
||||
-- Note that you can only change the default module libraries before any module is created.
|
||||
-- @name //addon//:SetDefaultModuleLibraries
|
||||
-- @paramsig lib[, lib, ...]
|
||||
-- @param lib List of libraries to embed into the addon
|
||||
-- @usage
|
||||
-- -- Create the addon object
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
|
||||
-- -- Configure default libraries for modules (all modules need AceEvent-3.0)
|
||||
-- MyAddon:SetDefaultModuleLibraries("AceEvent-3.0")
|
||||
-- -- Create a module
|
||||
-- MyModule = MyAddon:NewModule("MyModule")
|
||||
function SetDefaultModuleLibraries(self, ...)
|
||||
if next(self.modules) then
|
||||
error("Usage: SetDefaultModuleLibraries(...): cannot change the module defaults after a module has been registered.", 2)
|
||||
end
|
||||
self.defaultModuleLibraries = {...}
|
||||
end
|
||||
|
||||
--- Set the default state in which new modules are being created.
|
||||
-- Note that you can only change the default state before any module is created.
|
||||
-- @name //addon//:SetDefaultModuleState
|
||||
-- @paramsig state
|
||||
-- @param state Default state for new modules, true for enabled, false for disabled
|
||||
-- @usage
|
||||
-- -- Create the addon object
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
|
||||
-- -- Set the default state to "disabled"
|
||||
-- MyAddon:SetDefaultModuleState(false)
|
||||
-- -- Create a module and explicilty enable it
|
||||
-- MyModule = MyAddon:NewModule("MyModule")
|
||||
-- MyModule:Enable()
|
||||
function SetDefaultModuleState(self, state)
|
||||
if next(self.modules) then
|
||||
error("Usage: SetDefaultModuleState(state): cannot change the module defaults after a module has been registered.", 2)
|
||||
end
|
||||
self.defaultModuleState = state
|
||||
end
|
||||
|
||||
--- Set the default prototype to use for new modules on creation.
|
||||
-- Note that you can only change the default prototype before any module is created.
|
||||
-- @name //addon//:SetDefaultModulePrototype
|
||||
-- @paramsig prototype
|
||||
-- @param prototype Default prototype for the new modules (table)
|
||||
-- @usage
|
||||
-- -- Define a prototype
|
||||
-- local prototype = { OnEnable = function(self) print("OnEnable called!") end }
|
||||
-- -- Set the default prototype
|
||||
-- MyAddon:SetDefaultModulePrototype(prototype)
|
||||
-- -- Create a module and explicitly Enable it
|
||||
-- MyModule = MyAddon:NewModule("MyModule")
|
||||
-- MyModule:Enable()
|
||||
-- -- should print "OnEnable called!" now
|
||||
-- @see NewModule
|
||||
function SetDefaultModulePrototype(self, prototype)
|
||||
if next(self.modules) then
|
||||
error("Usage: SetDefaultModulePrototype(prototype): cannot change the module defaults after a module has been registered.", 2)
|
||||
end
|
||||
if type(prototype) ~= "table" then
|
||||
error(("Usage: SetDefaultModulePrototype(prototype): 'prototype' - table expected got '%s'."):format(type(prototype)), 2)
|
||||
end
|
||||
self.defaultModulePrototype = prototype
|
||||
end
|
||||
|
||||
--- Set the state of an addon or module
|
||||
-- This should only be called before any enabling actually happend, e.g. in/before OnInitialize.
|
||||
-- @name //addon//:SetEnabledState
|
||||
-- @paramsig state
|
||||
-- @param state the state of an addon or module (enabled=true, disabled=false)
|
||||
function SetEnabledState(self, state)
|
||||
self.enabledState = state
|
||||
end
|
||||
|
||||
|
||||
--- Return an iterator of all modules associated to the addon.
|
||||
-- @name //addon//:IterateModules
|
||||
-- @paramsig
|
||||
-- @usage
|
||||
-- -- Enable all modules
|
||||
-- for name, module in MyAddon:IterateModules() do
|
||||
-- module:Enable()
|
||||
-- end
|
||||
local function IterateModules(self) return pairs(self.modules) end
|
||||
|
||||
-- Returns an iterator of all embeds in the addon
|
||||
-- @name //addon//:IterateEmbeds
|
||||
-- @paramsig
|
||||
local function IterateEmbeds(self) return pairs(AceAddon.embeds[self]) end
|
||||
|
||||
--- Query the enabledState of an addon.
|
||||
-- @name //addon//:IsEnabled
|
||||
-- @paramsig
|
||||
-- @usage
|
||||
-- if MyAddon:IsEnabled() then
|
||||
-- MyAddon:Disable()
|
||||
-- end
|
||||
local function IsEnabled(self) return self.enabledState end
|
||||
local mixins = {
|
||||
NewModule = NewModule,
|
||||
GetModule = GetModule,
|
||||
Enable = Enable,
|
||||
Disable = Disable,
|
||||
EnableModule = EnableModule,
|
||||
DisableModule = DisableModule,
|
||||
IsEnabled = IsEnabled,
|
||||
SetDefaultModuleLibraries = SetDefaultModuleLibraries,
|
||||
SetDefaultModuleState = SetDefaultModuleState,
|
||||
SetDefaultModulePrototype = SetDefaultModulePrototype,
|
||||
SetEnabledState = SetEnabledState,
|
||||
IterateModules = IterateModules,
|
||||
IterateEmbeds = IterateEmbeds,
|
||||
GetName = GetName,
|
||||
}
|
||||
local function IsModule(self) return false end
|
||||
local pmixins = {
|
||||
defaultModuleState = true,
|
||||
enabledState = true,
|
||||
IsModule = IsModule,
|
||||
}
|
||||
-- Embed( target )
|
||||
-- target (object) - target object to embed aceaddon in
|
||||
--
|
||||
-- this is a local function specifically since it's meant to be only called internally
|
||||
function Embed(target)
|
||||
for k, v in pairs(mixins) do
|
||||
target[k] = v
|
||||
end
|
||||
for k, v in pairs(pmixins) do
|
||||
target[k] = target[k] or v
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- - Initialize the addon after creation.
|
||||
-- This function is only used internally during the ADDON_LOADED event
|
||||
-- It will call the **OnInitialize** function on the addon object (if present),
|
||||
-- and the **OnEmbedInitialize** function on all embeded libraries.
|
||||
--
|
||||
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
|
||||
-- @param addon addon object to intialize
|
||||
function AceAddon:InitializeAddon(addon)
|
||||
safecall(addon.OnInitialize, addon)
|
||||
|
||||
local embeds = self.embeds[addon]
|
||||
for i = 1, #embeds do
|
||||
local lib = LibStub:GetLibrary(embeds[i], true)
|
||||
if lib then safecall(lib.OnEmbedInitialize, lib, addon) end
|
||||
end
|
||||
|
||||
-- we don't call InitializeAddon on modules specifically, this is handled
|
||||
-- from the event handler and only done _once_
|
||||
end
|
||||
|
||||
-- - Enable the addon after creation.
|
||||
-- Note: This function is only used internally during the PLAYER_LOGIN event, or during ADDON_LOADED,
|
||||
-- if IsLoggedIn() already returns true at that point, e.g. for LoD Addons.
|
||||
-- It will call the **OnEnable** function on the addon object (if present),
|
||||
-- and the **OnEmbedEnable** function on all embeded libraries.\\
|
||||
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is disabled.
|
||||
--
|
||||
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
|
||||
-- Use :Enable on the addon itself instead.
|
||||
-- @param addon addon object to enable
|
||||
function AceAddon:EnableAddon(addon)
|
||||
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
|
||||
if self.statuses[addon.name] or not addon.enabledState then return false end
|
||||
|
||||
-- set the statuses first, before calling the OnEnable. this allows for Disabling of the addon in OnEnable.
|
||||
self.statuses[addon.name] = true
|
||||
|
||||
safecall(addon.OnEnable, addon)
|
||||
|
||||
-- make sure we're still enabled before continueing
|
||||
if self.statuses[addon.name] then
|
||||
local embeds = self.embeds[addon]
|
||||
for i = 1, #embeds do
|
||||
local lib = LibStub:GetLibrary(embeds[i], true)
|
||||
if lib then safecall(lib.OnEmbedEnable, lib, addon) end
|
||||
end
|
||||
|
||||
-- enable possible modules.
|
||||
for name, module in pairs(addon.modules) do
|
||||
self:EnableAddon(module)
|
||||
end
|
||||
end
|
||||
return self.statuses[addon.name] -- return true if we're disabled
|
||||
end
|
||||
|
||||
-- - Disable the addon
|
||||
-- Note: This function is only used internally.
|
||||
-- It will call the **OnDisable** function on the addon object (if present),
|
||||
-- and the **OnEmbedDisable** function on all embeded libraries.\\
|
||||
-- This function does not toggle the enable state of the addon itself, and will return early if the addon is still enabled.
|
||||
--
|
||||
-- **Note:** Do not call this function manually, unless you're absolutely sure that you know what you are doing.
|
||||
-- Use :Disable on the addon itself instead.
|
||||
-- @param addon addon object to enable
|
||||
function AceAddon:DisableAddon(addon)
|
||||
if type(addon) == "string" then addon = AceAddon:GetAddon(addon) end
|
||||
if not self.statuses[addon.name] then return false end
|
||||
|
||||
-- set statuses first before calling OnDisable, this allows for aborting the disable in OnDisable.
|
||||
self.statuses[addon.name] = false
|
||||
|
||||
safecall( addon.OnDisable, addon )
|
||||
|
||||
-- make sure we're still disabling...
|
||||
if not self.statuses[addon.name] then
|
||||
local embeds = self.embeds[addon]
|
||||
for i = 1, #embeds do
|
||||
local lib = LibStub:GetLibrary(embeds[i], true)
|
||||
if lib then safecall(lib.OnEmbedDisable, lib, addon) end
|
||||
end
|
||||
-- disable possible modules.
|
||||
for name, module in pairs(addon.modules) do
|
||||
self:DisableAddon(module)
|
||||
end
|
||||
end
|
||||
|
||||
return not self.statuses[addon.name] -- return true if we're disabled
|
||||
end
|
||||
|
||||
--- Get an iterator over all registered addons.
|
||||
-- @usage
|
||||
-- -- Print a list of all installed AceAddon's
|
||||
-- for name, addon in AceAddon:IterateAddons() do
|
||||
-- print("Addon: " .. name)
|
||||
-- end
|
||||
function AceAddon:IterateAddons() return pairs(self.addons) end
|
||||
|
||||
--- Get an iterator over the internal status registry.
|
||||
-- @usage
|
||||
-- -- Print a list of all enabled addons
|
||||
-- for name, status in AceAddon:IterateAddonStatus() do
|
||||
-- if status then
|
||||
-- print("EnabledAddon: " .. name)
|
||||
-- end
|
||||
-- end
|
||||
function AceAddon:IterateAddonStatus() return pairs(self.statuses) end
|
||||
|
||||
-- Following Iterators are deprecated, and their addon specific versions should be used
|
||||
-- e.g. addon:IterateEmbeds() instead of :IterateEmbedsOnAddon(addon)
|
||||
function AceAddon:IterateEmbedsOnAddon(addon) return pairs(self.embeds[addon]) end
|
||||
function AceAddon:IterateModulesOfAddon(addon) return pairs(addon.modules) end
|
||||
|
||||
-- Event Handling
|
||||
local function onEvent(this, event, arg1)
|
||||
if event == "ADDON_LOADED" or event == "PLAYER_LOGIN" then
|
||||
-- if a addon loads another addon, recursion could happen here, so we need to validate the table on every iteration
|
||||
while(#AceAddon.initializequeue > 0) do
|
||||
local addon = tremove(AceAddon.initializequeue, 1)
|
||||
-- this might be an issue with recursion - TODO: validate
|
||||
if event == "ADDON_LOADED" then addon.baseName = arg1 end
|
||||
AceAddon:InitializeAddon(addon)
|
||||
tinsert(AceAddon.enablequeue, addon)
|
||||
end
|
||||
|
||||
if IsLoggedIn() then
|
||||
while(#AceAddon.enablequeue > 0) do
|
||||
local addon = tremove(AceAddon.enablequeue, 1)
|
||||
AceAddon:EnableAddon(addon)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
AceAddon.frame:RegisterEvent("ADDON_LOADED")
|
||||
AceAddon.frame:RegisterEvent("PLAYER_LOGIN")
|
||||
AceAddon.frame:SetScript("OnEvent", onEvent)
|
||||
|
||||
-- upgrade embeded
|
||||
for name, addon in pairs(AceAddon.addons) do
|
||||
Embed(addon)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceAddon-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,309 @@
|
||||
--- **AceComm-3.0** allows you to send messages of unlimited length over the addon comm channels.
|
||||
-- It'll automatically split the messages into multiple parts and rebuild them on the receiving end.\\
|
||||
-- **ChatThrottleLib** is of course being used to avoid being disconnected by the server.
|
||||
--
|
||||
-- **AceComm-3.0** can be embeded into your addon, either explicitly by calling AceComm:Embed(MyAddon) or by
|
||||
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
|
||||
-- and can be accessed directly, without having to explicitly call AceComm itself.\\
|
||||
-- It is recommended to embed AceComm, otherwise you'll have to specify a custom `self` on all calls you
|
||||
-- make into AceComm.
|
||||
-- @class file
|
||||
-- @name AceComm-3.0
|
||||
-- @release $Id: AceComm-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
|
||||
|
||||
--[[ AceComm-3.0
|
||||
|
||||
TODO: Time out old data rotting around from dead senders? Not a HUGE deal since the number of possible sender names is somewhat limited.
|
||||
|
||||
]]
|
||||
|
||||
local MAJOR, MINOR = "AceComm-3.0", 6
|
||||
|
||||
local AceComm,oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceComm then return end
|
||||
|
||||
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
|
||||
local CTL = assert(ChatThrottleLib, "AceComm-3.0 requires ChatThrottleLib")
|
||||
|
||||
-- Lua APIs
|
||||
local type, next, pairs, tostring = type, next, pairs, tostring
|
||||
local strsub, strfind = string.sub, string.find
|
||||
local tinsert, tconcat = table.insert, table.concat
|
||||
local error, assert = error, assert
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: LibStub, DEFAULT_CHAT_FRAME, geterrorhandler
|
||||
|
||||
AceComm.embeds = AceComm.embeds or {}
|
||||
|
||||
-- for my sanity and yours, let's give the message type bytes some names
|
||||
local MSG_MULTI_FIRST = "\001"
|
||||
local MSG_MULTI_NEXT = "\002"
|
||||
local MSG_MULTI_LAST = "\003"
|
||||
|
||||
AceComm.multipart_origprefixes = AceComm.multipart_origprefixes or {} -- e.g. "Prefix\001"="Prefix", "Prefix\002"="Prefix"
|
||||
AceComm.multipart_reassemblers = AceComm.multipart_reassemblers or {} -- e.g. "Prefix\001"="OnReceiveMultipartFirst"
|
||||
|
||||
-- the multipart message spool: indexed by a combination of sender+distribution+
|
||||
AceComm.multipart_spool = AceComm.multipart_spool or {}
|
||||
|
||||
--- Register for Addon Traffic on a specified prefix
|
||||
-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
|
||||
-- @param method Callback to call on message reception: Function reference, or method name (string) to call on self. Defaults to "OnCommReceived"
|
||||
function AceComm:RegisterComm(prefix, method)
|
||||
if method == nil then
|
||||
method = "OnCommReceived"
|
||||
end
|
||||
|
||||
return AceComm._RegisterComm(self, prefix, method) -- created by CallbackHandler
|
||||
end
|
||||
|
||||
local warnedPrefix=false
|
||||
|
||||
--- Send a message over the Addon Channel
|
||||
-- @param prefix A printable character (\032-\255) classification of the message (typically AddonName or AddonNameEvent)
|
||||
-- @param text Data to send, nils (\000) not allowed. Any length.
|
||||
-- @param distribution Addon channel, e.g. "RAID", "GUILD", etc; see SendAddonMessage API
|
||||
-- @param target Destination for some distributions; see SendAddonMessage API
|
||||
-- @param prio OPTIONAL: ChatThrottleLib priority, "BULK", "NORMAL" or "ALERT". Defaults to "NORMAL".
|
||||
-- @param callbackFn OPTIONAL: callback function to be called as each chunk is sent. receives 3 args: the user supplied arg (see next), the number of bytes sent so far, and the number of bytes total to send.
|
||||
-- @param callbackArg: OPTIONAL: first arg to the callback function. nil will be passed if not specified.
|
||||
function AceComm:SendCommMessage(prefix, text, distribution, target, prio, callbackFn, callbackArg)
|
||||
prio = prio or "NORMAL" -- pasta's reference implementation had different prio for singlepart and multipart, but that's a very bad idea since that can easily lead to out-of-sequence delivery!
|
||||
if not( type(prefix)=="string" and
|
||||
type(text)=="string" and
|
||||
type(distribution)=="string" and
|
||||
(target==nil or type(target)=="string") and
|
||||
(prio=="BULK" or prio=="NORMAL" or prio=="ALERT")
|
||||
) then
|
||||
error('Usage: SendCommMessage(addon, "prefix", "text", "distribution"[, "target"[, "prio"[, callbackFn, callbackarg]]])', 2)
|
||||
end
|
||||
|
||||
if strfind(prefix, "[\001-\009]") then
|
||||
if strfind(prefix, "[\001-\003]") then
|
||||
error("SendCommMessage: Characters \\001--\\003 in prefix are reserved for AceComm metadata", 2)
|
||||
elseif not warnedPrefix then
|
||||
-- I have some ideas about future extensions that require more control characters /mikk, 20090808
|
||||
geterrorhandler()("SendCommMessage: Heads-up developers: Characters \\004--\\009 in prefix are reserved for AceComm future extension")
|
||||
warnedPrefix = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local textlen = #text
|
||||
local maxtextlen = 254 - #prefix -- 254 is the max length of prefix + text that can be sent in one message
|
||||
local queueName = prefix..distribution..(target or "")
|
||||
|
||||
local ctlCallback = nil
|
||||
if callbackFn then
|
||||
ctlCallback = function(sent)
|
||||
return callbackFn(callbackArg, sent, textlen)
|
||||
end
|
||||
end
|
||||
|
||||
if textlen <= maxtextlen then
|
||||
-- fits all in one message
|
||||
CTL:SendAddonMessage(prio, prefix, text, distribution, target, queueName, ctlCallback, textlen)
|
||||
else
|
||||
maxtextlen = maxtextlen - 1 -- 1 extra byte for part indicator in prefix
|
||||
|
||||
-- first part
|
||||
local chunk = strsub(text, 1, maxtextlen)
|
||||
CTL:SendAddonMessage(prio, prefix..MSG_MULTI_FIRST, chunk, distribution, target, queueName, ctlCallback, maxtextlen)
|
||||
|
||||
-- continuation
|
||||
local pos = 1+maxtextlen
|
||||
local prefix2 = prefix..MSG_MULTI_NEXT
|
||||
|
||||
while pos+maxtextlen <= textlen do
|
||||
chunk = strsub(text, pos, pos+maxtextlen-1)
|
||||
CTL:SendAddonMessage(prio, prefix2, chunk, distribution, target, queueName, ctlCallback, pos+maxtextlen-1)
|
||||
pos = pos + maxtextlen
|
||||
end
|
||||
|
||||
-- final part
|
||||
chunk = strsub(text, pos)
|
||||
CTL:SendAddonMessage(prio, prefix..MSG_MULTI_LAST, chunk, distribution, target, queueName, ctlCallback, textlen)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------
|
||||
-- Message receiving
|
||||
----------------------------------------
|
||||
|
||||
do
|
||||
local compost = setmetatable({}, {__mode = "k"})
|
||||
local function new()
|
||||
local t = next(compost)
|
||||
if t then
|
||||
compost[t]=nil
|
||||
for i=#t,3,-1 do -- faster than pairs loop. don't even nil out 1/2 since they'll be overwritten
|
||||
t[i]=nil
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
return {}
|
||||
end
|
||||
|
||||
local function lostdatawarning(prefix,sender,where)
|
||||
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: lost network data regarding '"..tostring(prefix).."' from '"..tostring(sender).."' (in "..where..")")
|
||||
end
|
||||
|
||||
function AceComm:OnReceiveMultipartFirst(prefix, message, distribution, sender)
|
||||
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
|
||||
local spool = AceComm.multipart_spool
|
||||
|
||||
--[[
|
||||
if spool[key] then
|
||||
lostdatawarning(prefix,sender,"First")
|
||||
-- continue and overwrite
|
||||
end
|
||||
--]]
|
||||
|
||||
spool[key] = message -- plain string for now
|
||||
end
|
||||
|
||||
function AceComm:OnReceiveMultipartNext(prefix, message, distribution, sender)
|
||||
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
|
||||
local spool = AceComm.multipart_spool
|
||||
local olddata = spool[key]
|
||||
|
||||
if not olddata then
|
||||
--lostdatawarning(prefix,sender,"Next")
|
||||
return
|
||||
end
|
||||
|
||||
if type(olddata)~="table" then
|
||||
-- ... but what we have is not a table. So make it one. (Pull a composted one if available)
|
||||
local t = new()
|
||||
t[1] = olddata -- add old data as first string
|
||||
t[2] = message -- and new message as second string
|
||||
spool[key] = t -- and put the table in the spool instead of the old string
|
||||
else
|
||||
tinsert(olddata, message)
|
||||
end
|
||||
end
|
||||
|
||||
function AceComm:OnReceiveMultipartLast(prefix, message, distribution, sender)
|
||||
local key = prefix.."\t"..distribution.."\t"..sender -- a unique stream is defined by the prefix + distribution + sender
|
||||
local spool = AceComm.multipart_spool
|
||||
local olddata = spool[key]
|
||||
|
||||
if not olddata then
|
||||
--lostdatawarning(prefix,sender,"End")
|
||||
return
|
||||
end
|
||||
|
||||
spool[key] = nil
|
||||
|
||||
if type(olddata) == "table" then
|
||||
-- if we've received a "next", the spooled data will be a table for rapid & garbage-free tconcat
|
||||
tinsert(olddata, message)
|
||||
AceComm.callbacks:Fire(prefix, tconcat(olddata, ""), distribution, sender)
|
||||
compost[olddata] = true
|
||||
else
|
||||
-- if we've only received a "first", the spooled data will still only be a string
|
||||
AceComm.callbacks:Fire(prefix, olddata..message, distribution, sender)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------------------
|
||||
-- Embed CallbackHandler
|
||||
----------------------------------------
|
||||
|
||||
if not AceComm.callbacks then
|
||||
-- ensure that 'prefix to watch' table is consistent with registered
|
||||
-- callbacks
|
||||
AceComm.__prefixes = {}
|
||||
|
||||
AceComm.callbacks = CallbackHandler:New(AceComm,
|
||||
"_RegisterComm",
|
||||
"UnregisterComm",
|
||||
"UnregisterAllComm")
|
||||
end
|
||||
|
||||
function AceComm.callbacks:OnUsed(target, prefix)
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = prefix
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = "OnReceiveMultipartFirst"
|
||||
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = prefix
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = "OnReceiveMultipartNext"
|
||||
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = prefix
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = "OnReceiveMultipartLast"
|
||||
end
|
||||
|
||||
function AceComm.callbacks:OnUnused(target, prefix)
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_FIRST] = nil
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_FIRST] = nil
|
||||
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_NEXT] = nil
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_NEXT] = nil
|
||||
|
||||
AceComm.multipart_origprefixes[prefix..MSG_MULTI_LAST] = nil
|
||||
AceComm.multipart_reassemblers[prefix..MSG_MULTI_LAST] = nil
|
||||
end
|
||||
|
||||
local function OnEvent(this, event, ...)
|
||||
if event == "CHAT_MSG_ADDON" then
|
||||
local prefix,message,distribution,sender = ...
|
||||
local reassemblername = AceComm.multipart_reassemblers[prefix]
|
||||
if reassemblername then
|
||||
-- multipart: reassemble
|
||||
local aceCommReassemblerFunc = AceComm[reassemblername]
|
||||
local origprefix = AceComm.multipart_origprefixes[prefix]
|
||||
aceCommReassemblerFunc(AceComm, origprefix, message, distribution, sender)
|
||||
else
|
||||
-- single part: fire it off immediately and let CallbackHandler decide if it's registered or not
|
||||
AceComm.callbacks:Fire(prefix, message, distribution, sender)
|
||||
end
|
||||
else
|
||||
assert(false, "Received "..tostring(event).." event?!")
|
||||
end
|
||||
end
|
||||
|
||||
AceComm.frame = AceComm.frame or CreateFrame("Frame", "AceComm30Frame")
|
||||
AceComm.frame:SetScript("OnEvent", OnEvent)
|
||||
AceComm.frame:UnregisterAllEvents()
|
||||
AceComm.frame:RegisterEvent("CHAT_MSG_ADDON")
|
||||
|
||||
|
||||
----------------------------------------
|
||||
-- Base library stuff
|
||||
----------------------------------------
|
||||
|
||||
local mixins = {
|
||||
"RegisterComm",
|
||||
"UnregisterComm",
|
||||
"UnregisterAllComm",
|
||||
"SendCommMessage",
|
||||
}
|
||||
|
||||
-- Embeds AceComm-3.0 into the target object making the functions from the mixins list available on target:..
|
||||
-- @param target target object to embed AceComm-3.0 in
|
||||
function AceComm:Embed(target)
|
||||
for k, v in pairs(mixins) do
|
||||
target[v] = self[v]
|
||||
end
|
||||
self.embeds[target] = true
|
||||
return target
|
||||
end
|
||||
|
||||
function AceComm:OnEmbedDisable(target)
|
||||
target:UnregisterAllComm()
|
||||
end
|
||||
|
||||
-- Update embeds
|
||||
for target, v in pairs(AceComm.embeds) do
|
||||
AceComm:Embed(target)
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
<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">
|
||||
<Script file="ChatThrottleLib.lua"/>
|
||||
<Script file="AceComm-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,503 @@
|
||||
--
|
||||
-- ChatThrottleLib by Mikk
|
||||
--
|
||||
-- Manages AddOn chat output to keep player from getting kicked off.
|
||||
--
|
||||
-- ChatThrottleLib:SendChatMessage/:SendAddonMessage functions that accept
|
||||
-- a Priority ("BULK", "NORMAL", "ALERT") as well as prefix for SendChatMessage.
|
||||
--
|
||||
-- Priorities get an equal share of available bandwidth when fully loaded.
|
||||
-- Communication channels are separated on extension+chattype+destination and
|
||||
-- get round-robinned. (Destination only matters for whispers and channels,
|
||||
-- obviously)
|
||||
--
|
||||
-- Will install hooks for SendChatMessage and SendAddonMessage to measure
|
||||
-- bandwidth bypassing the library and use less bandwidth itself.
|
||||
--
|
||||
--
|
||||
-- Fully embeddable library. Just copy this file into your addon directory,
|
||||
-- add it to the .toc, and it's done.
|
||||
--
|
||||
-- Can run as a standalone addon also, but, really, just embed it! :-)
|
||||
--
|
||||
|
||||
local CTL_VERSION = 21
|
||||
|
||||
local _G = _G
|
||||
|
||||
if _G.ChatThrottleLib then
|
||||
if _G.ChatThrottleLib.version >= CTL_VERSION then
|
||||
-- There's already a newer (or same) version loaded. Buh-bye.
|
||||
return
|
||||
elseif not _G.ChatThrottleLib.securelyHooked then
|
||||
print("ChatThrottleLib: Warning: There's an ANCIENT ChatThrottleLib.lua (pre-wow 2.0, <v16) in an addon somewhere. Get the addon updated or copy in a newer ChatThrottleLib.lua (>=v16) in it!")
|
||||
-- ATTEMPT to unhook; this'll behave badly if someone else has hooked...
|
||||
-- ... and if someone has securehooked, they can kiss that goodbye too... >.<
|
||||
_G.SendChatMessage = _G.ChatThrottleLib.ORIG_SendChatMessage
|
||||
if _G.ChatThrottleLib.ORIG_SendAddonMessage then
|
||||
_G.SendAddonMessage = _G.ChatThrottleLib.ORIG_SendAddonMessage
|
||||
end
|
||||
end
|
||||
_G.ChatThrottleLib.ORIG_SendChatMessage = nil
|
||||
_G.ChatThrottleLib.ORIG_SendAddonMessage = nil
|
||||
end
|
||||
|
||||
if not _G.ChatThrottleLib then
|
||||
_G.ChatThrottleLib = {}
|
||||
end
|
||||
|
||||
ChatThrottleLib = _G.ChatThrottleLib -- in case some addon does "local ChatThrottleLib" above us and we're copypasted (AceComm-2, sigh)
|
||||
local ChatThrottleLib = _G.ChatThrottleLib
|
||||
|
||||
ChatThrottleLib.version = CTL_VERSION
|
||||
|
||||
|
||||
|
||||
------------------ TWEAKABLES -----------------
|
||||
|
||||
ChatThrottleLib.MAX_CPS = 800 -- 2000 seems to be safe if NOTHING ELSE is happening. let's call it 800.
|
||||
ChatThrottleLib.MSG_OVERHEAD = 40 -- Guesstimate overhead for sending a message; source+dest+chattype+protocolstuff
|
||||
|
||||
ChatThrottleLib.BURST = 4000 -- WoW's server buffer seems to be about 32KB. 8KB should be safe, but seen disconnects on _some_ servers. Using 4KB now.
|
||||
|
||||
ChatThrottleLib.MIN_FPS = 20 -- Reduce output CPS to half (and don't burst) if FPS drops below this value
|
||||
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local table_remove = table.remove
|
||||
local tostring = tostring
|
||||
local GetTime = GetTime
|
||||
local math_min = math.min
|
||||
local math_max = math.max
|
||||
local next = next
|
||||
local strlen = string.len
|
||||
local GetFrameRate = GetFrameRate
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Double-linked ring implementation
|
||||
|
||||
local Ring = {}
|
||||
local RingMeta = { __index = Ring }
|
||||
|
||||
function Ring:New()
|
||||
local ret = {}
|
||||
setmetatable(ret, RingMeta)
|
||||
return ret
|
||||
end
|
||||
|
||||
function Ring:Add(obj) -- Append at the "far end" of the ring (aka just before the current position)
|
||||
if self.pos then
|
||||
obj.prev = self.pos.prev
|
||||
obj.prev.next = obj
|
||||
obj.next = self.pos
|
||||
obj.next.prev = obj
|
||||
else
|
||||
obj.next = obj
|
||||
obj.prev = obj
|
||||
self.pos = obj
|
||||
end
|
||||
end
|
||||
|
||||
function Ring:Remove(obj)
|
||||
obj.next.prev = obj.prev
|
||||
obj.prev.next = obj.next
|
||||
if self.pos == obj then
|
||||
self.pos = obj.next
|
||||
if self.pos == obj then
|
||||
self.pos = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Recycling bin for pipes
|
||||
-- A pipe is a plain integer-indexed queue, which also happens to be a ring member
|
||||
|
||||
ChatThrottleLib.PipeBin = nil -- pre-v19, drastically different
|
||||
local PipeBin = setmetatable({}, {__mode="k"})
|
||||
|
||||
local function DelPipe(pipe)
|
||||
for i = #pipe, 1, -1 do
|
||||
pipe[i] = nil
|
||||
end
|
||||
pipe.prev = nil
|
||||
pipe.next = nil
|
||||
|
||||
PipeBin[pipe] = true
|
||||
end
|
||||
|
||||
local function NewPipe()
|
||||
local pipe = next(PipeBin)
|
||||
if pipe then
|
||||
PipeBin[pipe] = nil
|
||||
return pipe
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Recycling bin for messages
|
||||
|
||||
ChatThrottleLib.MsgBin = nil -- pre-v19, drastically different
|
||||
local MsgBin = setmetatable({}, {__mode="k"})
|
||||
|
||||
local function DelMsg(msg)
|
||||
msg[1] = nil
|
||||
-- there's more parameters, but they're very repetetive so the string pool doesn't suffer really, and it's faster to just not delete them.
|
||||
MsgBin[msg] = true
|
||||
end
|
||||
|
||||
local function NewMsg()
|
||||
local msg = next(MsgBin)
|
||||
if msg then
|
||||
MsgBin[msg] = nil
|
||||
return msg
|
||||
end
|
||||
return {}
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- ChatThrottleLib:Init
|
||||
-- Initialize queues, set up frame for OnUpdate, etc
|
||||
|
||||
|
||||
function ChatThrottleLib:Init()
|
||||
|
||||
-- Set up queues
|
||||
if not self.Prio then
|
||||
self.Prio = {}
|
||||
self.Prio["ALERT"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
|
||||
self.Prio["NORMAL"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
|
||||
self.Prio["BULK"] = { ByName = {}, Ring = Ring:New(), avail = 0 }
|
||||
end
|
||||
|
||||
-- v4: total send counters per priority
|
||||
for _, Prio in pairs(self.Prio) do
|
||||
Prio.nTotalSent = Prio.nTotalSent or 0
|
||||
end
|
||||
|
||||
if not self.avail then
|
||||
self.avail = 0 -- v5
|
||||
end
|
||||
if not self.nTotalSent then
|
||||
self.nTotalSent = 0 -- v5
|
||||
end
|
||||
|
||||
|
||||
-- Set up a frame to get OnUpdate events
|
||||
if not self.Frame then
|
||||
self.Frame = CreateFrame("Frame")
|
||||
self.Frame:Hide()
|
||||
end
|
||||
self.Frame:SetScript("OnUpdate", self.OnUpdate)
|
||||
self.Frame:SetScript("OnEvent", self.OnEvent) -- v11: Monitor P_E_W so we can throttle hard for a few seconds
|
||||
self.Frame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||||
self.OnUpdateDelay = 0
|
||||
self.LastAvailUpdate = GetTime()
|
||||
self.HardThrottlingBeginTime = GetTime() -- v11: Throttle hard for a few seconds after startup
|
||||
|
||||
-- Hook SendChatMessage and SendAddonMessage so we can measure unpiped traffic and avoid overloads (v7)
|
||||
if not self.securelyHooked then
|
||||
-- Use secure hooks as of v16. Old regular hook support yanked out in v21.
|
||||
self.securelyHooked = true
|
||||
--SendChatMessage
|
||||
hooksecurefunc("SendChatMessage", function(...)
|
||||
return ChatThrottleLib.Hook_SendChatMessage(...)
|
||||
end)
|
||||
--SendAddonMessage
|
||||
hooksecurefunc("SendAddonMessage", function(...)
|
||||
return ChatThrottleLib.Hook_SendAddonMessage(...)
|
||||
end)
|
||||
end
|
||||
self.nBypass = 0
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- ChatThrottleLib.Hook_SendChatMessage / .Hook_SendAddonMessage
|
||||
|
||||
local bMyTraffic = false
|
||||
|
||||
function ChatThrottleLib.Hook_SendChatMessage(text, chattype, language, destination, ...)
|
||||
if bMyTraffic then
|
||||
return
|
||||
end
|
||||
local self = ChatThrottleLib
|
||||
local size = strlen(tostring(text or "")) + strlen(tostring(destination or "")) + self.MSG_OVERHEAD
|
||||
self.avail = self.avail - size
|
||||
self.nBypass = self.nBypass + size -- just a statistic
|
||||
end
|
||||
function ChatThrottleLib.Hook_SendAddonMessage(prefix, text, chattype, destination, ...)
|
||||
if bMyTraffic then
|
||||
return
|
||||
end
|
||||
local self = ChatThrottleLib
|
||||
local size = tostring(text or ""):len() + tostring(prefix or ""):len();
|
||||
size = size + tostring(destination or ""):len() + self.MSG_OVERHEAD
|
||||
self.avail = self.avail - size
|
||||
self.nBypass = self.nBypass + size -- just a statistic
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- ChatThrottleLib:UpdateAvail
|
||||
-- Update self.avail with how much bandwidth is currently available
|
||||
|
||||
function ChatThrottleLib:UpdateAvail()
|
||||
local now = GetTime()
|
||||
local MAX_CPS = self.MAX_CPS;
|
||||
local newavail = MAX_CPS * (now - self.LastAvailUpdate)
|
||||
local avail = self.avail
|
||||
|
||||
if now - self.HardThrottlingBeginTime < 5 then
|
||||
-- First 5 seconds after startup/zoning: VERY hard clamping to avoid irritating the server rate limiter, it seems very cranky then
|
||||
avail = math_min(avail + (newavail*0.1), MAX_CPS*0.5)
|
||||
self.bChoking = true
|
||||
elseif GetFramerate() < self.MIN_FPS then -- GetFrameRate call takes ~0.002 secs
|
||||
avail = math_min(MAX_CPS, avail + newavail*0.5)
|
||||
self.bChoking = true -- just a statistic
|
||||
else
|
||||
avail = math_min(self.BURST, avail + newavail)
|
||||
self.bChoking = false
|
||||
end
|
||||
|
||||
avail = math_max(avail, 0-(MAX_CPS*2)) -- Can go negative when someone is eating bandwidth past the lib. but we refuse to stay silent for more than 2 seconds; if they can do it, we can.
|
||||
|
||||
self.avail = avail
|
||||
self.LastAvailUpdate = now
|
||||
|
||||
return avail
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Despooling logic
|
||||
|
||||
function ChatThrottleLib:Despool(Prio)
|
||||
local ring = Prio.Ring
|
||||
while ring.pos and Prio.avail > ring.pos[1].nSize do
|
||||
local msg = table_remove(Prio.Ring.pos, 1)
|
||||
if not Prio.Ring.pos[1] then
|
||||
local pipe = Prio.Ring.pos
|
||||
Prio.Ring:Remove(pipe)
|
||||
Prio.ByName[pipe.name] = nil
|
||||
DelPipe(pipe)
|
||||
else
|
||||
Prio.Ring.pos = Prio.Ring.pos.next
|
||||
end
|
||||
Prio.avail = Prio.avail - msg.nSize
|
||||
bMyTraffic = true
|
||||
msg.f(unpack(msg, 1, msg.n))
|
||||
bMyTraffic = false
|
||||
Prio.nTotalSent = Prio.nTotalSent + msg.nSize
|
||||
DelMsg(msg)
|
||||
if msg.callbackFn then
|
||||
msg.callbackFn (msg.callbackArg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ChatThrottleLib.OnEvent(this,event)
|
||||
-- v11: We know that the rate limiter is touchy after login. Assume that it's touchy after zoning, too.
|
||||
local self = ChatThrottleLib
|
||||
if event == "PLAYER_ENTERING_WORLD" then
|
||||
self.HardThrottlingBeginTime = GetTime() -- Throttle hard for a few seconds after zoning
|
||||
self.avail = 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function ChatThrottleLib.OnUpdate(this,delay)
|
||||
local self = ChatThrottleLib
|
||||
|
||||
self.OnUpdateDelay = self.OnUpdateDelay + delay
|
||||
if self.OnUpdateDelay < 0.08 then
|
||||
return
|
||||
end
|
||||
self.OnUpdateDelay = 0
|
||||
|
||||
self:UpdateAvail()
|
||||
|
||||
if self.avail < 0 then
|
||||
return -- argh. some bastard is spewing stuff past the lib. just bail early to save cpu.
|
||||
end
|
||||
|
||||
-- See how many of our priorities have queued messages (we only have 3, don't worry about the loop)
|
||||
local n = 0
|
||||
for prioname,Prio in pairs(self.Prio) do
|
||||
if Prio.Ring.pos or Prio.avail < 0 then
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Anything queued still?
|
||||
if n<1 then
|
||||
-- Nope. Move spillover bandwidth to global availability gauge and clear self.bQueueing
|
||||
for prioname, Prio in pairs(self.Prio) do
|
||||
self.avail = self.avail + Prio.avail
|
||||
Prio.avail = 0
|
||||
end
|
||||
self.bQueueing = false
|
||||
self.Frame:Hide()
|
||||
return
|
||||
end
|
||||
|
||||
-- There's stuff queued. Hand out available bandwidth to priorities as needed and despool their queues
|
||||
local avail = self.avail/n
|
||||
self.avail = 0
|
||||
|
||||
for prioname, Prio in pairs(self.Prio) do
|
||||
if Prio.Ring.pos or Prio.avail < 0 then
|
||||
Prio.avail = Prio.avail + avail
|
||||
if Prio.Ring.pos and Prio.avail > Prio.Ring.pos[1].nSize then
|
||||
self:Despool(Prio)
|
||||
-- Note: We might not get here if the user-supplied callback function errors out! Take care!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Spooling logic
|
||||
|
||||
|
||||
function ChatThrottleLib:Enqueue(prioname, pipename, msg)
|
||||
local Prio = self.Prio[prioname]
|
||||
local pipe = Prio.ByName[pipename]
|
||||
if not pipe then
|
||||
self.Frame:Show()
|
||||
pipe = NewPipe()
|
||||
pipe.name = pipename
|
||||
Prio.ByName[pipename] = pipe
|
||||
Prio.Ring:Add(pipe)
|
||||
end
|
||||
|
||||
pipe[#pipe + 1] = msg
|
||||
|
||||
self.bQueueing = true
|
||||
end
|
||||
|
||||
|
||||
|
||||
function ChatThrottleLib:SendChatMessage(prio, prefix, text, chattype, language, destination, queueName, callbackFn, callbackArg)
|
||||
if not self or not prio or not prefix or not text or not self.Prio[prio] then
|
||||
error('Usage: ChatThrottleLib:SendChatMessage("{BULK||NORMAL||ALERT}", "prefix", "text"[, "chattype"[, "language"[, "destination"]]]', 2)
|
||||
end
|
||||
if callbackFn and type(callbackFn)~="function" then
|
||||
error('ChatThrottleLib:ChatMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
|
||||
end
|
||||
|
||||
local nSize = text:len()
|
||||
|
||||
if nSize>255 then
|
||||
error("ChatThrottleLib:SendChatMessage(): message length cannot exceed 255 bytes", 2)
|
||||
end
|
||||
|
||||
nSize = nSize + self.MSG_OVERHEAD
|
||||
|
||||
-- Check if there's room in the global available bandwidth gauge to send directly
|
||||
if not self.bQueueing and nSize < self:UpdateAvail() then
|
||||
self.avail = self.avail - nSize
|
||||
bMyTraffic = true
|
||||
_G.SendChatMessage(text, chattype, language, destination)
|
||||
bMyTraffic = false
|
||||
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
|
||||
if callbackFn then
|
||||
callbackFn (callbackArg)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Message needs to be queued
|
||||
local msg = NewMsg()
|
||||
msg.f = _G.SendChatMessage
|
||||
msg[1] = text
|
||||
msg[2] = chattype or "SAY"
|
||||
msg[3] = language
|
||||
msg[4] = destination
|
||||
msg.n = 4
|
||||
msg.nSize = nSize
|
||||
msg.callbackFn = callbackFn
|
||||
msg.callbackArg = callbackArg
|
||||
|
||||
self:Enqueue(prio, queueName or (prefix..(chattype or "SAY")..(destination or "")), msg)
|
||||
end
|
||||
|
||||
|
||||
function ChatThrottleLib:SendAddonMessage(prio, prefix, text, chattype, target, queueName, callbackFn, callbackArg)
|
||||
if not self or not prio or not prefix or not text or not chattype or not self.Prio[prio] then
|
||||
error('Usage: ChatThrottleLib:SendAddonMessage("{BULK||NORMAL||ALERT}", "prefix", "text", "chattype"[, "target"])', 2)
|
||||
end
|
||||
if callbackFn and type(callbackFn)~="function" then
|
||||
error('ChatThrottleLib:SendAddonMessage(): callbackFn: expected function, got '..type(callbackFn), 2)
|
||||
end
|
||||
|
||||
local nSize = prefix:len() + 1 + text:len();
|
||||
|
||||
if nSize>255 then
|
||||
error("ChatThrottleLib:SendAddonMessage(): prefix + message length cannot exceed 254 bytes", 2)
|
||||
end
|
||||
|
||||
nSize = nSize + self.MSG_OVERHEAD;
|
||||
|
||||
-- Check if there's room in the global available bandwidth gauge to send directly
|
||||
if not self.bQueueing and nSize < self:UpdateAvail() then
|
||||
self.avail = self.avail - nSize
|
||||
bMyTraffic = true
|
||||
_G.SendAddonMessage(prefix, text, chattype, target)
|
||||
bMyTraffic = false
|
||||
self.Prio[prio].nTotalSent = self.Prio[prio].nTotalSent + nSize
|
||||
if callbackFn then
|
||||
callbackFn (callbackArg)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Message needs to be queued
|
||||
local msg = NewMsg()
|
||||
msg.f = _G.SendAddonMessage
|
||||
msg[1] = prefix
|
||||
msg[2] = text
|
||||
msg[3] = chattype
|
||||
msg[4] = target
|
||||
msg.n = (target~=nil) and 4 or 3;
|
||||
msg.nSize = nSize
|
||||
msg.callbackFn = callbackFn
|
||||
msg.callbackArg = callbackArg
|
||||
|
||||
self:Enqueue(prio, queueName or (prefix..chattype..(target or "")), msg)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Get the ball rolling!
|
||||
|
||||
ChatThrottleLib:Init()
|
||||
|
||||
--[[ WoWBench debugging snippet
|
||||
if(WOWB_VER) then
|
||||
local function SayTimer()
|
||||
print("SAY: "..GetTime().." "..arg1)
|
||||
end
|
||||
ChatThrottleLib.Frame:SetScript("OnEvent", SayTimer)
|
||||
ChatThrottleLib.Frame:RegisterEvent("CHAT_MSG_SAY")
|
||||
end
|
||||
]]
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
--- AceConfig-3.0 wrapper library.
|
||||
-- Provides an API to register an options table with the config registry,
|
||||
-- as well as associate it with a slash command.
|
||||
-- @class file
|
||||
-- @name AceConfig-3.0
|
||||
-- @release $Id: AceConfig-3.0.lua 963 2010-07-26 11:35:35Z mikk $
|
||||
|
||||
--[[
|
||||
AceConfig-3.0
|
||||
|
||||
Very light wrapper library that combines all the AceConfig subcomponents into one more easily used whole.
|
||||
|
||||
]]
|
||||
|
||||
local MAJOR, MINOR = "AceConfig-3.0", 2
|
||||
local AceConfig = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceConfig then return end
|
||||
|
||||
local cfgreg = LibStub("AceConfigRegistry-3.0")
|
||||
local cfgcmd = LibStub("AceConfigCmd-3.0")
|
||||
--TODO: local cfgdlg = LibStub("AceConfigDialog-3.0", true)
|
||||
--TODO: local cfgdrp = LibStub("AceConfigDropdown-3.0", true)
|
||||
|
||||
-- Lua APIs
|
||||
local pcall, error, type, pairs = pcall, error, type, pairs
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- :RegisterOptionsTable(appName, options, slashcmd, persist)
|
||||
--
|
||||
-- - appName - (string) application name
|
||||
-- - options - table or function ref, see AceConfigRegistry
|
||||
-- - slashcmd - slash command (string) or table with commands, or nil to NOT create a slash command
|
||||
|
||||
--- Register a option table with the AceConfig registry.
|
||||
-- You can supply a slash command (or a table of slash commands) to register with AceConfigCmd directly.
|
||||
-- @paramsig appName, options [, slashcmd]
|
||||
-- @param appName The application name for the config table.
|
||||
-- @param options The option table (or a function to generate one on demand)
|
||||
-- @param slashcmd A slash command to register for the option table, or a table of slash commands.
|
||||
-- @usage
|
||||
-- local AceConfig = LibStub("AceConfig-3.0")
|
||||
-- AceConfig:RegisterOptionsTable("MyAddon", myOptions, {"/myslash", "/my"})
|
||||
function AceConfig:RegisterOptionsTable(appName, options, slashcmd)
|
||||
local ok,msg = pcall(cfgreg.RegisterOptionsTable, self, appName, options)
|
||||
if not ok then error(msg, 2) end
|
||||
|
||||
if slashcmd then
|
||||
if type(slashcmd) == "table" then
|
||||
for _,cmd in pairs(slashcmd) do
|
||||
cfgcmd:CreateChatCommand(cmd, appName)
|
||||
end
|
||||
else
|
||||
cfgcmd:CreateChatCommand(slashcmd, appName)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
<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">
|
||||
<Include file="AceConfigRegistry-3.0\AceConfigRegistry-3.0.xml"/>
|
||||
<Include file="AceConfigCmd-3.0\AceConfigCmd-3.0.xml"/>
|
||||
<Include file="AceConfigDialog-3.0\AceConfigDialog-3.0.xml"/>
|
||||
<!--<Include file="AceConfigDropdown-3.0\AceConfigDropdown-3.0.xml"/>-->
|
||||
<Script file="AceConfig-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,787 @@
|
||||
--- AceConfigCmd-3.0 handles access to an options table through the "command line" interface via the ChatFrames.
|
||||
-- @class file
|
||||
-- @name AceConfigCmd-3.0
|
||||
-- @release $Id: AceConfigCmd-3.0.lua 904 2009-12-13 11:56:37Z nevcairiel $
|
||||
|
||||
--[[
|
||||
AceConfigCmd-3.0
|
||||
|
||||
Handles commandline optionstable access
|
||||
|
||||
REQUIRES: AceConsole-3.0 for command registration (loaded on demand)
|
||||
|
||||
]]
|
||||
|
||||
-- TODO: plugin args
|
||||
|
||||
|
||||
local MAJOR, MINOR = "AceConfigCmd-3.0", 12
|
||||
local AceConfigCmd = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceConfigCmd then return end
|
||||
|
||||
AceConfigCmd.commands = AceConfigCmd.commands or {}
|
||||
local commands = AceConfigCmd.commands
|
||||
|
||||
local cfgreg = LibStub("AceConfigRegistry-3.0")
|
||||
local AceConsole -- LoD
|
||||
local AceConsoleName = "AceConsole-3.0"
|
||||
|
||||
-- Lua APIs
|
||||
local strsub, strsplit, strlower, strmatch, strtrim = string.sub, string.split, string.lower, string.match, string.trim
|
||||
local format, tonumber, tostring = string.format, tonumber, tostring
|
||||
local tsort, tinsert = table.sort, table.insert
|
||||
local select, pairs, next, type = select, pairs, next, type
|
||||
local error, assert = error, assert
|
||||
|
||||
-- WoW APIs
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: LibStub, SELECTED_CHAT_FRAME, DEFAULT_CHAT_FRAME
|
||||
|
||||
|
||||
local L = setmetatable({}, { -- TODO: replace with proper locale
|
||||
__index = function(self,k) return k end
|
||||
})
|
||||
|
||||
|
||||
|
||||
local function print(msg)
|
||||
(SELECTED_CHAT_FRAME or DEFAULT_CHAT_FRAME):AddMessage(msg)
|
||||
end
|
||||
|
||||
-- constants used by getparam() calls below
|
||||
|
||||
local handlertypes = {["table"]=true}
|
||||
local handlermsg = "expected a table"
|
||||
|
||||
local functypes = {["function"]=true, ["string"]=true}
|
||||
local funcmsg = "expected function or member name"
|
||||
|
||||
|
||||
-- pickfirstset() - picks the first non-nil value and returns it
|
||||
|
||||
local function pickfirstset(...)
|
||||
for i=1,select("#",...) do
|
||||
if select(i,...)~=nil then
|
||||
return select(i,...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- err() - produce real error() regarding malformed options tables etc
|
||||
|
||||
local function err(info,inputpos,msg )
|
||||
local cmdstr=" "..strsub(info.input, 1, inputpos-1)
|
||||
error(MAJOR..": /" ..info[0] ..cmdstr ..": "..(msg or "malformed options table"), 2)
|
||||
end
|
||||
|
||||
|
||||
-- usererr() - produce chatframe message regarding bad slash syntax etc
|
||||
|
||||
local function usererr(info,inputpos,msg )
|
||||
local cmdstr=strsub(info.input, 1, inputpos-1);
|
||||
print("/" ..info[0] .. " "..cmdstr ..": "..(msg or "malformed options table"))
|
||||
end
|
||||
|
||||
|
||||
-- callmethod() - call a given named method (e.g. "get", "set") with given arguments
|
||||
|
||||
local function callmethod(info, inputpos, tab, methodtype, ...)
|
||||
local method = info[methodtype]
|
||||
if not method then
|
||||
err(info, inputpos, "'"..methodtype.."': not set")
|
||||
end
|
||||
|
||||
info.arg = tab.arg
|
||||
info.option = tab
|
||||
info.type = tab.type
|
||||
|
||||
if type(method)=="function" then
|
||||
return method(info, ...)
|
||||
elseif type(method)=="string" then
|
||||
if type(info.handler[method])~="function" then
|
||||
err(info, inputpos, "'"..methodtype.."': '"..method.."' is not a member function of "..tostring(info.handler))
|
||||
end
|
||||
return info.handler[method](info.handler, info, ...)
|
||||
else
|
||||
assert(false) -- type should have already been checked on read
|
||||
end
|
||||
end
|
||||
|
||||
-- callfunction() - call a given named function (e.g. "name", "desc") with given arguments
|
||||
|
||||
local function callfunction(info, tab, methodtype, ...)
|
||||
local method = tab[methodtype]
|
||||
|
||||
info.arg = tab.arg
|
||||
info.option = tab
|
||||
info.type = tab.type
|
||||
|
||||
if type(method)=="function" then
|
||||
return method(info, ...)
|
||||
else
|
||||
assert(false) -- type should have already been checked on read
|
||||
end
|
||||
end
|
||||
|
||||
-- do_final() - do the final step (set/execute) along with validation and confirmation
|
||||
|
||||
local function do_final(info, inputpos, tab, methodtype, ...)
|
||||
if info.validate then
|
||||
local res = callmethod(info,inputpos,tab,"validate",...)
|
||||
if type(res)=="string" then
|
||||
usererr(info, inputpos, "'"..strsub(info.input, inputpos).."' - "..res)
|
||||
return
|
||||
end
|
||||
end
|
||||
-- console ignores .confirm
|
||||
|
||||
callmethod(info,inputpos,tab,methodtype, ...)
|
||||
end
|
||||
|
||||
|
||||
-- getparam() - used by handle() to retreive and store "handler", "get", "set", etc
|
||||
|
||||
local function getparam(info, inputpos, tab, depth, paramname, types, errormsg)
|
||||
local old,oldat = info[paramname], info[paramname.."_at"]
|
||||
local val=tab[paramname]
|
||||
if val~=nil then
|
||||
if val==false then
|
||||
val=nil
|
||||
elseif not types[type(val)] then
|
||||
err(info, inputpos, "'" .. paramname.. "' - "..errormsg)
|
||||
end
|
||||
info[paramname] = val
|
||||
info[paramname.."_at"] = depth
|
||||
end
|
||||
return old,oldat
|
||||
end
|
||||
|
||||
|
||||
-- iterateargs(tab) - custom iterator that iterates both t.args and t.plugins.*
|
||||
local dummytable={}
|
||||
|
||||
local function iterateargs(tab)
|
||||
if not tab.plugins then
|
||||
return pairs(tab.args)
|
||||
end
|
||||
|
||||
local argtabkey,argtab=next(tab.plugins)
|
||||
local v
|
||||
|
||||
return function(_, k)
|
||||
while argtab do
|
||||
k,v = next(argtab, k)
|
||||
if k then return k,v end
|
||||
if argtab==tab.args then
|
||||
argtab=nil
|
||||
else
|
||||
argtabkey,argtab = next(tab.plugins, argtabkey)
|
||||
if not argtabkey then
|
||||
argtab=tab.args
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function checkhidden(info, inputpos, tab)
|
||||
if tab.cmdHidden~=nil then
|
||||
return tab.cmdHidden
|
||||
end
|
||||
local hidden = tab.hidden
|
||||
if type(hidden) == "function" or type(hidden) == "string" then
|
||||
info.hidden = hidden
|
||||
hidden = callmethod(info, inputpos, tab, 'hidden')
|
||||
info.hidden = nil
|
||||
end
|
||||
return hidden
|
||||
end
|
||||
|
||||
local function showhelp(info, inputpos, tab, depth, noHead)
|
||||
if not noHead then
|
||||
print("|cff33ff99"..info.appName.."|r: Arguments to |cffffff78/"..info[0].."|r "..strsub(info.input,1,inputpos-1)..":")
|
||||
end
|
||||
|
||||
local sortTbl = {} -- [1..n]=name
|
||||
local refTbl = {} -- [name]=tableref
|
||||
|
||||
for k,v in iterateargs(tab) do
|
||||
if not refTbl[k] then -- a plugin overriding something in .args
|
||||
tinsert(sortTbl, k)
|
||||
refTbl[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
tsort(sortTbl, function(one, two)
|
||||
local o1 = refTbl[one].order or 100
|
||||
local o2 = refTbl[two].order or 100
|
||||
if type(o1) == "function" or type(o1) == "string" then
|
||||
info.order = o1
|
||||
info[#info+1] = one
|
||||
o1 = callmethod(info, inputpos, refTbl[one], "order")
|
||||
info[#info] = nil
|
||||
info.order = nil
|
||||
end
|
||||
if type(o2) == "function" or type(o1) == "string" then
|
||||
info.order = o2
|
||||
info[#info+1] = two
|
||||
o2 = callmethod(info, inputpos, refTbl[two], "order")
|
||||
info[#info] = nil
|
||||
info.order = nil
|
||||
end
|
||||
if o1<0 and o2<0 then return o1<o2 end
|
||||
if o2<0 then return true end
|
||||
if o1<0 then return false end
|
||||
if o1==o2 then return tostring(one)<tostring(two) end -- compare names
|
||||
return o1<o2
|
||||
end)
|
||||
|
||||
for i = 1, #sortTbl do
|
||||
local k = sortTbl[i]
|
||||
local v = refTbl[k]
|
||||
if not checkhidden(info, inputpos, v) then
|
||||
if v.type ~= "description" and v.type ~= "header" then
|
||||
-- recursively show all inline groups
|
||||
local name, desc = v.name, v.desc
|
||||
if type(name) == "function" then
|
||||
name = callfunction(info, v, 'name')
|
||||
end
|
||||
if type(desc) == "function" then
|
||||
desc = callfunction(info, v, 'desc')
|
||||
end
|
||||
if v.type == "group" and pickfirstset(v.cmdInline, v.inline, false) then
|
||||
print(" "..(desc or name)..":")
|
||||
local oldhandler,oldhandler_at = getparam(info, inputpos, v, depth, "handler", handlertypes, handlermsg)
|
||||
showhelp(info, inputpos, v, depth, true)
|
||||
info.handler,info.handler_at = oldhandler,oldhandler_at
|
||||
else
|
||||
local key = k:gsub(" ", "_")
|
||||
print(" |cffffff78"..key.."|r - "..(desc or name or ""))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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 text == "" then
|
||||
return false
|
||||
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
|
||||
|
||||
-- handle() - selfrecursing function that processes input->optiontable
|
||||
-- - depth - starts at 0
|
||||
-- - retfalse - return false rather than produce error if a match is not found (used by inlined groups)
|
||||
|
||||
local function handle(info, inputpos, tab, depth, retfalse)
|
||||
|
||||
if not(type(tab)=="table" and type(tab.type)=="string") then err(info,inputpos) end
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Grab hold of handler,set,get,func,etc if set (and remember old ones)
|
||||
-- Note that we do NOT validate if method names are correct at this stage,
|
||||
-- the handler may change before they're actually used!
|
||||
|
||||
local oldhandler,oldhandler_at = getparam(info,inputpos,tab,depth,"handler",handlertypes,handlermsg)
|
||||
local oldset,oldset_at = getparam(info,inputpos,tab,depth,"set",functypes,funcmsg)
|
||||
local oldget,oldget_at = getparam(info,inputpos,tab,depth,"get",functypes,funcmsg)
|
||||
local oldfunc,oldfunc_at = getparam(info,inputpos,tab,depth,"func",functypes,funcmsg)
|
||||
local oldvalidate,oldvalidate_at = getparam(info,inputpos,tab,depth,"validate",functypes,funcmsg)
|
||||
--local oldconfirm,oldconfirm_at = getparam(info,inputpos,tab,depth,"confirm",functypes,funcmsg)
|
||||
|
||||
-------------------------------------------------------------------
|
||||
-- Act according to .type of this table
|
||||
|
||||
if tab.type=="group" then
|
||||
------------ group --------------------------------------------
|
||||
|
||||
if type(tab.args)~="table" then err(info, inputpos) end
|
||||
if tab.plugins and type(tab.plugins)~="table" then err(info,inputpos) end
|
||||
|
||||
-- grab next arg from input
|
||||
local _,nextpos,arg = (info.input):find(" *([^ ]+) *", inputpos)
|
||||
if not arg then
|
||||
showhelp(info, inputpos, tab, depth)
|
||||
return
|
||||
end
|
||||
nextpos=nextpos+1
|
||||
|
||||
-- loop .args and try to find a key with a matching name
|
||||
for k,v in iterateargs(tab) do
|
||||
if not(type(k)=="string" and type(v)=="table" and type(v.type)=="string") then err(info,inputpos, "options table child '"..tostring(k).."' is malformed") end
|
||||
|
||||
-- is this child an inline group? if so, traverse into it
|
||||
if v.type=="group" and pickfirstset(v.cmdInline, v.inline, false) then
|
||||
info[depth+1] = k
|
||||
if handle(info, inputpos, v, depth+1, true)==false then
|
||||
info[depth+1] = nil
|
||||
-- wasn't found in there, but that's ok, we just keep looking down here
|
||||
else
|
||||
return -- done, name was found in inline group
|
||||
end
|
||||
-- matching name and not a inline group
|
||||
elseif strlower(arg)==strlower(k:gsub(" ", "_")) then
|
||||
info[depth+1] = k
|
||||
return handle(info,nextpos,v,depth+1)
|
||||
end
|
||||
end
|
||||
|
||||
-- no match
|
||||
if retfalse then
|
||||
-- restore old infotable members and return false to indicate failure
|
||||
info.handler,info.handler_at = oldhandler,oldhandler_at
|
||||
info.set,info.set_at = oldset,oldset_at
|
||||
info.get,info.get_at = oldget,oldget_at
|
||||
info.func,info.func_at = oldfunc,oldfunc_at
|
||||
info.validate,info.validate_at = oldvalidate,oldvalidate_at
|
||||
--info.confirm,info.confirm_at = oldconfirm,oldconfirm_at
|
||||
return false
|
||||
end
|
||||
|
||||
-- couldn't find the command, display error
|
||||
usererr(info, inputpos, "'"..arg.."' - " .. L["unknown argument"])
|
||||
return
|
||||
end
|
||||
|
||||
local str = strsub(info.input,inputpos);
|
||||
|
||||
if tab.type=="execute" then
|
||||
------------ execute --------------------------------------------
|
||||
do_final(info, inputpos, tab, "func")
|
||||
|
||||
|
||||
|
||||
elseif tab.type=="input" then
|
||||
------------ input --------------------------------------------
|
||||
|
||||
local res = true
|
||||
if tab.pattern then
|
||||
if not(type(tab.pattern)=="string") then err(info, inputpos, "'pattern' - expected a string") end
|
||||
if not strmatch(str, tab.pattern) then
|
||||
usererr(info, inputpos, "'"..str.."' - " .. L["invalid input"])
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", str)
|
||||
|
||||
|
||||
|
||||
elseif tab.type=="toggle" then
|
||||
------------ toggle --------------------------------------------
|
||||
local b
|
||||
local str = strtrim(strlower(str))
|
||||
if str=="" then
|
||||
b = callmethod(info, inputpos, tab, "get")
|
||||
|
||||
if tab.tristate then
|
||||
--cycle in true, nil, false order
|
||||
if b then
|
||||
b = nil
|
||||
elseif b == nil then
|
||||
b = false
|
||||
else
|
||||
b = true
|
||||
end
|
||||
else
|
||||
b = not b
|
||||
end
|
||||
|
||||
elseif str==L["on"] then
|
||||
b = true
|
||||
elseif str==L["off"] then
|
||||
b = false
|
||||
elseif tab.tristate and str==L["default"] then
|
||||
b = nil
|
||||
else
|
||||
if tab.tristate then
|
||||
usererr(info, inputpos, format(L["'%s' - expected 'on', 'off' or 'default', or no argument to toggle."], str))
|
||||
else
|
||||
usererr(info, inputpos, format(L["'%s' - expected 'on' or 'off', or no argument to toggle."], str))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", b)
|
||||
|
||||
|
||||
elseif tab.type=="range" then
|
||||
------------ range --------------------------------------------
|
||||
local val = tonumber(str)
|
||||
if not val then
|
||||
usererr(info, inputpos, "'"..str.."' - "..L["expected number"])
|
||||
return
|
||||
end
|
||||
if type(info.step)=="number" then
|
||||
val = val- (val % info.step)
|
||||
end
|
||||
if type(info.min)=="number" and val<info.min then
|
||||
usererr(info, inputpos, val.." - "..format(L["must be equal to or higher than %s"], tostring(info.min)) )
|
||||
return
|
||||
end
|
||||
if type(info.max)=="number" and val>info.max then
|
||||
usererr(info, inputpos, val.." - "..format(L["must be equal to or lower than %s"], tostring(info.max)) )
|
||||
return
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", val)
|
||||
|
||||
|
||||
elseif tab.type=="select" then
|
||||
------------ select ------------------------------------
|
||||
local str = strtrim(strlower(str))
|
||||
|
||||
local values = tab.values
|
||||
if type(values) == "function" or type(values) == "string" then
|
||||
info.values = values
|
||||
values = callmethod(info, inputpos, tab, "values")
|
||||
info.values = nil
|
||||
end
|
||||
|
||||
if str == "" then
|
||||
local b = callmethod(info, inputpos, tab, "get")
|
||||
local fmt = "|cffffff78- [%s]|r %s"
|
||||
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
|
||||
print(L["Options for |cffffff78"..info[#info].."|r:"])
|
||||
for k, v in pairs(values) do
|
||||
if b == k then
|
||||
print(fmt_sel:format(k, v))
|
||||
else
|
||||
print(fmt:format(k, v))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local ok
|
||||
for k,v in pairs(values) do
|
||||
if strlower(k)==str then
|
||||
str = k -- overwrite with key (in case of case mismatches)
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
if not ok then
|
||||
usererr(info, inputpos, "'"..str.."' - "..L["unknown selection"])
|
||||
return
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", str)
|
||||
|
||||
elseif tab.type=="multiselect" then
|
||||
------------ multiselect -------------------------------------------
|
||||
local str = strtrim(strlower(str))
|
||||
|
||||
local values = tab.values
|
||||
if type(values) == "function" or type(values) == "string" then
|
||||
info.values = values
|
||||
values = callmethod(info, inputpos, tab, "values")
|
||||
info.values = nil
|
||||
end
|
||||
|
||||
if str == "" then
|
||||
local fmt = "|cffffff78- [%s]|r %s"
|
||||
local fmt_sel = "|cffffff78- [%s]|r %s |cffff0000*|r"
|
||||
print(L["Options for |cffffff78"..info[#info].."|r (multiple possible):"])
|
||||
for k, v in pairs(values) do
|
||||
if callmethod(info, inputpos, tab, "get", k) then
|
||||
print(fmt_sel:format(k, v))
|
||||
else
|
||||
print(fmt:format(k, v))
|
||||
end
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
--build a table of the selections, checking that they exist
|
||||
--parse for =on =off =default in the process
|
||||
--table will be key = true for options that should toggle, key = [on|off|default] for options to be set
|
||||
local sels = {}
|
||||
for v in str:gmatch("[^ ]+") do
|
||||
--parse option=on etc
|
||||
local opt, val = v:match('(.+)=(.+)')
|
||||
--get option if toggling
|
||||
if not opt then
|
||||
opt = v
|
||||
end
|
||||
|
||||
--check that the opt is valid
|
||||
local ok
|
||||
for k,v in pairs(values) do
|
||||
if strlower(k)==opt then
|
||||
opt = k -- overwrite with key (in case of case mismatches)
|
||||
ok = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not ok then
|
||||
usererr(info, inputpos, "'"..opt.."' - "..L["unknown selection"])
|
||||
return
|
||||
end
|
||||
|
||||
--check that if val was supplied it is valid
|
||||
if val then
|
||||
if val == L["on"] or val == L["off"] or (tab.tristate and val == L["default"]) then
|
||||
--val is valid insert it
|
||||
sels[opt] = val
|
||||
else
|
||||
if tab.tristate then
|
||||
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on', 'off' or 'default', or no argument to toggle."], v, val))
|
||||
else
|
||||
usererr(info, inputpos, format(L["'%s' '%s' - expected 'on' or 'off', or no argument to toggle."], v, val))
|
||||
end
|
||||
return
|
||||
end
|
||||
else
|
||||
-- no val supplied, toggle
|
||||
sels[opt] = true
|
||||
end
|
||||
end
|
||||
|
||||
for opt, val in pairs(sels) do
|
||||
local newval
|
||||
|
||||
if (val == true) then
|
||||
--toggle the option
|
||||
local b = callmethod(info, inputpos, tab, "get", opt)
|
||||
|
||||
if tab.tristate then
|
||||
--cycle in true, nil, false order
|
||||
if b then
|
||||
b = nil
|
||||
elseif b == nil then
|
||||
b = false
|
||||
else
|
||||
b = true
|
||||
end
|
||||
else
|
||||
b = not b
|
||||
end
|
||||
newval = b
|
||||
else
|
||||
--set the option as specified
|
||||
if val==L["on"] then
|
||||
newval = true
|
||||
elseif val==L["off"] then
|
||||
newval = false
|
||||
elseif val==L["default"] then
|
||||
newval = nil
|
||||
end
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", opt, newval)
|
||||
end
|
||||
|
||||
|
||||
elseif tab.type=="color" then
|
||||
------------ color --------------------------------------------
|
||||
local str = strtrim(strlower(str))
|
||||
if str == "" then
|
||||
--TODO: Show current value
|
||||
return
|
||||
end
|
||||
|
||||
local r, g, b, a
|
||||
|
||||
if tab.hasAlpha then
|
||||
if str:len() == 8 and str:find("^%x*$") then
|
||||
--parse a hex string
|
||||
r,g,b,a = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255, tonumber(str:sub(7, 8), 16) / 255
|
||||
else
|
||||
--parse seperate values
|
||||
r,g,b,a = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+) ([%d%.]+)$")
|
||||
r,g,b,a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
|
||||
end
|
||||
if not (r and g and b and a) then
|
||||
usererr(info, inputpos, format(L["'%s' - expected 'RRGGBBAA' or 'r g b a'."], str))
|
||||
return
|
||||
end
|
||||
|
||||
if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 and a >= 0.0 and a <= 1.0 then
|
||||
--values are valid
|
||||
elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 and a >= 0 and a <= 255 then
|
||||
--values are valid 0..255, convert to 0..1
|
||||
r = r / 255
|
||||
g = g / 255
|
||||
b = b / 255
|
||||
a = a / 255
|
||||
else
|
||||
--values are invalid
|
||||
usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0..1 or 0..255."], str))
|
||||
end
|
||||
else
|
||||
a = 1.0
|
||||
if str:len() == 6 and str:find("^%x*$") then
|
||||
--parse a hex string
|
||||
r,g,b = tonumber(str:sub(1, 2), 16) / 255, tonumber(str:sub(3, 4), 16) / 255, tonumber(str:sub(5, 6), 16) / 255
|
||||
else
|
||||
--parse seperate values
|
||||
r,g,b = str:match("^([%d%.]+) ([%d%.]+) ([%d%.]+)$")
|
||||
r,g,b = tonumber(r), tonumber(g), tonumber(b)
|
||||
end
|
||||
if not (r and g and b) then
|
||||
usererr(info, inputpos, format(L["'%s' - expected 'RRGGBB' or 'r g b'."], str))
|
||||
return
|
||||
end
|
||||
if r >= 0.0 and r <= 1.0 and g >= 0.0 and g <= 1.0 and b >= 0.0 and b <= 1.0 then
|
||||
--values are valid
|
||||
elseif r >= 0 and r <= 255 and g >= 0 and g <= 255 and b >= 0 and b <= 255 then
|
||||
--values are valid 0..255, convert to 0..1
|
||||
r = r / 255
|
||||
g = g / 255
|
||||
b = b / 255
|
||||
else
|
||||
--values are invalid
|
||||
usererr(info, inputpos, format(L["'%s' - values must all be either in the range 0-1 or 0-255."], str))
|
||||
end
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", r,g,b,a)
|
||||
|
||||
elseif tab.type=="keybinding" then
|
||||
------------ keybinding --------------------------------------------
|
||||
local str = strtrim(strlower(str))
|
||||
if str == "" then
|
||||
--TODO: Show current value
|
||||
return
|
||||
end
|
||||
local value = keybindingValidateFunc(str:upper())
|
||||
if value == false then
|
||||
usererr(info, inputpos, format(L["'%s' - Invalid Keybinding."], str))
|
||||
return
|
||||
end
|
||||
|
||||
do_final(info, inputpos, tab, "set", value)
|
||||
|
||||
elseif tab.type=="description" then
|
||||
------------ description --------------------
|
||||
-- ignore description, GUI config only
|
||||
else
|
||||
err(info, inputpos, "unknown options table item type '"..tostring(tab.type).."'")
|
||||
end
|
||||
end
|
||||
|
||||
--- Handle the chat command.
|
||||
-- This is usually called from a chat command handler to parse the command input as operations on an aceoptions table.\\
|
||||
-- AceConfigCmd uses this function internally when a slash command is registered with `:CreateChatCommand`
|
||||
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
-- @param input The commandline input (as given by the WoW handler, i.e. without the command itself)
|
||||
-- @usage
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon", "AceConsole-3.0")
|
||||
-- -- Use AceConsole-3.0 to register a Chat Command
|
||||
-- MyAddon:RegisterChatCommand("mychat", "ChatCommand")
|
||||
--
|
||||
-- -- Show the GUI if no input is supplied, otherwise handle the chat input.
|
||||
-- function MyAddon:ChatCommand(input)
|
||||
-- -- Assuming "MyOptions" is the appName of a valid options table
|
||||
-- if not input or input:trim() == "" then
|
||||
-- LibStub("AceConfigDialog-3.0"):Open("MyOptions")
|
||||
-- else
|
||||
-- LibStub("AceConfigCmd-3.0").HandleCommand(MyAddon, "mychat", "MyOptions", input)
|
||||
-- end
|
||||
-- end
|
||||
function AceConfigCmd:HandleCommand(slashcmd, appName, input)
|
||||
|
||||
local optgetter = cfgreg:GetOptionsTable(appName)
|
||||
if not optgetter then
|
||||
error([[Usage: HandleCommand("slashcmd", "appName", "input"): 'appName' - no options table "]]..tostring(appName)..[[" has been registered]], 2)
|
||||
end
|
||||
local options = assert( optgetter("cmd", MAJOR) )
|
||||
|
||||
local info = { -- Don't try to recycle this, it gets handed off to callbacks and whatnot
|
||||
[0] = slashcmd,
|
||||
appName = appName,
|
||||
options = options,
|
||||
input = input,
|
||||
self = self,
|
||||
handler = self,
|
||||
uiType = "cmd",
|
||||
uiName = MAJOR,
|
||||
}
|
||||
|
||||
handle(info, 1, options, 0) -- (info, inputpos, table, depth)
|
||||
end
|
||||
|
||||
--- Utility function to create a slash command handler.
|
||||
-- Also registers tab completion with AceTab
|
||||
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
function AceConfigCmd:CreateChatCommand(slashcmd, appName)
|
||||
if not AceConsole then
|
||||
AceConsole = LibStub(AceConsoleName)
|
||||
end
|
||||
if AceConsole.RegisterChatCommand(self, slashcmd, function(input)
|
||||
AceConfigCmd.HandleCommand(self, slashcmd, appName, input) -- upgradable
|
||||
end,
|
||||
true) then -- succesfully registered so lets get the command -> app table in
|
||||
commands[slashcmd] = appName
|
||||
end
|
||||
end
|
||||
|
||||
--- Utility function that returns the options table that belongs to a slashcommand.
|
||||
-- Designed to be used for the AceTab interface.
|
||||
-- @param slashcmd The slash command WITHOUT leading slash (only used for error output)
|
||||
-- @return The options table associated with the slash command (or nil if the slash command was not registered)
|
||||
function AceConfigCmd:GetChatCommandOptions(slashcmd)
|
||||
return commands[slashcmd]
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceConfigCmd-3.0.lua"/>
|
||||
</Ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceConfigDialog-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,346 @@
|
||||
--- AceConfigRegistry-3.0 handles central registration of options tables in use by addons and modules.\\
|
||||
-- Options tables can be registered as raw tables, OR as function refs that return a table.\\
|
||||
-- Such functions receive three arguments: "uiType", "uiName", "appName". \\
|
||||
-- * Valid **uiTypes**: "cmd", "dropdown", "dialog". This is verified by the library at call time. \\
|
||||
-- * The **uiName** field is expected to contain the full name of the calling addon, including version, e.g. "FooBar-1.0". This is verified by the library at call time.\\
|
||||
-- * The **appName** field is the options table name as given at registration time \\
|
||||
--
|
||||
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
|
||||
-- @class file
|
||||
-- @name AceConfigRegistry-3.0
|
||||
-- @release $Id: AceConfigRegistry-3.0.lua 921 2010-05-09 15:49:14Z nevcairiel $
|
||||
local MAJOR, MINOR = "AceConfigRegistry-3.0", 12
|
||||
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceConfigRegistry then return end
|
||||
|
||||
AceConfigRegistry.tables = AceConfigRegistry.tables or {}
|
||||
|
||||
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
|
||||
|
||||
if not AceConfigRegistry.callbacks then
|
||||
AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
|
||||
end
|
||||
|
||||
-- Lua APIs
|
||||
local tinsert, tconcat = table.insert, table.concat
|
||||
local strfind, strmatch = string.find, string.match
|
||||
local type, tostring, select, pairs = type, tostring, select, pairs
|
||||
local error, assert = error, assert
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- Validating options table consistency:
|
||||
|
||||
|
||||
AceConfigRegistry.validated = {
|
||||
-- list of options table names ran through :ValidateOptionsTable automatically.
|
||||
-- CLEARED ON PURPOSE, since newer versions may have newer validators
|
||||
cmd = {},
|
||||
dropdown = {},
|
||||
dialog = {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
local function err(msg, errlvl, ...)
|
||||
local t = {}
|
||||
for i=select("#",...),1,-1 do
|
||||
tinsert(t, (select(i, ...)))
|
||||
end
|
||||
error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2)
|
||||
end
|
||||
|
||||
|
||||
local isstring={["string"]=true, _="string"}
|
||||
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
|
||||
local istable={["table"]=true, _="table"}
|
||||
local ismethodtable={["table"]=true,["string"]=true,["function"]=true, _="methodname, funcref or table"}
|
||||
local optstring={["nil"]=true,["string"]=true, _="string"}
|
||||
local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"}
|
||||
local optnumber={["nil"]=true,["number"]=true, _="number"}
|
||||
local optmethod={["nil"]=true,["string"]=true,["function"]=true, _="methodname or funcref"}
|
||||
local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true}, _="methodname, funcref or false"}
|
||||
local optmethodnumber={["nil"]=true,["string"]=true,["function"]=true,["number"]=true, _="methodname, funcref or number"}
|
||||
local optmethodtable={["nil"]=true,["string"]=true,["function"]=true,["table"]=true, _="methodname, funcref or table"}
|
||||
local optmethodbool={["nil"]=true,["string"]=true,["function"]=true,["boolean"]=true, _="methodname, funcref or boolean"}
|
||||
local opttable={["nil"]=true,["table"]=true, _="table"}
|
||||
local optbool={["nil"]=true,["boolean"]=true, _="boolean"}
|
||||
local optboolnumber={["nil"]=true,["boolean"]=true,["number"]=true, _="boolean or number"}
|
||||
|
||||
local basekeys={
|
||||
type=isstring,
|
||||
name=isstringfunc,
|
||||
desc=optstringfunc,
|
||||
descStyle=optstring,
|
||||
order=optmethodnumber,
|
||||
validate=optmethodfalse,
|
||||
confirm=optmethodbool,
|
||||
confirmText=optstring,
|
||||
disabled=optmethodbool,
|
||||
hidden=optmethodbool,
|
||||
guiHidden=optmethodbool,
|
||||
dialogHidden=optmethodbool,
|
||||
dropdownHidden=optmethodbool,
|
||||
cmdHidden=optmethodbool,
|
||||
icon=optstringfunc,
|
||||
iconCoords=optmethodtable,
|
||||
handler=opttable,
|
||||
get=optmethodfalse,
|
||||
set=optmethodfalse,
|
||||
func=optmethodfalse,
|
||||
arg={["*"]=true},
|
||||
width=optstring,
|
||||
}
|
||||
|
||||
local typedkeys={
|
||||
header={},
|
||||
description={
|
||||
image=optstringfunc,
|
||||
imageCoords=optmethodtable,
|
||||
imageHeight=optnumber,
|
||||
imageWidth=optnumber,
|
||||
fontSize=optstringfunc,
|
||||
},
|
||||
group={
|
||||
args=istable,
|
||||
plugins=opttable,
|
||||
inline=optbool,
|
||||
cmdInline=optbool,
|
||||
guiInline=optbool,
|
||||
dropdownInline=optbool,
|
||||
dialogInline=optbool,
|
||||
childGroups=optstring,
|
||||
},
|
||||
execute={
|
||||
image=optstringfunc,
|
||||
imageCoords=optmethodtable,
|
||||
imageHeight=optnumber,
|
||||
imageWidth=optnumber,
|
||||
},
|
||||
input={
|
||||
pattern=optstring,
|
||||
usage=optstring,
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
multiline=optboolnumber,
|
||||
},
|
||||
toggle={
|
||||
tristate=optbool,
|
||||
image=optstringfunc,
|
||||
imageCoords=optmethodtable,
|
||||
},
|
||||
tristate={
|
||||
},
|
||||
range={
|
||||
min=optnumber,
|
||||
softMin=optnumber,
|
||||
max=optnumber,
|
||||
softMax=optnumber,
|
||||
step=optnumber,
|
||||
bigStep=optnumber,
|
||||
isPercent=optbool,
|
||||
},
|
||||
select={
|
||||
values=ismethodtable,
|
||||
style={
|
||||
["nil"]=true,
|
||||
["string"]={dropdown=true,radio=true},
|
||||
_="string: 'dropdown' or 'radio'"
|
||||
},
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
},
|
||||
multiselect={
|
||||
values=ismethodtable,
|
||||
style=optstring,
|
||||
tristate=optbool,
|
||||
control=optstring,
|
||||
dialogControl=optstring,
|
||||
dropdownControl=optstring,
|
||||
},
|
||||
color={
|
||||
hasAlpha=optbool,
|
||||
},
|
||||
keybinding={
|
||||
-- TODO
|
||||
},
|
||||
}
|
||||
|
||||
local function validateKey(k,errlvl,...)
|
||||
errlvl=(errlvl or 0)+1
|
||||
if type(k)~="string" then
|
||||
err("["..tostring(k).."] - key is not a string", errlvl,...)
|
||||
end
|
||||
if strfind(k, "[%c\127]") then
|
||||
err("["..tostring(k).."] - key name contained control characters", errlvl,...)
|
||||
end
|
||||
end
|
||||
|
||||
local function validateVal(v, oktypes, errlvl,...)
|
||||
errlvl=(errlvl or 0)+1
|
||||
local isok=oktypes[type(v)] or oktypes["*"]
|
||||
|
||||
if not isok then
|
||||
err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,...)
|
||||
end
|
||||
if type(isok)=="table" then -- isok was a table containing specific values to be tested for!
|
||||
if not isok[v] then
|
||||
err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function validate(options,errlvl,...)
|
||||
errlvl=(errlvl or 0)+1
|
||||
-- basic consistency
|
||||
if type(options)~="table" then
|
||||
err(": expected a table, got a "..type(options), errlvl,...)
|
||||
end
|
||||
if type(options.type)~="string" then
|
||||
err(".type: expected a string, got a "..type(options.type), errlvl,...)
|
||||
end
|
||||
|
||||
-- get type and 'typedkeys' member
|
||||
local tk = typedkeys[options.type]
|
||||
if not tk then
|
||||
err(".type: unknown type '"..options.type.."'", errlvl,...)
|
||||
end
|
||||
|
||||
-- make sure that all options[] are known parameters
|
||||
for k,v in pairs(options) do
|
||||
if not (tk[k] or basekeys[k]) then
|
||||
err(": unknown parameter", errlvl,tostring(k),...)
|
||||
end
|
||||
end
|
||||
|
||||
-- verify that required params are there, and that everything is the right type
|
||||
for k,oktypes in pairs(basekeys) do
|
||||
validateVal(options[k], oktypes, errlvl,k,...)
|
||||
end
|
||||
for k,oktypes in pairs(tk) do
|
||||
validateVal(options[k], oktypes, errlvl,k,...)
|
||||
end
|
||||
|
||||
-- extra logic for groups
|
||||
if options.type=="group" then
|
||||
for k,v in pairs(options.args) do
|
||||
validateKey(k,errlvl,"args",...)
|
||||
validate(v, errlvl,k,"args",...)
|
||||
end
|
||||
if options.plugins then
|
||||
for plugname,plugin in pairs(options.plugins) do
|
||||
if type(plugin)~="table" then
|
||||
err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",...)
|
||||
end
|
||||
for k,v in pairs(plugin) do
|
||||
validateKey(k,errlvl,tostring(plugname),"plugins",...)
|
||||
validate(v, errlvl,k,tostring(plugname),"plugins",...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Validates basic structure and integrity of an options table \\
|
||||
-- Does NOT verify that get/set etc actually exist, since they can be defined at any depth
|
||||
-- @param options The table to be validated
|
||||
-- @param name The name of the table to be validated (shown in any error message)
|
||||
-- @param errlvl (optional number) error level offset, default 0 (=errors point to the function calling :ValidateOptionsTable)
|
||||
function AceConfigRegistry:ValidateOptionsTable(options,name,errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
name = name or "Optionstable"
|
||||
if not options.name then
|
||||
options.name=name -- bit of a hack, the root level doesn't really need a .name :-/
|
||||
end
|
||||
validate(options,errlvl,name)
|
||||
end
|
||||
|
||||
--- Fires a "ConfigTableChange" callback for those listening in on it, allowing config GUIs to refresh.
|
||||
-- You should call this function if your options table changed from any outside event, like a game event
|
||||
-- or a timer.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
function AceConfigRegistry:NotifyChange(appName)
|
||||
if not AceConfigRegistry.tables[appName] then return end
|
||||
AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName)
|
||||
end
|
||||
|
||||
-- -------------------------------------------------------------------
|
||||
-- Registering and retreiving options tables:
|
||||
|
||||
|
||||
-- validateGetterArgs: helper function for :GetOptionsTable (or, rather, the getter functions returned by it)
|
||||
|
||||
local function validateGetterArgs(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+2
|
||||
if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
|
||||
error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
|
||||
end
|
||||
if not strmatch(uiName, "[A-Za-z]%-[0-9]") then -- Expecting e.g. "MyLib-1.2"
|
||||
error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
|
||||
end
|
||||
end
|
||||
|
||||
--- Register an options table with the config registry.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
-- @param options The options table, OR a function reference that generates it on demand. \\
|
||||
-- See the top of the page for info on arguments passed to such functions.
|
||||
function AceConfigRegistry:RegisterOptionsTable(appName, options)
|
||||
if type(options)=="table" then
|
||||
if options.type~="group" then -- quick sanity checker
|
||||
error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - missing type='group' member in root group", 2)
|
||||
end
|
||||
AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
validateGetterArgs(uiType, uiName, errlvl)
|
||||
if not AceConfigRegistry.validated[uiType][appName] then
|
||||
AceConfigRegistry:ValidateOptionsTable(options, appName, errlvl) -- upgradable
|
||||
AceConfigRegistry.validated[uiType][appName] = true
|
||||
end
|
||||
return options
|
||||
end
|
||||
elseif type(options)=="function" then
|
||||
AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
|
||||
errlvl=(errlvl or 0)+1
|
||||
validateGetterArgs(uiType, uiName, errlvl)
|
||||
local tab = assert(options(uiType, uiName, appName))
|
||||
if not AceConfigRegistry.validated[uiType][appName] then
|
||||
AceConfigRegistry:ValidateOptionsTable(tab, appName, errlvl) -- upgradable
|
||||
AceConfigRegistry.validated[uiType][appName] = true
|
||||
end
|
||||
return tab
|
||||
end
|
||||
else
|
||||
error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - expected table or function reference", 2)
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns an iterator of ["appName"]=funcref pairs
|
||||
function AceConfigRegistry:IterateOptionsTables()
|
||||
return pairs(AceConfigRegistry.tables)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Query the registry for a specific options table.
|
||||
-- If only appName is given, a function is returned which you
|
||||
-- can call with (uiType,uiName) to get the table.\\
|
||||
-- If uiType&uiName are given, the table is returned.
|
||||
-- @param appName The application name as given to `:RegisterOptionsTable()`
|
||||
-- @param uiType The type of UI to get the table for, one of "cmd", "dropdown", "dialog"
|
||||
-- @param uiName The name of the library/addon querying for the table, e.g. "MyLib-1.0"
|
||||
function AceConfigRegistry:GetOptionsTable(appName, uiType, uiName)
|
||||
local f = AceConfigRegistry.tables[appName]
|
||||
if not f then
|
||||
return nil
|
||||
end
|
||||
|
||||
if uiType then
|
||||
return f(uiType,uiName,1) -- get the table for us
|
||||
else
|
||||
return f -- return the function
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceConfigRegistry-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,250 @@
|
||||
--- **AceConsole-3.0** provides registration facilities for slash commands.
|
||||
-- You can register slash commands to your custom functions and use the `GetArgs` function to parse them
|
||||
-- to your addons individual needs.
|
||||
--
|
||||
-- **AceConsole-3.0** can be embeded into your addon, either explicitly by calling AceConsole:Embed(MyAddon) or by
|
||||
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
|
||||
-- and can be accessed directly, without having to explicitly call AceConsole itself.\\
|
||||
-- It is recommended to embed AceConsole, otherwise you'll have to specify a custom `self` on all calls you
|
||||
-- make into AceConsole.
|
||||
-- @class file
|
||||
-- @name AceConsole-3.0
|
||||
-- @release $Id: AceConsole-3.0.lua 878 2009-11-02 18:51:58Z nevcairiel $
|
||||
local MAJOR,MINOR = "AceConsole-3.0", 7
|
||||
|
||||
local AceConsole, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceConsole then return end -- No upgrade needed
|
||||
|
||||
AceConsole.embeds = AceConsole.embeds or {} -- table containing objects AceConsole is embedded in.
|
||||
AceConsole.commands = AceConsole.commands or {} -- table containing commands registered
|
||||
AceConsole.weakcommands = AceConsole.weakcommands or {} -- table containing self, command => func references for weak commands that don't persist through enable/disable
|
||||
|
||||
-- Lua APIs
|
||||
local tconcat, tostring, select = table.concat, tostring, select
|
||||
local type, pairs, error = type, pairs, error
|
||||
local format, strfind, strsub = string.format, string.find, string.sub
|
||||
local max = math.max
|
||||
|
||||
-- WoW APIs
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: DEFAULT_CHAT_FRAME, SlashCmdList, hash_SlashCmdList
|
||||
|
||||
local tmp={}
|
||||
local function Print(self,frame,...)
|
||||
local n=0
|
||||
if self ~= AceConsole then
|
||||
n=n+1
|
||||
tmp[n] = "|cff33ff99"..tostring( self ).."|r:"
|
||||
end
|
||||
for i=1, select("#", ...) do
|
||||
n=n+1
|
||||
tmp[n] = tostring(select(i, ...))
|
||||
end
|
||||
frame:AddMessage( tconcat(tmp," ",1,n) )
|
||||
end
|
||||
|
||||
--- Print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
|
||||
-- @paramsig [chatframe ,] ...
|
||||
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
|
||||
-- @param ... List of any values to be printed
|
||||
function AceConsole:Print(...)
|
||||
local frame = ...
|
||||
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
|
||||
return Print(self, frame, select(2,...))
|
||||
else
|
||||
return Print(self, DEFAULT_CHAT_FRAME, ...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Formatted (using format()) print to DEFAULT_CHAT_FRAME or given ChatFrame (anything with an .AddMessage function)
|
||||
-- @paramsig [chatframe ,] "format"[, ...]
|
||||
-- @param chatframe Custom ChatFrame to print to (or any frame with an .AddMessage function)
|
||||
-- @param format Format string - same syntax as standard Lua format()
|
||||
-- @param ... Arguments to the format string
|
||||
function AceConsole:Printf(...)
|
||||
local frame = ...
|
||||
if type(frame) == "table" and frame.AddMessage then -- Is first argument something with an .AddMessage member?
|
||||
return Print(self, frame, format(select(2,...)))
|
||||
else
|
||||
return Print(self, DEFAULT_CHAT_FRAME, format(...))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--- Register a simple chat command
|
||||
-- @param command Chat command to be registered WITHOUT leading "/"
|
||||
-- @param func Function to call when the slash command is being used (funcref or methodname)
|
||||
-- @param persist if false, the command will be soft disabled/enabled when aceconsole is used as a mixin (default: true)
|
||||
function AceConsole:RegisterChatCommand( command, func, persist )
|
||||
if type(command)~="string" then error([[Usage: AceConsole:RegisterChatCommand( "command", func[, persist ]): 'command' - expected a string]], 2) end
|
||||
|
||||
if persist==nil then persist=true end -- I'd rather have my addon's "/addon enable" around if the author screws up. Having some extra slash regged when it shouldnt be isn't as destructive. True is a better default. /Mikk
|
||||
|
||||
local name = "ACECONSOLE_"..command:upper()
|
||||
|
||||
if type( func ) == "string" then
|
||||
SlashCmdList[name] = function(input, editBox)
|
||||
self[func](self, input, editBox)
|
||||
end
|
||||
else
|
||||
SlashCmdList[name] = func
|
||||
end
|
||||
_G["SLASH_"..name.."1"] = "/"..command:lower()
|
||||
AceConsole.commands[command] = name
|
||||
-- non-persisting commands are registered for enabling disabling
|
||||
if not persist then
|
||||
if not AceConsole.weakcommands[self] then AceConsole.weakcommands[self] = {} end
|
||||
AceConsole.weakcommands[self][command] = func
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Unregister a chatcommand
|
||||
-- @param command Chat command to be unregistered WITHOUT leading "/"
|
||||
function AceConsole:UnregisterChatCommand( command )
|
||||
local name = AceConsole.commands[command]
|
||||
if name then
|
||||
SlashCmdList[name] = nil
|
||||
_G["SLASH_" .. name .. "1"] = nil
|
||||
hash_SlashCmdList["/" .. command:upper()] = nil
|
||||
AceConsole.commands[command] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Get an iterator over all Chat Commands registered with AceConsole
|
||||
-- @return Iterator (pairs) over all commands
|
||||
function AceConsole:IterateChatCommands() return pairs(AceConsole.commands) end
|
||||
|
||||
|
||||
local function nils(n, ...)
|
||||
if n>1 then
|
||||
return nil, nils(n-1, ...)
|
||||
elseif n==1 then
|
||||
return nil, ...
|
||||
else
|
||||
return ...
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- Retreive one or more space-separated arguments from a string.
|
||||
-- Treats quoted strings and itemlinks as non-spaced.
|
||||
-- @param string The raw argument string
|
||||
-- @param numargs How many arguments to get (default 1)
|
||||
-- @param startpos Where in the string to start scanning (default 1)
|
||||
-- @return Returns arg1, arg2, ..., nextposition\\
|
||||
-- Missing arguments will be returned as nils. 'nextposition' is returned as 1e9 at the end of the string.
|
||||
function AceConsole:GetArgs(str, numargs, startpos)
|
||||
numargs = numargs or 1
|
||||
startpos = max(startpos or 1, 1)
|
||||
|
||||
local pos=startpos
|
||||
|
||||
-- find start of new arg
|
||||
pos = strfind(str, "[^ ]", pos)
|
||||
if not pos then -- whoops, end of string
|
||||
return nils(numargs, 1e9)
|
||||
end
|
||||
|
||||
if numargs<1 then
|
||||
return pos
|
||||
end
|
||||
|
||||
-- quoted or space separated? find out which pattern to use
|
||||
local delim_or_pipe
|
||||
local ch = strsub(str, pos, pos)
|
||||
if ch=='"' then
|
||||
pos = pos + 1
|
||||
delim_or_pipe='([|"])'
|
||||
elseif ch=="'" then
|
||||
pos = pos + 1
|
||||
delim_or_pipe="([|'])"
|
||||
else
|
||||
delim_or_pipe="([| ])"
|
||||
end
|
||||
|
||||
startpos = pos
|
||||
|
||||
while true do
|
||||
-- find delimiter or hyperlink
|
||||
local ch,_
|
||||
pos,_,ch = strfind(str, delim_or_pipe, pos)
|
||||
|
||||
if not pos then break end
|
||||
|
||||
if ch=="|" then
|
||||
-- some kind of escape
|
||||
|
||||
if strsub(str,pos,pos+1)=="|H" then
|
||||
-- It's a |H....|hhyper link!|h
|
||||
pos=strfind(str, "|h", pos+2) -- first |h
|
||||
if not pos then break end
|
||||
|
||||
pos=strfind(str, "|h", pos+2) -- second |h
|
||||
if not pos then break end
|
||||
elseif strsub(str,pos, pos+1) == "|T" then
|
||||
-- It's a |T....|t texture
|
||||
pos=strfind(str, "|t", pos+2)
|
||||
if not pos then break end
|
||||
end
|
||||
|
||||
pos=pos+2 -- skip past this escape (last |h if it was a hyperlink)
|
||||
|
||||
else
|
||||
-- found delimiter, done with this arg
|
||||
return strsub(str, startpos, pos-1), AceConsole:GetArgs(str, numargs-1, pos+1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- search aborted, we hit end of string. return it all as one argument. (yes, even if it's an unterminated quote or hyperlink)
|
||||
return strsub(str, startpos), nils(numargs-1, 1e9)
|
||||
end
|
||||
|
||||
|
||||
--- embedding and embed handling
|
||||
|
||||
local mixins = {
|
||||
"Print",
|
||||
"Printf",
|
||||
"RegisterChatCommand",
|
||||
"UnregisterChatCommand",
|
||||
"GetArgs",
|
||||
}
|
||||
|
||||
-- Embeds AceConsole into the target object making the functions from the mixins list available on target:..
|
||||
-- @param target target object to embed AceBucket in
|
||||
function AceConsole:Embed( target )
|
||||
for k, v in pairs( mixins ) do
|
||||
target[v] = self[v]
|
||||
end
|
||||
self.embeds[target] = true
|
||||
return target
|
||||
end
|
||||
|
||||
function AceConsole:OnEmbedEnable( target )
|
||||
if AceConsole.weakcommands[target] then
|
||||
for command, func in pairs( AceConsole.weakcommands[target] ) do
|
||||
target:RegisterChatCommand( command, func, false, true ) -- nonpersisting and silent registry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function AceConsole:OnEmbedDisable( target )
|
||||
if AceConsole.weakcommands[target] then
|
||||
for command, func in pairs( AceConsole.weakcommands[target] ) do
|
||||
target:UnregisterChatCommand( command ) -- TODO: this could potentially unregister a command from another application in case of command conflicts. Do we care?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for addon in pairs(AceConsole.embeds) do
|
||||
AceConsole:Embed(addon)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceConsole-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,728 @@
|
||||
--- **AceDB-3.0** manages the SavedVariables of your addon.
|
||||
-- It offers profile management, smart defaults and namespaces for modules.\\
|
||||
-- Data can be saved in different data-types, depending on its intended usage.
|
||||
-- The most common data-type is the `profile` type, which allows the user to choose
|
||||
-- the active profile, and manage the profiles of all of his characters.\\
|
||||
-- The following data types are available:
|
||||
-- * **char** Character-specific data. Every character has its own database.
|
||||
-- * **realm** Realm-specific data. All of the players characters on the same realm share this database.
|
||||
-- * **class** Class-specific data. All of the players characters of the same class share this database.
|
||||
-- * **race** Race-specific data. All of the players characters of the same race share this database.
|
||||
-- * **faction** Faction-specific data. All of the players characters of the same faction share this database.
|
||||
-- * **factionrealm** Faction and realm specific data. All of the players characters on the same realm and of the same faction share this database.
|
||||
-- * **global** Global Data. All characters on the same account share this database.
|
||||
-- * **profile** Profile-specific data. All characters using the same profile share this database. The user can control which profile should be used.
|
||||
--
|
||||
-- Creating a new Database using the `:New` function will return a new DBObject. A database will inherit all functions
|
||||
-- of the DBObjectLib listed here. \\
|
||||
-- If you create a new namespaced child-database (`:RegisterNamespace`), you'll get a DBObject as well, but note
|
||||
-- that the child-databases cannot individually change their profile, and are linked to their parents profile - and because of that,
|
||||
-- the profile related APIs are not available. Only `:RegisterDefaults` and `:ResetProfile` are available on child-databases.
|
||||
--
|
||||
-- For more details on how to use AceDB-3.0, see the [[AceDB-3.0 Tutorial]].
|
||||
--
|
||||
-- You may also be interested in [[libdualspec-1-0|LibDualSpec-1.0]] to do profile switching automatically when switching specs.
|
||||
--
|
||||
-- @usage
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("DBExample")
|
||||
--
|
||||
-- -- declare defaults to be used in the DB
|
||||
-- local defaults = {
|
||||
-- profile = {
|
||||
-- setting = true,
|
||||
-- }
|
||||
-- }
|
||||
--
|
||||
-- function MyAddon:OnInitialize()
|
||||
-- -- Assuming the .toc says ## SavedVariables: MyAddonDB
|
||||
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
|
||||
-- end
|
||||
-- @class file
|
||||
-- @name AceDB-3.0.lua
|
||||
-- @release $Id: AceDB-3.0.lua 940 2010-06-19 08:01:47Z nevcairiel $
|
||||
local ACEDB_MAJOR, ACEDB_MINOR = "AceDB-3.0", 21
|
||||
local AceDB, oldminor = LibStub:NewLibrary(ACEDB_MAJOR, ACEDB_MINOR)
|
||||
|
||||
if not AceDB then return end -- No upgrade needed
|
||||
|
||||
-- Lua APIs
|
||||
local type, pairs, next, error = type, pairs, next, error
|
||||
local setmetatable, getmetatable, rawset, rawget = setmetatable, getmetatable, rawset, rawget
|
||||
|
||||
-- WoW APIs
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: LibStub
|
||||
|
||||
AceDB.db_registry = AceDB.db_registry or {}
|
||||
AceDB.frame = AceDB.frame or CreateFrame("Frame")
|
||||
|
||||
local CallbackHandler
|
||||
local CallbackDummy = { Fire = function() end }
|
||||
|
||||
local DBObjectLib = {}
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
AceDB Utility Functions
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
-- Simple shallow copy for copying defaults
|
||||
local function copyTable(src, dest)
|
||||
if type(dest) ~= "table" then dest = {} end
|
||||
if type(src) == "table" then
|
||||
for k,v in pairs(src) do
|
||||
if type(v) == "table" then
|
||||
-- try to index the key first so that the metatable creates the defaults, if set, and use that table
|
||||
v = copyTable(v, dest[k])
|
||||
end
|
||||
dest[k] = v
|
||||
end
|
||||
end
|
||||
return dest
|
||||
end
|
||||
|
||||
-- Called to add defaults to a section of the database
|
||||
--
|
||||
-- When a ["*"] default section is indexed with a new key, a table is returned
|
||||
-- and set in the host table. These tables must be cleaned up by removeDefaults
|
||||
-- in order to ensure we don't write empty default tables.
|
||||
local function copyDefaults(dest, src)
|
||||
-- this happens if some value in the SV overwrites our default value with a non-table
|
||||
--if type(dest) ~= "table" then return end
|
||||
for k, v in pairs(src) do
|
||||
if k == "*" or k == "**" then
|
||||
if type(v) == "table" then
|
||||
-- This is a metatable used for table defaults
|
||||
local mt = {
|
||||
-- This handles the lookup and creation of new subtables
|
||||
__index = function(t,k)
|
||||
if k == nil then return nil end
|
||||
local tbl = {}
|
||||
copyDefaults(tbl, v)
|
||||
rawset(t, k, tbl)
|
||||
return tbl
|
||||
end,
|
||||
}
|
||||
setmetatable(dest, mt)
|
||||
-- handle already existing tables in the SV
|
||||
for dk, dv in pairs(dest) do
|
||||
if not rawget(src, dk) and type(dv) == "table" then
|
||||
copyDefaults(dv, v)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Values are not tables, so this is just a simple return
|
||||
local mt = {__index = function(t,k) return k~=nil and v or nil end}
|
||||
setmetatable(dest, mt)
|
||||
end
|
||||
elseif type(v) == "table" then
|
||||
if not rawget(dest, k) then rawset(dest, k, {}) end
|
||||
if type(dest[k]) == "table" then
|
||||
copyDefaults(dest[k], v)
|
||||
if src['**'] then
|
||||
copyDefaults(dest[k], src['**'])
|
||||
end
|
||||
end
|
||||
else
|
||||
if rawget(dest, k) == nil then
|
||||
rawset(dest, k, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Called to remove all defaults in the default table from the database
|
||||
local function removeDefaults(db, defaults, blocker)
|
||||
-- remove all metatables from the db, so we don't accidentally create new sub-tables through them
|
||||
setmetatable(db, nil)
|
||||
-- loop through the defaults and remove their content
|
||||
for k,v in pairs(defaults) do
|
||||
if k == "*" or k == "**" then
|
||||
if type(v) == "table" then
|
||||
-- Loop through all the actual k,v pairs and remove
|
||||
for key, value in pairs(db) do
|
||||
if type(value) == "table" then
|
||||
-- if the key was not explicitly specified in the defaults table, just strip everything from * and ** tables
|
||||
if defaults[key] == nil and (not blocker or blocker[key] == nil) then
|
||||
removeDefaults(value, v)
|
||||
-- if the table is empty afterwards, remove it
|
||||
if next(value) == nil then
|
||||
db[key] = nil
|
||||
end
|
||||
-- if it was specified, only strip ** content, but block values which were set in the key table
|
||||
elseif k == "**" then
|
||||
removeDefaults(value, v, defaults[key])
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif k == "*" then
|
||||
-- check for non-table default
|
||||
for key, value in pairs(db) do
|
||||
if defaults[key] == nil and v == value then
|
||||
db[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif type(v) == "table" and type(db[k]) == "table" then
|
||||
-- if a blocker was set, dive into it, to allow multi-level defaults
|
||||
removeDefaults(db[k], v, blocker and blocker[k])
|
||||
if next(db[k]) == nil then
|
||||
db[k] = nil
|
||||
end
|
||||
else
|
||||
-- check if the current value matches the default, and that its not blocked by another defaults table
|
||||
if db[k] == defaults[k] and (not blocker or blocker[k] == nil) then
|
||||
db[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- This is called when a table section is first accessed, to set up the defaults
|
||||
local function initSection(db, section, svstore, key, defaults)
|
||||
local sv = rawget(db, "sv")
|
||||
|
||||
local tableCreated
|
||||
if not sv[svstore] then sv[svstore] = {} end
|
||||
if not sv[svstore][key] then
|
||||
sv[svstore][key] = {}
|
||||
tableCreated = true
|
||||
end
|
||||
|
||||
local tbl = sv[svstore][key]
|
||||
|
||||
if defaults then
|
||||
copyDefaults(tbl, defaults)
|
||||
end
|
||||
rawset(db, section, tbl)
|
||||
|
||||
return tableCreated, tbl
|
||||
end
|
||||
|
||||
-- Metatable to handle the dynamic creation of sections and copying of sections.
|
||||
local dbmt = {
|
||||
__index = function(t, section)
|
||||
local keys = rawget(t, "keys")
|
||||
local key = keys[section]
|
||||
if key then
|
||||
local defaultTbl = rawget(t, "defaults")
|
||||
local defaults = defaultTbl and defaultTbl[section]
|
||||
|
||||
if section == "profile" then
|
||||
local new = initSection(t, section, "profiles", key, defaults)
|
||||
if new then
|
||||
-- Callback: OnNewProfile, database, newProfileKey
|
||||
t.callbacks:Fire("OnNewProfile", t, key)
|
||||
end
|
||||
elseif section == "profiles" then
|
||||
local sv = rawget(t, "sv")
|
||||
if not sv.profiles then sv.profiles = {} end
|
||||
rawset(t, "profiles", sv.profiles)
|
||||
elseif section == "global" then
|
||||
local sv = rawget(t, "sv")
|
||||
if not sv.global then sv.global = {} end
|
||||
if defaults then
|
||||
copyDefaults(sv.global, defaults)
|
||||
end
|
||||
rawset(t, section, sv.global)
|
||||
else
|
||||
initSection(t, section, section, key, defaults)
|
||||
end
|
||||
end
|
||||
|
||||
return rawget(t, section)
|
||||
end
|
||||
}
|
||||
|
||||
local function validateDefaults(defaults, keyTbl, offset)
|
||||
if not defaults then return end
|
||||
offset = offset or 0
|
||||
for k in pairs(defaults) do
|
||||
if not keyTbl[k] or k == "profiles" then
|
||||
error(("Usage: AceDBObject:RegisterDefaults(defaults): '%s' is not a valid datatype."):format(k), 3 + offset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local preserve_keys = {
|
||||
["callbacks"] = true,
|
||||
["RegisterCallback"] = true,
|
||||
["UnregisterCallback"] = true,
|
||||
["UnregisterAllCallbacks"] = true,
|
||||
["children"] = true,
|
||||
}
|
||||
|
||||
local realmKey = GetRealmName()
|
||||
local charKey = UnitName("player") .. " - " .. realmKey
|
||||
local _, classKey = UnitClass("player")
|
||||
local _, raceKey = UnitRace("player")
|
||||
local factionKey = UnitFactionGroup("player")
|
||||
local factionrealmKey = factionKey .. " - " .. realmKey
|
||||
-- Actual database initialization function
|
||||
local function initdb(sv, defaults, defaultProfile, olddb, parent)
|
||||
-- Generate the database keys for each section
|
||||
|
||||
-- map "true" to our "Default" profile
|
||||
if defaultProfile == true then defaultProfile = "Default" end
|
||||
|
||||
local profileKey
|
||||
if not parent then
|
||||
-- Make a container for profile keys
|
||||
if not sv.profileKeys then sv.profileKeys = {} end
|
||||
|
||||
-- Try to get the profile selected from the char db
|
||||
profileKey = sv.profileKeys[charKey] or defaultProfile or charKey
|
||||
|
||||
-- save the selected profile for later
|
||||
sv.profileKeys[charKey] = profileKey
|
||||
else
|
||||
-- Use the profile of the parents DB
|
||||
profileKey = parent.keys.profile or defaultProfile or charKey
|
||||
|
||||
-- clear the profileKeys in the DB, namespaces don't need to store them
|
||||
sv.profileKeys = nil
|
||||
end
|
||||
|
||||
-- This table contains keys that enable the dynamic creation
|
||||
-- of each section of the table. The 'global' and 'profiles'
|
||||
-- have a key of true, since they are handled in a special case
|
||||
local keyTbl= {
|
||||
["char"] = charKey,
|
||||
["realm"] = realmKey,
|
||||
["class"] = classKey,
|
||||
["race"] = raceKey,
|
||||
["faction"] = factionKey,
|
||||
["factionrealm"] = factionrealmKey,
|
||||
["profile"] = profileKey,
|
||||
["global"] = true,
|
||||
["profiles"] = true,
|
||||
}
|
||||
|
||||
validateDefaults(defaults, keyTbl, 1)
|
||||
|
||||
-- This allows us to use this function to reset an entire database
|
||||
-- Clear out the old database
|
||||
if olddb then
|
||||
for k,v in pairs(olddb) do if not preserve_keys[k] then olddb[k] = nil end end
|
||||
end
|
||||
|
||||
-- Give this database the metatable so it initializes dynamically
|
||||
local db = setmetatable(olddb or {}, dbmt)
|
||||
|
||||
if not rawget(db, "callbacks") then
|
||||
-- try to load CallbackHandler-1.0 if it loaded after our library
|
||||
if not CallbackHandler then CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0", true) end
|
||||
db.callbacks = CallbackHandler and CallbackHandler:New(db) or CallbackDummy
|
||||
end
|
||||
|
||||
-- Copy methods locally into the database object, to avoid hitting
|
||||
-- the metatable when calling methods
|
||||
|
||||
if not parent then
|
||||
for name, func in pairs(DBObjectLib) do
|
||||
db[name] = func
|
||||
end
|
||||
else
|
||||
-- hack this one in
|
||||
db.RegisterDefaults = DBObjectLib.RegisterDefaults
|
||||
db.ResetProfile = DBObjectLib.ResetProfile
|
||||
end
|
||||
|
||||
-- Set some properties in the database object
|
||||
db.profiles = sv.profiles
|
||||
db.keys = keyTbl
|
||||
db.sv = sv
|
||||
--db.sv_name = name
|
||||
db.defaults = defaults
|
||||
db.parent = parent
|
||||
|
||||
-- store the DB in the registry
|
||||
AceDB.db_registry[db] = true
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
-- handle PLAYER_LOGOUT
|
||||
-- strip all defaults from all databases
|
||||
-- and cleans up empty sections
|
||||
local function logoutHandler(frame, event)
|
||||
if event == "PLAYER_LOGOUT" then
|
||||
for db in pairs(AceDB.db_registry) do
|
||||
db.callbacks:Fire("OnDatabaseShutdown", db)
|
||||
db:RegisterDefaults(nil)
|
||||
|
||||
-- cleanup sections that are empty without defaults
|
||||
local sv = rawget(db, "sv")
|
||||
for section in pairs(db.keys) do
|
||||
if rawget(sv, section) then
|
||||
-- global is special, all other sections have sub-entrys
|
||||
-- also don't delete empty profiles on main dbs, only on namespaces
|
||||
if section ~= "global" and (section ~= "profiles" or rawget(db, "parent")) then
|
||||
for key in pairs(sv[section]) do
|
||||
if not next(sv[section][key]) then
|
||||
sv[section][key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if not next(sv[section]) then
|
||||
sv[section] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
AceDB.frame:RegisterEvent("PLAYER_LOGOUT")
|
||||
AceDB.frame:SetScript("OnEvent", logoutHandler)
|
||||
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
AceDB Object Method Definitions
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
--- Sets the defaults table for the given database object by clearing any
|
||||
-- that are currently set, and then setting the new defaults.
|
||||
-- @param defaults A table of defaults for this database
|
||||
function DBObjectLib:RegisterDefaults(defaults)
|
||||
if defaults and type(defaults) ~= "table" then
|
||||
error("Usage: AceDBObject:RegisterDefaults(defaults): 'defaults' - table or nil expected.", 2)
|
||||
end
|
||||
|
||||
validateDefaults(defaults, self.keys)
|
||||
|
||||
-- Remove any currently set defaults
|
||||
if self.defaults then
|
||||
for section,key in pairs(self.keys) do
|
||||
if self.defaults[section] and rawget(self, section) then
|
||||
removeDefaults(self[section], self.defaults[section])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the DBObject.defaults table
|
||||
self.defaults = defaults
|
||||
|
||||
-- Copy in any defaults, only touching those sections already created
|
||||
if defaults then
|
||||
for section,key in pairs(self.keys) do
|
||||
if defaults[section] and rawget(self, section) then
|
||||
copyDefaults(self[section], defaults[section])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Changes the profile of the database and all of it's namespaces to the
|
||||
-- supplied named profile
|
||||
-- @param name The name of the profile to set as the current profile
|
||||
function DBObjectLib:SetProfile(name)
|
||||
if type(name) ~= "string" then
|
||||
error("Usage: AceDBObject:SetProfile(name): 'name' - string expected.", 2)
|
||||
end
|
||||
|
||||
-- changing to the same profile, dont do anything
|
||||
if name == self.keys.profile then return end
|
||||
|
||||
local oldProfile = self.profile
|
||||
local defaults = self.defaults and self.defaults.profile
|
||||
|
||||
-- Callback: OnProfileShutdown, database
|
||||
self.callbacks:Fire("OnProfileShutdown", self)
|
||||
|
||||
if oldProfile and defaults then
|
||||
-- Remove the defaults from the old profile
|
||||
removeDefaults(oldProfile, defaults)
|
||||
end
|
||||
|
||||
self.profile = nil
|
||||
self.keys["profile"] = name
|
||||
|
||||
-- if the storage exists, save the new profile
|
||||
-- this won't exist on namespaces.
|
||||
if self.sv.profileKeys then
|
||||
self.sv.profileKeys[charKey] = name
|
||||
end
|
||||
|
||||
-- populate to child namespaces
|
||||
if self.children then
|
||||
for _, db in pairs(self.children) do
|
||||
DBObjectLib.SetProfile(db, name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callback: OnProfileChanged, database, newProfileKey
|
||||
self.callbacks:Fire("OnProfileChanged", self, name)
|
||||
end
|
||||
|
||||
--- Returns a table with the names of the existing profiles in the database.
|
||||
-- You can optionally supply a table to re-use for this purpose.
|
||||
-- @param tbl A table to store the profile names in (optional)
|
||||
function DBObjectLib:GetProfiles(tbl)
|
||||
if tbl and type(tbl) ~= "table" then
|
||||
error("Usage: AceDBObject:GetProfiles(tbl): 'tbl' - table or nil expected.", 2)
|
||||
end
|
||||
|
||||
-- Clear the container table
|
||||
if tbl then
|
||||
for k,v in pairs(tbl) do tbl[k] = nil end
|
||||
else
|
||||
tbl = {}
|
||||
end
|
||||
|
||||
local curProfile = self.keys.profile
|
||||
|
||||
local i = 0
|
||||
for profileKey in pairs(self.profiles) do
|
||||
i = i + 1
|
||||
tbl[i] = profileKey
|
||||
if curProfile and profileKey == curProfile then curProfile = nil end
|
||||
end
|
||||
|
||||
-- Add the current profile, if it hasn't been created yet
|
||||
if curProfile then
|
||||
i = i + 1
|
||||
tbl[i] = curProfile
|
||||
end
|
||||
|
||||
return tbl, i
|
||||
end
|
||||
|
||||
--- Returns the current profile name used by the database
|
||||
function DBObjectLib:GetCurrentProfile()
|
||||
return self.keys.profile
|
||||
end
|
||||
|
||||
--- Deletes a named profile. This profile must not be the active profile.
|
||||
-- @param name The name of the profile to be deleted
|
||||
-- @param silent If true, do not raise an error when the profile does not exist
|
||||
function DBObjectLib:DeleteProfile(name, silent)
|
||||
if type(name) ~= "string" then
|
||||
error("Usage: AceDBObject:DeleteProfile(name): 'name' - string expected.", 2)
|
||||
end
|
||||
|
||||
if self.keys.profile == name then
|
||||
error("Cannot delete the active profile in an AceDBObject.", 2)
|
||||
end
|
||||
|
||||
if not rawget(self.profiles, name) and not silent then
|
||||
error("Cannot delete profile '" .. name .. "'. It does not exist.", 2)
|
||||
end
|
||||
|
||||
self.profiles[name] = nil
|
||||
|
||||
-- populate to child namespaces
|
||||
if self.children then
|
||||
for _, db in pairs(self.children) do
|
||||
DBObjectLib.DeleteProfile(db, name, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callback: OnProfileDeleted, database, profileKey
|
||||
self.callbacks:Fire("OnProfileDeleted", self, name)
|
||||
end
|
||||
|
||||
--- Copies a named profile into the current profile, overwriting any conflicting
|
||||
-- settings.
|
||||
-- @param name The name of the profile to be copied into the current profile
|
||||
-- @param silent If true, do not raise an error when the profile does not exist
|
||||
function DBObjectLib:CopyProfile(name, silent)
|
||||
if type(name) ~= "string" then
|
||||
error("Usage: AceDBObject:CopyProfile(name): 'name' - string expected.", 2)
|
||||
end
|
||||
|
||||
if name == self.keys.profile then
|
||||
error("Cannot have the same source and destination profiles.", 2)
|
||||
end
|
||||
|
||||
if not rawget(self.profiles, name) and not silent then
|
||||
error("Cannot copy profile '" .. name .. "'. It does not exist.", 2)
|
||||
end
|
||||
|
||||
-- Reset the profile before copying
|
||||
DBObjectLib.ResetProfile(self, nil, true)
|
||||
|
||||
local profile = self.profile
|
||||
local source = self.profiles[name]
|
||||
|
||||
copyTable(source, profile)
|
||||
|
||||
-- populate to child namespaces
|
||||
if self.children then
|
||||
for _, db in pairs(self.children) do
|
||||
DBObjectLib.CopyProfile(db, name, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callback: OnProfileCopied, database, sourceProfileKey
|
||||
self.callbacks:Fire("OnProfileCopied", self, name)
|
||||
end
|
||||
|
||||
--- Resets the current profile to the default values (if specified).
|
||||
-- @param noChildren if set to true, the reset will not be populated to the child namespaces of this DB object
|
||||
-- @param noCallbacks if set to true, won't fire the OnProfileReset callback
|
||||
function DBObjectLib:ResetProfile(noChildren, noCallbacks)
|
||||
local profile = self.profile
|
||||
|
||||
for k,v in pairs(profile) do
|
||||
profile[k] = nil
|
||||
end
|
||||
|
||||
local defaults = self.defaults and self.defaults.profile
|
||||
if defaults then
|
||||
copyDefaults(profile, defaults)
|
||||
end
|
||||
|
||||
-- populate to child namespaces
|
||||
if self.children and not noChildren then
|
||||
for _, db in pairs(self.children) do
|
||||
DBObjectLib.ResetProfile(db, nil, noCallbacks)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callback: OnProfileReset, database
|
||||
if not noCallbacks then
|
||||
self.callbacks:Fire("OnProfileReset", self)
|
||||
end
|
||||
end
|
||||
|
||||
--- Resets the entire database, using the string defaultProfile as the new default
|
||||
-- profile.
|
||||
-- @param defaultProfile The profile name to use as the default
|
||||
function DBObjectLib:ResetDB(defaultProfile)
|
||||
if defaultProfile and type(defaultProfile) ~= "string" then
|
||||
error("Usage: AceDBObject:ResetDB(defaultProfile): 'defaultProfile' - string or nil expected.", 2)
|
||||
end
|
||||
|
||||
local sv = self.sv
|
||||
for k,v in pairs(sv) do
|
||||
sv[k] = nil
|
||||
end
|
||||
|
||||
local parent = self.parent
|
||||
|
||||
initdb(sv, self.defaults, defaultProfile, self)
|
||||
|
||||
-- fix the child namespaces
|
||||
if self.children then
|
||||
if not sv.namespaces then sv.namespaces = {} end
|
||||
for name, db in pairs(self.children) do
|
||||
if not sv.namespaces[name] then sv.namespaces[name] = {} end
|
||||
initdb(sv.namespaces[name], db.defaults, self.keys.profile, db, self)
|
||||
end
|
||||
end
|
||||
|
||||
-- Callback: OnDatabaseReset, database
|
||||
self.callbacks:Fire("OnDatabaseReset", self)
|
||||
-- Callback: OnProfileChanged, database, profileKey
|
||||
self.callbacks:Fire("OnProfileChanged", self, self.keys["profile"])
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Creates a new database namespace, directly tied to the database. This
|
||||
-- is a full scale database in it's own rights other than the fact that
|
||||
-- it cannot control its profile individually
|
||||
-- @param name The name of the new namespace
|
||||
-- @param defaults A table of values to use as defaults
|
||||
function DBObjectLib:RegisterNamespace(name, defaults)
|
||||
if type(name) ~= "string" then
|
||||
error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - string expected.", 2)
|
||||
end
|
||||
if defaults and type(defaults) ~= "table" then
|
||||
error("Usage: AceDBObject:RegisterNamespace(name, defaults): 'defaults' - table or nil expected.", 2)
|
||||
end
|
||||
if self.children and self.children[name] then
|
||||
error ("Usage: AceDBObject:RegisterNamespace(name, defaults): 'name' - a namespace with that name already exists.", 2)
|
||||
end
|
||||
|
||||
local sv = self.sv
|
||||
if not sv.namespaces then sv.namespaces = {} end
|
||||
if not sv.namespaces[name] then
|
||||
sv.namespaces[name] = {}
|
||||
end
|
||||
|
||||
local newDB = initdb(sv.namespaces[name], defaults, self.keys.profile, nil, self)
|
||||
|
||||
if not self.children then self.children = {} end
|
||||
self.children[name] = newDB
|
||||
return newDB
|
||||
end
|
||||
|
||||
--- Returns an already existing namespace from the database object.
|
||||
-- @param name The name of the new namespace
|
||||
-- @param silent if true, the addon is optional, silently return nil if its not found
|
||||
-- @usage
|
||||
-- local namespace = self.db:GetNamespace('namespace')
|
||||
-- @return the namespace object if found
|
||||
function DBObjectLib:GetNamespace(name, silent)
|
||||
if type(name) ~= "string" then
|
||||
error("Usage: AceDBObject:GetNamespace(name): 'name' - string expected.", 2)
|
||||
end
|
||||
if not silent and not (self.children and self.children[name]) then
|
||||
error ("Usage: AceDBObject:GetNamespace(name): 'name' - namespace does not exist.", 2)
|
||||
end
|
||||
if not self.children then self.children = {} end
|
||||
return self.children[name]
|
||||
end
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
AceDB Exposed Methods
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
--- Creates a new database object that can be used to handle database settings and profiles.
|
||||
-- By default, an empty DB is created, using a character specific profile.
|
||||
--
|
||||
-- You can override the default profile used by passing any profile name as the third argument,
|
||||
-- or by passing //true// as the third argument to use a globally shared profile called "Default".
|
||||
--
|
||||
-- Note that there is no token replacement in the default profile name, passing a defaultProfile as "char"
|
||||
-- will use a profile named "char", and not a character-specific profile.
|
||||
-- @param tbl The name of variable, or table to use for the database
|
||||
-- @param defaults A table of database defaults
|
||||
-- @param defaultProfile The name of the default profile. If not set, a character specific profile will be used as the default.
|
||||
-- You can also pass //true// to use a shared global profile called "Default".
|
||||
-- @usage
|
||||
-- -- Create an empty DB using a character-specific default profile.
|
||||
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB")
|
||||
-- @usage
|
||||
-- -- Create a DB using defaults and using a shared default profile
|
||||
-- self.db = LibStub("AceDB-3.0"):New("MyAddonDB", defaults, true)
|
||||
function AceDB:New(tbl, defaults, defaultProfile)
|
||||
if type(tbl) == "string" then
|
||||
local name = tbl
|
||||
tbl = _G[name]
|
||||
if not tbl then
|
||||
tbl = {}
|
||||
_G[name] = tbl
|
||||
end
|
||||
end
|
||||
|
||||
if type(tbl) ~= "table" then
|
||||
error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'tbl' - table expected.", 2)
|
||||
end
|
||||
|
||||
if defaults and type(defaults) ~= "table" then
|
||||
error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaults' - table expected.", 2)
|
||||
end
|
||||
|
||||
if defaultProfile and type(defaultProfile) ~= "string" and defaultProfile ~= true then
|
||||
error("Usage: AceDB:New(tbl, defaults, defaultProfile): 'defaultProfile' - string or true expected.", 2)
|
||||
end
|
||||
|
||||
return initdb(tbl, defaults, defaultProfile)
|
||||
end
|
||||
|
||||
-- upgrade existing databases
|
||||
for db in pairs(AceDB.db_registry) do
|
||||
if not db.parent then
|
||||
for name,func in pairs(DBObjectLib) do
|
||||
db[name] = func
|
||||
end
|
||||
else
|
||||
db.RegisterDefaults = DBObjectLib.RegisterDefaults
|
||||
db.ResetProfile = DBObjectLib.ResetProfile
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceDB-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,420 @@
|
||||
--- AceDBOptions-3.0 provides a universal AceConfig options screen for managing AceDB-3.0 profiles.
|
||||
-- @class file
|
||||
-- @name AceDBOptions-3.0
|
||||
-- @release $Id: AceDBOptions-3.0.lua 938 2010-06-13 07:21:38Z nevcairiel $
|
||||
local ACEDBO_MAJOR, ACEDBO_MINOR = "AceDBOptions-3.0", 12
|
||||
local AceDBOptions, oldminor = LibStub:NewLibrary(ACEDBO_MAJOR, ACEDBO_MINOR)
|
||||
|
||||
if not AceDBOptions then return end -- No upgrade needed
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, next = pairs, next
|
||||
|
||||
-- WoW APIs
|
||||
local UnitClass = UnitClass
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: NORMAL_FONT_COLOR_CODE, FONT_COLOR_CODE_CLOSE
|
||||
|
||||
AceDBOptions.optionTables = AceDBOptions.optionTables or {}
|
||||
AceDBOptions.handlers = AceDBOptions.handlers or {}
|
||||
|
||||
--[[
|
||||
Localization of AceDBOptions-3.0
|
||||
]]
|
||||
|
||||
local L = {
|
||||
default = "Default",
|
||||
intro = "You can change the active database profile, so you can have different settings for every character.",
|
||||
reset_desc = "Reset the current profile back to its default values, in case your configuration is broken, or you simply want to start over.",
|
||||
reset = "Reset Profile",
|
||||
reset_sub = "Reset the current profile to the default",
|
||||
choose_desc = "You can either create a new profile by entering a name in the editbox, or choose one of the already existing profiles.",
|
||||
new = "New",
|
||||
new_sub = "Create a new empty profile.",
|
||||
choose = "Existing Profiles",
|
||||
choose_sub = "Select one of your currently available profiles.",
|
||||
copy_desc = "Copy the settings from one existing profile into the currently active profile.",
|
||||
copy = "Copy From",
|
||||
delete_desc = "Delete existing and unused profiles from the database to save space, and cleanup the SavedVariables file.",
|
||||
delete = "Delete a Profile",
|
||||
delete_sub = "Deletes a profile from the database.",
|
||||
delete_confirm = "Are you sure you want to delete the selected profile?",
|
||||
profiles = "Profiles",
|
||||
profiles_sub = "Manage Profiles",
|
||||
current = "Current Profile:",
|
||||
}
|
||||
|
||||
local LOCALE = GetLocale()
|
||||
if LOCALE == "deDE" then
|
||||
L["default"] = "Standard"
|
||||
L["intro"] = "Hier kannst du das aktive Datenbankprofile \195\164ndern, damit du verschiedene Einstellungen f\195\188r jeden Charakter erstellen kannst, wodurch eine sehr flexible Konfiguration m\195\182glich wird."
|
||||
L["reset_desc"] = "Setzt das momentane Profil auf Standardwerte zur\195\188ck, f\195\188r den Fall das mit der Konfiguration etwas schief lief oder weil du einfach neu starten willst."
|
||||
L["reset"] = "Profil zur\195\188cksetzen"
|
||||
L["reset_sub"] = "Das aktuelle Profil auf Standard zur\195\188cksetzen."
|
||||
L["choose_desc"] = "Du kannst ein neues Profil erstellen, indem du einen neuen Namen in der Eingabebox 'Neu' eingibst, oder w\195\164hle eines der vorhandenen Profile aus."
|
||||
L["new"] = "Neu"
|
||||
L["new_sub"] = "Ein neues Profil erstellen."
|
||||
L["choose"] = "Vorhandene Profile"
|
||||
L["choose_sub"] = "W\195\164hlt ein bereits vorhandenes Profil aus."
|
||||
L["copy_desc"] = "Kopiere die Einstellungen von einem vorhandenen Profil in das aktive Profil."
|
||||
L["copy"] = "Kopieren von..."
|
||||
L["delete_desc"] = "L\195\182sche vorhandene oder unbenutzte Profile aus der Datenbank um Platz zu sparen und um die SavedVariables Datei 'sauber' zu halten."
|
||||
L["delete"] = "Profil l\195\182schen"
|
||||
L["delete_sub"] = "L\195\182scht ein Profil aus der Datenbank."
|
||||
L["delete_confirm"] = "Willst du das ausgew\195\164hlte Profil wirklich l\195\182schen?"
|
||||
L["profiles"] = "Profile"
|
||||
L["profiles_sub"] = "Profile verwalten"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "frFR" then
|
||||
L["default"] = "D\195\169faut"
|
||||
L["intro"] = "Vous pouvez changer le profil actuel afin d'avoir des param\195\168tres diff\195\169rents pour chaque personnage, permettant ainsi d'avoir une configuration tr\195\168s flexible."
|
||||
L["reset_desc"] = "R\195\169initialise le profil actuel au cas o\195\185 votre configuration est corrompue ou si vous voulez tout simplement faire table rase."
|
||||
L["reset"] = "R\195\169initialiser le profil"
|
||||
L["reset_sub"] = "R\195\169initialise le profil actuel avec les param\195\168tres par d\195\169faut."
|
||||
L["choose_desc"] = "Vous pouvez cr\195\169er un nouveau profil en entrant un nouveau nom dans la bo\195\174te de saisie, ou en choississant un des profils d\195\169j\195\160 existants."
|
||||
L["new"] = "Nouveau"
|
||||
L["new_sub"] = "Cr\195\169\195\169e un nouveau profil vierge."
|
||||
L["choose"] = "Profils existants"
|
||||
L["choose_sub"] = "Permet de choisir un des profils d\195\169j\195\160 disponibles."
|
||||
L["copy_desc"] = "Copie les param\195\168tres d'un profil d\195\169j\195\160 existant dans le profil actuellement actif."
|
||||
L["copy"] = "Copier \195\160 partir de"
|
||||
L["delete_desc"] = "Supprime les profils existants inutilis\195\169s de la base de donn\195\169es afin de gagner de la place et de nettoyer le fichier SavedVariables."
|
||||
L["delete"] = "Supprimer un profil"
|
||||
L["delete_sub"] = "Supprime un profil de la base de donn\195\169es."
|
||||
L["delete_confirm"] = "Etes-vous s\195\187r de vouloir supprimer le profil s\195\169lectionn\195\169 ?"
|
||||
L["profiles"] = "Profils"
|
||||
L["profiles_sub"] = "Gestion des profils"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "koKR" then
|
||||
L["default"] = "기본값"
|
||||
L["intro"] = "모든 캐릭터의 다양한 설정과 사용중인 데이터베이스 프로필, 어느것이던지 매우 다루기 쉽게 바꿀수 있습니다."
|
||||
L["reset_desc"] = "단순히 다시 새롭게 구성을 원하는 경우, 현재 프로필을 기본값으로 초기화 합니다."
|
||||
L["reset"] = "프로필 초기화"
|
||||
L["reset_sub"] = "현재의 프로필을 기본값으로 초기화 합니다"
|
||||
L["choose_desc"] = "새로운 이름을 입력하거나, 이미 있는 프로필중 하나를 선택하여 새로운 프로필을 만들 수 있습니다."
|
||||
L["new"] = "새로운 프로필"
|
||||
L["new_sub"] = "새로운 프로필을 만듭니다."
|
||||
L["choose"] = "프로필 선택"
|
||||
L["choose_sub"] = "당신이 현재 이용할수 있는 프로필을 선택합니다."
|
||||
L["copy_desc"] = "현재 사용중인 프로필에, 선택한 프로필의 설정을 복사합니다."
|
||||
L["copy"] = "복사"
|
||||
L["delete_desc"] = "데이터베이스에 사용중이거나 저장된 프로파일 삭제로 SavedVariables 파일의 정리와 공간 절약이 됩니다."
|
||||
L["delete"] = "프로필 삭제"
|
||||
L["delete_sub"] = "데이터베이스의 프로필을 삭제합니다."
|
||||
L["delete_confirm"] = "정말로 선택한 프로필의 삭제를 원하십니까?"
|
||||
L["profiles"] = "프로필"
|
||||
L["profiles_sub"] = "프로필 설정"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "esES" or LOCALE == "esMX" then
|
||||
L["default"] = "Por defecto"
|
||||
L["intro"] = "Puedes cambiar el perfil activo de tal manera que cada personaje tenga diferentes configuraciones."
|
||||
L["reset_desc"] = "Reinicia el perfil actual a los valores por defectos, en caso de que se haya estropeado la configuración o quieras volver a empezar de nuevo."
|
||||
L["reset"] = "Reiniciar Perfil"
|
||||
L["reset_sub"] = "Reinicar el perfil actual al de por defecto"
|
||||
L["choose_desc"] = "Puedes crear un nuevo perfil introduciendo un nombre en el recuadro o puedes seleccionar un perfil de los ya existentes."
|
||||
L["new"] = "Nuevo"
|
||||
L["new_sub"] = "Crear un nuevo perfil vacio."
|
||||
L["choose"] = "Perfiles existentes"
|
||||
L["choose_sub"] = "Selecciona uno de los perfiles disponibles."
|
||||
L["copy_desc"] = "Copia los ajustes de un perfil existente al perfil actual."
|
||||
L["copy"] = "Copiar de"
|
||||
L["delete_desc"] = "Borra los perfiles existentes y sin uso de la base de datos para ganar espacio y limpiar el archivo SavedVariables."
|
||||
L["delete"] = "Borrar un Perfil"
|
||||
L["delete_sub"] = "Borra un perfil de la base de datos."
|
||||
L["delete_confirm"] = "¿Estas seguro que quieres borrar el perfil seleccionado?"
|
||||
L["profiles"] = "Perfiles"
|
||||
L["profiles_sub"] = "Manejar Perfiles"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "zhTW" then
|
||||
L["default"] = "預設"
|
||||
L["intro"] = "你可以選擇一個活動的資料設定檔,這樣你的每個角色就可以擁有不同的設定值,可以給你的插件設定帶來極大的靈活性。"
|
||||
L["reset_desc"] = "將當前的設定檔恢復到它的預設值,用於你的設定檔損壞,或者你只是想重來的情況。"
|
||||
L["reset"] = "重置設定檔"
|
||||
L["reset_sub"] = "將當前的設定檔恢復為預設值"
|
||||
L["choose_desc"] = "你可以通過在文本框內輸入一個名字創立一個新的設定檔,也可以選擇一個已經存在的設定檔。"
|
||||
L["new"] = "新建"
|
||||
L["new_sub"] = "新建一個空的設定檔。"
|
||||
L["choose"] = "現有的設定檔"
|
||||
L["choose_sub"] = "從當前可用的設定檔裏面選擇一個。"
|
||||
L["copy_desc"] = "從當前某個已保存的設定檔複製到當前正使用的設定檔。"
|
||||
L["copy"] = "複製自"
|
||||
L["delete_desc"] = "從資料庫裏刪除不再使用的設定檔,以節省空間,並且清理SavedVariables檔。"
|
||||
L["delete"] = "刪除一個設定檔"
|
||||
L["delete_sub"] = "從資料庫裏刪除一個設定檔。"
|
||||
L["delete_confirm"] = "你確定要刪除所選擇的設定檔嗎?"
|
||||
L["profiles"] = "設定檔"
|
||||
L["profiles_sub"] = "管理設定檔"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "zhCN" then
|
||||
L["default"] = "默认"
|
||||
L["intro"] = "你可以选择一个活动的数据配置文件,这样你的每个角色就可以拥有不同的设置值,可以给你的插件配置带来极大的灵活性。"
|
||||
L["reset_desc"] = "将当前的配置文件恢复到它的默认值,用于你的配置文件损坏,或者你只是想重来的情况。"
|
||||
L["reset"] = "重置配置文件"
|
||||
L["reset_sub"] = "将当前的配置文件恢复为默认值"
|
||||
L["choose_desc"] = "你可以通过在文本框内输入一个名字创立一个新的配置文件,也可以选择一个已经存在的配置文件。"
|
||||
L["new"] = "新建"
|
||||
L["new_sub"] = "新建一个空的配置文件。"
|
||||
L["choose"] = "现有的配置文件"
|
||||
L["choose_sub"] = "从当前可用的配置文件里面选择一个。"
|
||||
L["copy_desc"] = "从当前某个已保存的配置文件复制到当前正使用的配置文件。"
|
||||
L["copy"] = "复制自"
|
||||
L["delete_desc"] = "从数据库里删除不再使用的配置文件,以节省空间,并且清理SavedVariables文件。"
|
||||
L["delete"] = "删除一个配置文件"
|
||||
L["delete_sub"] = "从数据库里删除一个配置文件。"
|
||||
L["delete_confirm"] = "你确定要删除所选择的配置文件么?"
|
||||
L["profiles"] = "配置文件"
|
||||
L["profiles_sub"] = "管理配置文件"
|
||||
--L["current"] = "Current Profile:"
|
||||
elseif LOCALE == "ruRU" then
|
||||
L["default"] = "По умолчанию"
|
||||
L["intro"] = "Изменяя активный профиль, вы можете задать различные настройки модификаций для каждого персонажа."
|
||||
L["reset_desc"] = "Если ваша конфигурации испорчена или если вы хотите настроить всё заново - сбросьте текущий профиль на стандартные значения."
|
||||
L["reset"] = "Сброс профиля"
|
||||
L["reset_sub"] = "Сброс текущего профиля на стандартный"
|
||||
L["choose_desc"] = "Вы можете создать новый профиль, введя название в поле ввода, или выбрать один из уже существующих профилей."
|
||||
L["new"] = "Новый"
|
||||
L["new_sub"] = "Создать новый чистый профиль"
|
||||
L["choose"] = "Существующие профили"
|
||||
L["choose_sub"] = "Выбор одиного из уже доступных профилей"
|
||||
L["copy_desc"] = "Скопировать настройки из выбранного профиля в активный."
|
||||
L["copy"] = "Скопировать из"
|
||||
L["delete_desc"] = "Удалить существующий и неиспользуемый профиль из БД для сохранения места, и очистить SavedVariables файл."
|
||||
L["delete"] = "Удалить профиль"
|
||||
L["delete_sub"] = "Удаление профиля из БД"
|
||||
L["delete_confirm"] = "Вы уверены, что вы хотите удалить выбранный профиль?"
|
||||
L["profiles"] = "Профили"
|
||||
L["profiles_sub"] = "Управление профилями"
|
||||
--L["current"] = "Current Profile:"
|
||||
end
|
||||
|
||||
local defaultProfiles
|
||||
local tmpprofiles = {}
|
||||
|
||||
-- Get a list of available profiles for the specified database.
|
||||
-- You can specify which profiles to include/exclude in the list using the two boolean parameters listed below.
|
||||
-- @param db The db object to retrieve the profiles from
|
||||
-- @param common If true, getProfileList will add the default profiles to the return list, even if they have not been created yet
|
||||
-- @param nocurrent If true, then getProfileList will not display the current profile in the list
|
||||
-- @return Hashtable of all profiles with the internal name as keys and the display name as value.
|
||||
local function getProfileList(db, common, nocurrent)
|
||||
local profiles = {}
|
||||
|
||||
-- copy existing profiles into the table
|
||||
local currentProfile = db:GetCurrentProfile()
|
||||
for i,v in pairs(db:GetProfiles(tmpprofiles)) do
|
||||
if not (nocurrent and v == currentProfile) then
|
||||
profiles[v] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- add our default profiles to choose from ( or rename existing profiles)
|
||||
for k,v in pairs(defaultProfiles) do
|
||||
if (common or profiles[k]) and not (nocurrent and k == currentProfile) then
|
||||
profiles[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
return profiles
|
||||
end
|
||||
|
||||
--[[
|
||||
OptionsHandlerPrototype
|
||||
prototype class for handling the options in a sane way
|
||||
]]
|
||||
local OptionsHandlerPrototype = {}
|
||||
|
||||
--[[ Reset the profile ]]
|
||||
function OptionsHandlerPrototype:Reset()
|
||||
self.db:ResetProfile()
|
||||
end
|
||||
|
||||
--[[ Set the profile to value ]]
|
||||
function OptionsHandlerPrototype:SetProfile(info, value)
|
||||
self.db:SetProfile(value)
|
||||
end
|
||||
|
||||
--[[ returns the currently active profile ]]
|
||||
function OptionsHandlerPrototype:GetCurrentProfile()
|
||||
return self.db:GetCurrentProfile()
|
||||
end
|
||||
|
||||
--[[
|
||||
List all active profiles
|
||||
you can control the output with the .arg variable
|
||||
currently four modes are supported
|
||||
|
||||
(empty) - return all available profiles
|
||||
"nocurrent" - returns all available profiles except the currently active profile
|
||||
"common" - returns all avaialble profiles + some commonly used profiles ("char - realm", "realm", "class", "Default")
|
||||
"both" - common except the active profile
|
||||
]]
|
||||
function OptionsHandlerPrototype:ListProfiles(info)
|
||||
local arg = info.arg
|
||||
local profiles
|
||||
if arg == "common" and not self.noDefaultProfiles then
|
||||
profiles = getProfileList(self.db, true, nil)
|
||||
elseif arg == "nocurrent" then
|
||||
profiles = getProfileList(self.db, nil, true)
|
||||
elseif arg == "both" then -- currently not used
|
||||
profiles = getProfileList(self.db, (not self.noDefaultProfiles) and true, true)
|
||||
else
|
||||
profiles = getProfileList(self.db)
|
||||
end
|
||||
|
||||
return profiles
|
||||
end
|
||||
|
||||
function OptionsHandlerPrototype:HasNoProfiles(info)
|
||||
local profiles = self:ListProfiles(info)
|
||||
return ((not next(profiles)) and true or false)
|
||||
end
|
||||
|
||||
--[[ Copy a profile ]]
|
||||
function OptionsHandlerPrototype:CopyProfile(info, value)
|
||||
self.db:CopyProfile(value)
|
||||
end
|
||||
|
||||
--[[ Delete a profile from the db ]]
|
||||
function OptionsHandlerPrototype:DeleteProfile(info, value)
|
||||
self.db:DeleteProfile(value)
|
||||
end
|
||||
|
||||
--[[ fill defaultProfiles with some generic values ]]
|
||||
local function generateDefaultProfiles(db)
|
||||
defaultProfiles = {
|
||||
["Default"] = L["default"],
|
||||
[db.keys.char] = db.keys.char,
|
||||
[db.keys.realm] = db.keys.realm,
|
||||
[db.keys.class] = UnitClass("player")
|
||||
}
|
||||
end
|
||||
|
||||
--[[ create and return a handler object for the db, or upgrade it if it already existed ]]
|
||||
local function getOptionsHandler(db, noDefaultProfiles)
|
||||
if not defaultProfiles then
|
||||
generateDefaultProfiles(db)
|
||||
end
|
||||
|
||||
local handler = AceDBOptions.handlers[db] or { db = db, noDefaultProfiles = noDefaultProfiles }
|
||||
|
||||
for k,v in pairs(OptionsHandlerPrototype) do
|
||||
handler[k] = v
|
||||
end
|
||||
|
||||
AceDBOptions.handlers[db] = handler
|
||||
return handler
|
||||
end
|
||||
|
||||
--[[
|
||||
the real options table
|
||||
]]
|
||||
local optionsTable = {
|
||||
desc = {
|
||||
order = 1,
|
||||
type = "description",
|
||||
name = L["intro"] .. "\n",
|
||||
},
|
||||
descreset = {
|
||||
order = 9,
|
||||
type = "description",
|
||||
name = L["reset_desc"],
|
||||
},
|
||||
reset = {
|
||||
order = 10,
|
||||
type = "execute",
|
||||
name = L["reset"],
|
||||
desc = L["reset_sub"],
|
||||
func = "Reset",
|
||||
},
|
||||
current = {
|
||||
order = 11,
|
||||
type = "description",
|
||||
name = function(info) return L["current"] .. " " .. NORMAL_FONT_COLOR_CODE .. info.handler:GetCurrentProfile() .. FONT_COLOR_CODE_CLOSE end,
|
||||
width = "default",
|
||||
},
|
||||
choosedesc = {
|
||||
order = 20,
|
||||
type = "description",
|
||||
name = "\n" .. L["choose_desc"],
|
||||
},
|
||||
new = {
|
||||
name = L["new"],
|
||||
desc = L["new_sub"],
|
||||
type = "input",
|
||||
order = 30,
|
||||
get = false,
|
||||
set = "SetProfile",
|
||||
},
|
||||
choose = {
|
||||
name = L["choose"],
|
||||
desc = L["choose_sub"],
|
||||
type = "select",
|
||||
order = 40,
|
||||
get = "GetCurrentProfile",
|
||||
set = "SetProfile",
|
||||
values = "ListProfiles",
|
||||
arg = "common",
|
||||
},
|
||||
copydesc = {
|
||||
order = 50,
|
||||
type = "description",
|
||||
name = "\n" .. L["copy_desc"],
|
||||
},
|
||||
copyfrom = {
|
||||
order = 60,
|
||||
type = "select",
|
||||
name = L["copy"],
|
||||
desc = L["copy_desc"],
|
||||
get = false,
|
||||
set = "CopyProfile",
|
||||
values = "ListProfiles",
|
||||
disabled = "HasNoProfiles",
|
||||
arg = "nocurrent",
|
||||
},
|
||||
deldesc = {
|
||||
order = 70,
|
||||
type = "description",
|
||||
name = "\n" .. L["delete_desc"],
|
||||
},
|
||||
delete = {
|
||||
order = 80,
|
||||
type = "select",
|
||||
name = L["delete"],
|
||||
desc = L["delete_sub"],
|
||||
get = false,
|
||||
set = "DeleteProfile",
|
||||
values = "ListProfiles",
|
||||
disabled = "HasNoProfiles",
|
||||
arg = "nocurrent",
|
||||
confirm = true,
|
||||
confirmText = L["delete_confirm"],
|
||||
},
|
||||
}
|
||||
|
||||
--- Get/Create a option table that you can use in your addon to control the profiles of AceDB-3.0.
|
||||
-- @param db The database object to create the options table for.
|
||||
-- @return The options table to be used in AceConfig-3.0
|
||||
-- @usage
|
||||
-- -- Assuming `options` is your top-level options table and `self.db` is your database:
|
||||
-- options.args.profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
|
||||
function AceDBOptions:GetOptionsTable(db, noDefaultProfiles)
|
||||
local tbl = AceDBOptions.optionTables[db] or {
|
||||
type = "group",
|
||||
name = L["profiles"],
|
||||
desc = L["profiles_sub"],
|
||||
}
|
||||
|
||||
tbl.handler = getOptionsHandler(db, noDefaultProfiles)
|
||||
tbl.args = optionsTable
|
||||
|
||||
AceDBOptions.optionTables[db] = tbl
|
||||
return tbl
|
||||
end
|
||||
|
||||
-- upgrade existing tables
|
||||
for db,tbl in pairs(AceDBOptions.optionTables) do
|
||||
tbl.handler = getOptionsHandler(db)
|
||||
tbl.args = optionsTable
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceDBOptions-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,126 @@
|
||||
--- AceEvent-3.0 provides event registration and secure dispatching.
|
||||
-- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
|
||||
-- CallbackHandler, and dispatches all game events or addon message to the registrees.
|
||||
--
|
||||
-- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
|
||||
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
|
||||
-- and can be accessed directly, without having to explicitly call AceEvent itself.\\
|
||||
-- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
|
||||
-- make into AceEvent.
|
||||
-- @class file
|
||||
-- @name AceEvent-3.0
|
||||
-- @release $Id: AceEvent-3.0.lua 877 2009-11-02 15:56:50Z nevcairiel $
|
||||
local MAJOR, MINOR = "AceEvent-3.0", 3
|
||||
local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceEvent then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
local CallbackHandler = LibStub:GetLibrary("CallbackHandler-1.0")
|
||||
|
||||
AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
|
||||
AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
|
||||
|
||||
-- APIs and registry for blizzard events, using CallbackHandler lib
|
||||
if not AceEvent.events then
|
||||
AceEvent.events = CallbackHandler:New(AceEvent,
|
||||
"RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
|
||||
end
|
||||
|
||||
function AceEvent.events:OnUsed(target, eventname)
|
||||
AceEvent.frame:RegisterEvent(eventname)
|
||||
end
|
||||
|
||||
function AceEvent.events:OnUnused(target, eventname)
|
||||
AceEvent.frame:UnregisterEvent(eventname)
|
||||
end
|
||||
|
||||
|
||||
-- APIs and registry for IPC messages, using CallbackHandler lib
|
||||
if not AceEvent.messages then
|
||||
AceEvent.messages = CallbackHandler:New(AceEvent,
|
||||
"RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
|
||||
)
|
||||
AceEvent.SendMessage = AceEvent.messages.Fire
|
||||
end
|
||||
|
||||
--- embedding and embed handling
|
||||
local mixins = {
|
||||
"RegisterEvent", "UnregisterEvent",
|
||||
"RegisterMessage", "UnregisterMessage",
|
||||
"SendMessage",
|
||||
"UnregisterAllEvents", "UnregisterAllMessages",
|
||||
}
|
||||
|
||||
--- Register for a Blizzard Event.
|
||||
-- The callback will always be called with the event as the first argument, and if supplied, the `arg` as second argument.
|
||||
-- Any arguments to the event will be passed on after that.
|
||||
-- @name AceEvent:RegisterEvent
|
||||
-- @class function
|
||||
-- @paramsig event[, callback [, arg]]
|
||||
-- @param event The event to register for
|
||||
-- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
|
||||
-- @param arg An optional argument to pass to the callback function
|
||||
|
||||
--- Unregister an event.
|
||||
-- @name AceEvent:UnregisterEvent
|
||||
-- @class function
|
||||
-- @paramsig event
|
||||
-- @param event The event to unregister
|
||||
|
||||
--- Register for a custom AceEvent-internal message.
|
||||
-- The callback will always be called with the event as the first argument, and if supplied, the `arg` as second argument.
|
||||
-- Any arguments to the event will be passed on after that.
|
||||
-- @name AceEvent:RegisterMessage
|
||||
-- @class function
|
||||
-- @paramsig message[, callback [, arg]]
|
||||
-- @param message The message to register for
|
||||
-- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
|
||||
-- @param arg An optional argument to pass to the callback function
|
||||
|
||||
--- Unregister a message
|
||||
-- @name AceEvent:UnregisterMessage
|
||||
-- @class function
|
||||
-- @paramsig message
|
||||
-- @param message The message to unregister
|
||||
|
||||
--- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
|
||||
-- @name AceEvent:SendMessage
|
||||
-- @class function
|
||||
-- @paramsig message, ...
|
||||
-- @param message The message to send
|
||||
-- @param ... Any arguments to the message
|
||||
|
||||
|
||||
-- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
|
||||
-- @param target target object to embed AceEvent in
|
||||
function AceEvent:Embed(target)
|
||||
for k, v in pairs(mixins) do
|
||||
target[v] = self[v]
|
||||
end
|
||||
self.embeds[target] = true
|
||||
return target
|
||||
end
|
||||
|
||||
-- AceEvent:OnEmbedDisable( target )
|
||||
-- target (object) - target object that is being disabled
|
||||
--
|
||||
-- Unregister all events messages etc when the target disables.
|
||||
-- this method should be called by the target manually or by an addon framework
|
||||
function AceEvent:OnEmbedDisable(target)
|
||||
target:UnregisterAllEvents()
|
||||
target:UnregisterAllMessages()
|
||||
end
|
||||
|
||||
-- Script to fire blizzard events into the event listeners
|
||||
local events = AceEvent.events
|
||||
AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
|
||||
events:Fire(event, ...)
|
||||
end)
|
||||
|
||||
--- Finally: upgrade our old embeds
|
||||
for target, v in pairs(AceEvent.embeds) do
|
||||
AceEvent:Embed(target)
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceEvent-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,805 @@
|
||||
--- **AceGUI-3.0** provides access to numerous widgets which can be used to create GUIs.
|
||||
-- AceGUI is used by AceConfigDialog to create the option GUIs, but you can use it by itself
|
||||
-- to create any custom GUI. There are more extensive examples in the test suite in the Ace3
|
||||
-- stand-alone distribution.
|
||||
--
|
||||
-- **Note**: When using AceGUI-3.0 directly, please do not modify the frames of the widgets directly,
|
||||
-- as any "unknown" change to the widgets will cause addons that get your widget out of the widget pool
|
||||
-- to misbehave. If you think some part of a widget should be modifiable, please open a ticket, and we"ll
|
||||
-- implement a proper API to modify it.
|
||||
-- @usage
|
||||
-- local AceGUI = LibStub("AceGUI-3.0")
|
||||
-- -- Create a container frame
|
||||
-- local f = AceGUI:Create("Frame")
|
||||
-- f:SetCallback("OnClose",function(widget) AceGUI:Release(widget) end)
|
||||
-- f:SetTitle("AceGUI-3.0 Example")
|
||||
-- f:SetStatusText("Status Bar")
|
||||
-- f:SetLayout("Flow")
|
||||
-- -- Create a button
|
||||
-- local btn = AceGUI:Create("Button")
|
||||
-- btn:SetWidth(170)
|
||||
-- btn:SetText("Button !")
|
||||
-- btn:SetCallback("OnClick", function() print("Click!") end)
|
||||
-- -- Add the button to the container
|
||||
-- f:AddChild(btn)
|
||||
-- @class file
|
||||
-- @name AceGUI-3.0
|
||||
-- @release $Id: AceGUI-3.0.lua 924 2010-05-13 15:12:20Z nevcairiel $
|
||||
local ACEGUI_MAJOR, ACEGUI_MINOR = "AceGUI-3.0", 33
|
||||
local AceGUI, oldminor = LibStub:NewLibrary(ACEGUI_MAJOR, ACEGUI_MINOR)
|
||||
|
||||
if not AceGUI then return end -- No upgrade needed
|
||||
|
||||
-- Lua APIs
|
||||
local tconcat, tremove, tinsert = table.concat, table.remove, table.insert
|
||||
local select, pairs, next, type = select, pairs, next, type
|
||||
local error, assert, loadstring = error, assert, loadstring
|
||||
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
|
||||
local math_max = math.max
|
||||
|
||||
-- WoW APIs
|
||||
local UIParent = UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: geterrorhandler, LibStub
|
||||
|
||||
--local con = LibStub("AceConsole-3.0",true)
|
||||
|
||||
AceGUI.WidgetRegistry = AceGUI.WidgetRegistry or {}
|
||||
AceGUI.LayoutRegistry = AceGUI.LayoutRegistry or {}
|
||||
AceGUI.WidgetBase = AceGUI.WidgetBase or {}
|
||||
AceGUI.WidgetContainerBase = AceGUI.WidgetContainerBase or {}
|
||||
AceGUI.WidgetVersions = AceGUI.WidgetVersions or {}
|
||||
|
||||
-- local upvalues
|
||||
local WidgetRegistry = AceGUI.WidgetRegistry
|
||||
local LayoutRegistry = AceGUI.LayoutRegistry
|
||||
local WidgetVersions = AceGUI.WidgetVersions
|
||||
|
||||
--[[
|
||||
xpcall safecall implementation
|
||||
]]
|
||||
local xpcall = xpcall
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
|
||||
local function CreateDispatcher(argCount)
|
||||
local code = [[
|
||||
local xpcall, eh = ...
|
||||
local method, ARGS
|
||||
local function call() return method(ARGS) end
|
||||
|
||||
local function dispatch(func, ...)
|
||||
method = func
|
||||
if not method then return end
|
||||
ARGS = ...
|
||||
return xpcall(call, eh)
|
||||
end
|
||||
|
||||
return dispatch
|
||||
]]
|
||||
|
||||
local ARGS = {}
|
||||
for i = 1, argCount do ARGS[i] = "arg"..i end
|
||||
code = code:gsub("ARGS", tconcat(ARGS, ", "))
|
||||
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
|
||||
end
|
||||
|
||||
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
|
||||
local dispatcher = CreateDispatcher(argCount)
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end})
|
||||
Dispatchers[0] = function(func)
|
||||
return xpcall(func, errorhandler)
|
||||
end
|
||||
|
||||
local function safecall(func, ...)
|
||||
return Dispatchers[select("#", ...)](func, ...)
|
||||
end
|
||||
|
||||
-- Recycling functions
|
||||
local newWidget, delWidget
|
||||
do
|
||||
-- Version Upgrade in Minor 29
|
||||
-- Internal Storage of the objects changed, from an array table
|
||||
-- to a hash table, and additionally we introduced versioning on
|
||||
-- the widgets which would discard all widgets from a pre-29 version
|
||||
-- anyway, so we just clear the storage now, and don't try to
|
||||
-- convert the storage tables to the new format.
|
||||
-- This should generally not cause *many* widgets to end up in trash,
|
||||
-- since once dialogs are opened, all addons should be loaded already
|
||||
-- and AceGUI should be on the latest version available on the users
|
||||
-- setup.
|
||||
-- -- nevcairiel - Nov 2nd, 2009
|
||||
if oldminor and oldminor < 29 and AceGUI.objPools then
|
||||
AceGUI.objPools = nil
|
||||
end
|
||||
|
||||
AceGUI.objPools = AceGUI.objPools or {}
|
||||
local objPools = AceGUI.objPools
|
||||
--Returns a new instance, if none are available either returns a new table or calls the given contructor
|
||||
function newWidget(type)
|
||||
if not WidgetRegistry[type] then
|
||||
error("Attempt to instantiate unknown widget type", 2)
|
||||
end
|
||||
|
||||
if not objPools[type] then
|
||||
objPools[type] = {}
|
||||
end
|
||||
|
||||
local newObj = next(objPools[type])
|
||||
if not newObj then
|
||||
newObj = WidgetRegistry[type]()
|
||||
newObj.AceGUIWidgetVersion = WidgetVersions[type]
|
||||
else
|
||||
objPools[type][newObj] = nil
|
||||
-- if the widget is older then the latest, don't even try to reuse it
|
||||
-- just forget about it, and grab a new one.
|
||||
if not newObj.AceGUIWidgetVersion or newObj.AceGUIWidgetVersion < WidgetVersions[type] then
|
||||
return newWidget(type)
|
||||
end
|
||||
end
|
||||
return newObj
|
||||
end
|
||||
-- Releases an instance to the Pool
|
||||
function delWidget(obj,type)
|
||||
if not objPools[type] then
|
||||
objPools[type] = {}
|
||||
end
|
||||
if objPools[type][obj] then
|
||||
error("Attempt to Release Widget that is already released", 2)
|
||||
end
|
||||
objPools[type][obj] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-------------------
|
||||
-- API Functions --
|
||||
-------------------
|
||||
|
||||
-- Gets a widget Object
|
||||
|
||||
--- Create a new Widget of the given type.
|
||||
-- This function will instantiate a new widget (or use one from the widget pool), and call the
|
||||
-- OnAcquire function on it, before returning.
|
||||
-- @param type The type of the widget.
|
||||
-- @return The newly created widget.
|
||||
function AceGUI:Create(type)
|
||||
if WidgetRegistry[type] then
|
||||
local widget = newWidget(type)
|
||||
|
||||
if rawget(widget, "Acquire") then
|
||||
widget.OnAcquire = widget.Acquire
|
||||
widget.Acquire = nil
|
||||
elseif rawget(widget, "Aquire") then
|
||||
widget.OnAcquire = widget.Aquire
|
||||
widget.Aquire = nil
|
||||
end
|
||||
|
||||
if rawget(widget, "Release") then
|
||||
widget.OnRelease = rawget(widget, "Release")
|
||||
widget.Release = nil
|
||||
end
|
||||
|
||||
if widget.OnAcquire then
|
||||
widget:OnAcquire()
|
||||
else
|
||||
error(("Widget type %s doesn't supply an OnAcquire Function"):format(type))
|
||||
end
|
||||
-- Set the default Layout ("List")
|
||||
safecall(widget.SetLayout, widget, "List")
|
||||
safecall(widget.ResumeLayout, widget)
|
||||
return widget
|
||||
end
|
||||
end
|
||||
|
||||
--- Releases a widget Object.
|
||||
-- This function calls OnRelease on the widget and places it back in the widget pool.
|
||||
-- Any data on the widget is being erased, and the widget will be hidden.\\
|
||||
-- If this widget is a Container-Widget, all of its Child-Widgets will be releases as well.
|
||||
-- @param widget The widget to release
|
||||
function AceGUI:Release(widget)
|
||||
safecall(widget.PauseLayout, widget)
|
||||
widget:Fire("OnRelease")
|
||||
safecall(widget.ReleaseChildren, widget)
|
||||
|
||||
if widget.OnRelease then
|
||||
widget:OnRelease()
|
||||
-- else
|
||||
-- error(("Widget type %s doesn't supply an OnRelease Function"):format(widget.type))
|
||||
end
|
||||
for k in pairs(widget.userdata) do
|
||||
widget.userdata[k] = nil
|
||||
end
|
||||
for k in pairs(widget.events) do
|
||||
widget.events[k] = nil
|
||||
end
|
||||
widget.width = nil
|
||||
widget.relWidth = nil
|
||||
widget.height = nil
|
||||
widget.relHeight = nil
|
||||
widget.noAutoHeight = nil
|
||||
widget.frame:ClearAllPoints()
|
||||
widget.frame:Hide()
|
||||
widget.frame:SetParent(UIParent)
|
||||
widget.frame.width = nil
|
||||
widget.frame.height = nil
|
||||
if widget.content then
|
||||
widget.content.width = nil
|
||||
widget.content.height = nil
|
||||
end
|
||||
delWidget(widget, widget.type)
|
||||
end
|
||||
|
||||
-----------
|
||||
-- Focus --
|
||||
-----------
|
||||
|
||||
|
||||
--- Called when a widget has taken focus.
|
||||
-- e.g. Dropdowns opening, Editboxes gaining kb focus
|
||||
-- @param widget The widget that should be focused
|
||||
function AceGUI:SetFocus(widget)
|
||||
if self.FocusedWidget and self.FocusedWidget ~= widget then
|
||||
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
|
||||
end
|
||||
self.FocusedWidget = widget
|
||||
end
|
||||
|
||||
|
||||
--- Called when something has happened that could cause widgets with focus to drop it
|
||||
-- e.g. titlebar of a frame being clicked
|
||||
function AceGUI:ClearFocus()
|
||||
if self.FocusedWidget then
|
||||
safecall(self.FocusedWidget.ClearFocus, self.FocusedWidget)
|
||||
self.FocusedWidget = nil
|
||||
end
|
||||
end
|
||||
|
||||
-------------
|
||||
-- Widgets --
|
||||
-------------
|
||||
--[[
|
||||
Widgets must provide the following functions
|
||||
OnAcquire() - Called when the object is acquired, should set everything to a default hidden state
|
||||
|
||||
And the following members
|
||||
frame - the frame or derivitive object that will be treated as the widget for size and anchoring purposes
|
||||
type - the type of the object, same as the name given to :RegisterWidget()
|
||||
|
||||
Widgets contain a table called userdata, this is a safe place to store data associated with the wigdet
|
||||
It will be cleared automatically when a widget is released
|
||||
Placing values directly into a widget object should be avoided
|
||||
|
||||
If the Widget can act as a container for other Widgets the following
|
||||
content - frame or derivitive that children will be anchored to
|
||||
|
||||
The Widget can supply the following Optional Members
|
||||
:OnRelease() - Called when the object is Released, should remove any additional anchors and clear any data
|
||||
:OnWidthSet(width) - Called when the width of the widget is changed
|
||||
:OnHeightSet(height) - Called when the height of the widget is changed
|
||||
Widgets should not use the OnSizeChanged events of thier frame or content members, use these methods instead
|
||||
AceGUI already sets a handler to the event
|
||||
:LayoutFinished(width, height) - called after a layout has finished, the width and height will be the width and height of the
|
||||
area used for controls. These can be nil if the layout used the existing size to layout the controls.
|
||||
|
||||
]]
|
||||
|
||||
--------------------------
|
||||
-- Widget Base Template --
|
||||
--------------------------
|
||||
do
|
||||
local WidgetBase = AceGUI.WidgetBase
|
||||
|
||||
WidgetBase.SetParent = function(self, parent)
|
||||
local frame = self.frame
|
||||
frame:SetParent(nil)
|
||||
frame:SetParent(parent.content)
|
||||
self.parent = parent
|
||||
end
|
||||
|
||||
WidgetBase.SetCallback = function(self, name, func)
|
||||
if type(func) == "function" then
|
||||
self.events[name] = func
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.Fire = function(self, name, ...)
|
||||
if self.events[name] then
|
||||
local success, ret = safecall(self.events[name], self, name, ...)
|
||||
if success then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.SetWidth = function(self, width)
|
||||
self.frame:SetWidth(width)
|
||||
self.frame.width = width
|
||||
if self.OnWidthSet then
|
||||
self:OnWidthSet(width)
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.SetRelativeWidth = function(self, width)
|
||||
if width <= 0 or width > 1 then
|
||||
error(":SetRelativeWidth(width): Invalid relative width.", 2)
|
||||
end
|
||||
self.relWidth = width
|
||||
self.width = "relative"
|
||||
end
|
||||
|
||||
WidgetBase.SetHeight = function(self, height)
|
||||
self.frame:SetHeight(height)
|
||||
self.frame.height = height
|
||||
if self.OnHeightSet then
|
||||
self:OnHeightSet(height)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ WidgetBase.SetRelativeHeight = function(self, height)
|
||||
if height <= 0 or height > 1 then
|
||||
error(":SetRelativeHeight(height): Invalid relative height.", 2)
|
||||
end
|
||||
self.relHeight = height
|
||||
self.height = "relative"
|
||||
end ]]
|
||||
|
||||
WidgetBase.IsVisible = function(self)
|
||||
return self.frame:IsVisible()
|
||||
end
|
||||
|
||||
WidgetBase.IsShown= function(self)
|
||||
return self.frame:IsShown()
|
||||
end
|
||||
|
||||
WidgetBase.Release = function(self)
|
||||
AceGUI:Release(self)
|
||||
end
|
||||
|
||||
WidgetBase.SetPoint = function(self, ...)
|
||||
return self.frame:SetPoint(...)
|
||||
end
|
||||
|
||||
WidgetBase.ClearAllPoints = function(self)
|
||||
return self.frame:ClearAllPoints()
|
||||
end
|
||||
|
||||
WidgetBase.GetNumPoints = function(self)
|
||||
return self.frame:GetNumPoints()
|
||||
end
|
||||
|
||||
WidgetBase.GetPoint = function(self, ...)
|
||||
return self.frame:GetPoint(...)
|
||||
end
|
||||
|
||||
WidgetBase.GetUserDataTable = function(self)
|
||||
return self.userdata
|
||||
end
|
||||
|
||||
WidgetBase.SetUserData = function(self, key, value)
|
||||
self.userdata[key] = value
|
||||
end
|
||||
|
||||
WidgetBase.GetUserData = function(self, key)
|
||||
return self.userdata[key]
|
||||
end
|
||||
|
||||
WidgetBase.IsFullHeight = function(self)
|
||||
return self.height == "fill"
|
||||
end
|
||||
|
||||
WidgetBase.SetFullHeight = function(self, isFull)
|
||||
if isFull then
|
||||
self.height = "fill"
|
||||
else
|
||||
self.height = nil
|
||||
end
|
||||
end
|
||||
|
||||
WidgetBase.IsFullWidth = function(self)
|
||||
return self.width == "fill"
|
||||
end
|
||||
|
||||
WidgetBase.SetFullWidth = function(self, isFull)
|
||||
if isFull then
|
||||
self.width = "fill"
|
||||
else
|
||||
self.width = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- local function LayoutOnUpdate(this)
|
||||
-- this:SetScript("OnUpdate",nil)
|
||||
-- this.obj:PerformLayout()
|
||||
-- end
|
||||
|
||||
local WidgetContainerBase = AceGUI.WidgetContainerBase
|
||||
|
||||
WidgetContainerBase.PauseLayout = function(self)
|
||||
self.LayoutPaused = true
|
||||
end
|
||||
|
||||
WidgetContainerBase.ResumeLayout = function(self)
|
||||
self.LayoutPaused = nil
|
||||
end
|
||||
|
||||
WidgetContainerBase.PerformLayout = function(self)
|
||||
if self.LayoutPaused then
|
||||
return
|
||||
end
|
||||
safecall(self.LayoutFunc, self.content, self.children)
|
||||
end
|
||||
|
||||
--call this function to layout, makes sure layed out objects get a frame to get sizes etc
|
||||
WidgetContainerBase.DoLayout = function(self)
|
||||
self:PerformLayout()
|
||||
-- if not self.parent then
|
||||
-- self.frame:SetScript("OnUpdate", LayoutOnUpdate)
|
||||
-- end
|
||||
end
|
||||
|
||||
WidgetContainerBase.AddChild = function(self, child, beforeWidget)
|
||||
if beforeWidget then
|
||||
local siblingIndex = 1
|
||||
for _, widget in pairs(self.children) do
|
||||
if widget == beforeWidget then
|
||||
break
|
||||
end
|
||||
siblingIndex = siblingIndex + 1
|
||||
end
|
||||
tinsert(self.children, siblingIndex, child)
|
||||
else
|
||||
tinsert(self.children, child)
|
||||
end
|
||||
child:SetParent(self)
|
||||
child.frame:Show()
|
||||
self:DoLayout()
|
||||
end
|
||||
|
||||
WidgetContainerBase.AddChildren = function(self, ...)
|
||||
for i = 1, select("#", ...) do
|
||||
local child = select(i, ...)
|
||||
tinsert(self.children, child)
|
||||
child:SetParent(self)
|
||||
child.frame:Show()
|
||||
end
|
||||
self:DoLayout()
|
||||
end
|
||||
|
||||
WidgetContainerBase.ReleaseChildren = function(self)
|
||||
local children = self.children
|
||||
for i = 1,#children do
|
||||
AceGUI:Release(children[i])
|
||||
children[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
WidgetContainerBase.SetLayout = function(self, Layout)
|
||||
self.LayoutFunc = AceGUI:GetLayout(Layout)
|
||||
end
|
||||
|
||||
WidgetContainerBase.SetAutoAdjustHeight = function(self, adjust)
|
||||
if adjust then
|
||||
self.noAutoHeight = nil
|
||||
else
|
||||
self.noAutoHeight = true
|
||||
end
|
||||
end
|
||||
|
||||
local function FrameResize(this)
|
||||
local self = this.obj
|
||||
if this:GetWidth() and this:GetHeight() then
|
||||
if self.OnWidthSet then
|
||||
self:OnWidthSet(this:GetWidth())
|
||||
end
|
||||
if self.OnHeightSet then
|
||||
self:OnHeightSet(this:GetHeight())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ContentResize(this)
|
||||
if this:GetWidth() and this:GetHeight() then
|
||||
this.width = this:GetWidth()
|
||||
this.height = this:GetHeight()
|
||||
this.obj:DoLayout()
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(WidgetContainerBase, {__index=WidgetBase})
|
||||
|
||||
--One of these function should be called on each Widget Instance as part of its creation process
|
||||
|
||||
--- Register a widget-class as a container for newly created widgets.
|
||||
-- @param widget The widget class
|
||||
function AceGUI:RegisterAsContainer(widget)
|
||||
widget.children = {}
|
||||
widget.userdata = {}
|
||||
widget.events = {}
|
||||
widget.base = WidgetContainerBase
|
||||
widget.content.obj = widget
|
||||
widget.frame.obj = widget
|
||||
widget.content:SetScript("OnSizeChanged", ContentResize)
|
||||
widget.frame:SetScript("OnSizeChanged", FrameResize)
|
||||
setmetatable(widget, {__index = WidgetContainerBase})
|
||||
widget:SetLayout("List")
|
||||
return widget
|
||||
end
|
||||
|
||||
--- Register a widget-class as a widget.
|
||||
-- @param widget The widget class
|
||||
function AceGUI:RegisterAsWidget(widget)
|
||||
widget.userdata = {}
|
||||
widget.events = {}
|
||||
widget.base = WidgetBase
|
||||
widget.frame.obj = widget
|
||||
widget.frame:SetScript("OnSizeChanged", FrameResize)
|
||||
setmetatable(widget, {__index = WidgetBase})
|
||||
return widget
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
-- Widget API --
|
||||
------------------
|
||||
|
||||
--- Registers a widget Constructor, this function returns a new instance of the Widget
|
||||
-- @param Name The name of the widget
|
||||
-- @param Constructor The widget constructor function
|
||||
-- @param Version The version of the widget
|
||||
function AceGUI:RegisterWidgetType(Name, Constructor, Version)
|
||||
assert(type(Constructor) == "function")
|
||||
assert(type(Version) == "number")
|
||||
|
||||
local oldVersion = WidgetVersions[Name]
|
||||
if oldVersion and oldVersion >= Version then return end
|
||||
|
||||
WidgetVersions[Name] = Version
|
||||
WidgetRegistry[Name] = Constructor
|
||||
end
|
||||
|
||||
--- Registers a Layout Function
|
||||
-- @param Name The name of the layout
|
||||
-- @param LayoutFunc Reference to the layout function
|
||||
function AceGUI:RegisterLayout(Name, LayoutFunc)
|
||||
assert(type(LayoutFunc) == "function")
|
||||
if type(Name) == "string" then
|
||||
Name = Name:upper()
|
||||
end
|
||||
LayoutRegistry[Name] = LayoutFunc
|
||||
end
|
||||
|
||||
--- Get a Layout Function from the registry
|
||||
-- @param Name The name of the layout
|
||||
function AceGUI:GetLayout(Name)
|
||||
if type(Name) == "string" then
|
||||
Name = Name:upper()
|
||||
end
|
||||
return LayoutRegistry[Name]
|
||||
end
|
||||
|
||||
AceGUI.counts = AceGUI.counts or {}
|
||||
|
||||
--- A type-based counter to count the number of widgets created.
|
||||
-- This is used by widgets that require a named frame, e.g. when a Blizzard
|
||||
-- Template requires it.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetNextWidgetNum(type)
|
||||
if not self.counts[type] then
|
||||
self.counts[type] = 0
|
||||
end
|
||||
self.counts[type] = self.counts[type] + 1
|
||||
return self.counts[type]
|
||||
end
|
||||
|
||||
--- Return the number of created widgets for this type.
|
||||
-- In contrast to GetNextWidgetNum, the number is not incremented.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetWidgetCount(type)
|
||||
return self.counts[type] or 0
|
||||
end
|
||||
|
||||
--- Return the version of the currently registered widget type.
|
||||
-- @param type The widget type
|
||||
function AceGUI:GetWidgetVersion(type)
|
||||
return WidgetVersions[type]
|
||||
end
|
||||
|
||||
-------------
|
||||
-- Layouts --
|
||||
-------------
|
||||
|
||||
--[[
|
||||
A Layout is a func that takes 2 parameters
|
||||
content - the frame that widgets will be placed inside
|
||||
children - a table containing the widgets to layout
|
||||
]]
|
||||
|
||||
-- Very simple Layout, Children are stacked on top of each other down the left side
|
||||
AceGUI:RegisterLayout("List",
|
||||
function(content, children)
|
||||
local height = 0
|
||||
local width = content.width or content:GetWidth() or 0
|
||||
for i = 1, #children do
|
||||
local child = children[i]
|
||||
|
||||
local frame = child.frame
|
||||
frame:ClearAllPoints()
|
||||
frame:Show()
|
||||
if i == 1 then
|
||||
frame:SetPoint("TOPLEFT", content)
|
||||
else
|
||||
frame:SetPoint("TOPLEFT", children[i-1].frame, "BOTTOMLEFT")
|
||||
end
|
||||
|
||||
if child.width == "fill" then
|
||||
child:SetWidth(width)
|
||||
frame:SetPoint("RIGHT", content)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
elseif child.width == "relative" then
|
||||
child:SetWidth(width * child.relWidth)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
end
|
||||
|
||||
height = height + (frame.height or frame:GetHeight() or 0)
|
||||
end
|
||||
safecall(content.obj.LayoutFinished, content.obj, nil, height)
|
||||
end)
|
||||
|
||||
-- A single control fills the whole content area
|
||||
AceGUI:RegisterLayout("Fill",
|
||||
function(content, children)
|
||||
if children[1] then
|
||||
children[1]:SetWidth(content:GetWidth() or 0)
|
||||
children[1]:SetHeight(content:GetHeight() or 0)
|
||||
children[1].frame:SetAllPoints(content)
|
||||
children[1].frame:Show()
|
||||
safecall(content.obj.LayoutFinished, content.obj, nil, children[1].frame:GetHeight())
|
||||
end
|
||||
end)
|
||||
|
||||
AceGUI:RegisterLayout("Flow",
|
||||
function(content, children)
|
||||
--used height so far
|
||||
local height = 0
|
||||
--width used in the current row
|
||||
local usedwidth = 0
|
||||
--height of the current row
|
||||
local rowheight = 0
|
||||
local rowoffset = 0
|
||||
local lastrowoffset
|
||||
|
||||
local width = content.width or content:GetWidth() or 0
|
||||
|
||||
--control at the start of the row
|
||||
local rowstart
|
||||
local rowstartoffset
|
||||
local lastrowstart
|
||||
local isfullheight
|
||||
|
||||
local frameoffset
|
||||
local lastframeoffset
|
||||
local oversize
|
||||
for i = 1, #children do
|
||||
local child = children[i]
|
||||
oversize = nil
|
||||
local frame = child.frame
|
||||
local frameheight = frame.height or frame:GetHeight() or 0
|
||||
local framewidth = frame.width or frame:GetWidth() or 0
|
||||
lastframeoffset = frameoffset
|
||||
-- HACK: Why did we set a frameoffset of (frameheight / 2) ?
|
||||
-- That was moving all widgets half the widgets size down, is that intended?
|
||||
-- Actually, it seems to be neccessary for many cases, we'll leave it in for now.
|
||||
-- If widgets seem to anchor weirdly with this, provide a valid alignoffset for them.
|
||||
-- TODO: Investigate moar!
|
||||
frameoffset = child.alignoffset or (frameheight / 2)
|
||||
|
||||
if child.width == "relative" then
|
||||
framewidth = width * child.relWidth
|
||||
end
|
||||
|
||||
frame:Show()
|
||||
frame:ClearAllPoints()
|
||||
if i == 1 then
|
||||
-- anchor the first control to the top left
|
||||
frame:SetPoint("TOPLEFT", content)
|
||||
rowheight = frameheight
|
||||
rowoffset = frameoffset
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
usedwidth = framewidth
|
||||
if usedwidth > width then
|
||||
oversize = true
|
||||
end
|
||||
else
|
||||
-- if there isn't available width for the control start a new row
|
||||
-- if a control is "fill" it will be on a row of its own full width
|
||||
if usedwidth == 0 or ((framewidth) + usedwidth > width) or child.width == "fill" then
|
||||
if isfullheight then
|
||||
-- a previous row has already filled the entire height, there's nothing we can usefully do anymore
|
||||
-- (maybe error/warn about this?)
|
||||
break
|
||||
end
|
||||
--anchor the previous row, we will now know its height and offset
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
|
||||
height = height + rowheight + 3
|
||||
--save this as the rowstart so we can anchor it after the row is complete and we have the max height and offset of controls in it
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
rowheight = frameheight
|
||||
rowoffset = frameoffset
|
||||
usedwidth = framewidth
|
||||
if usedwidth > width then
|
||||
oversize = true
|
||||
end
|
||||
-- put the control on the current row, adding it to the width and checking if the height needs to be increased
|
||||
else
|
||||
--handles cases where the new height is higher than either control because of the offsets
|
||||
--math.max(rowheight-rowoffset+frameoffset, frameheight-frameoffset+rowoffset)
|
||||
|
||||
--offset is always the larger of the two offsets
|
||||
rowoffset = math_max(rowoffset, frameoffset)
|
||||
rowheight = math_max(rowheight, rowoffset + (frameheight / 2))
|
||||
|
||||
frame:SetPoint("TOPLEFT", children[i-1].frame, "TOPRIGHT", 0, frameoffset - lastframeoffset)
|
||||
usedwidth = framewidth + usedwidth
|
||||
end
|
||||
end
|
||||
|
||||
if child.width == "fill" then
|
||||
child:SetWidth(width)
|
||||
frame:SetPoint("RIGHT", content)
|
||||
|
||||
usedwidth = 0
|
||||
rowstart = frame
|
||||
rowstartoffset = frameoffset
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
rowheight = frame.height or frame:GetHeight() or 0
|
||||
rowoffset = child.alignoffset or (rowheight / 2)
|
||||
rowstartoffset = rowoffset
|
||||
elseif child.width == "relative" then
|
||||
child:SetWidth(width * child.relWidth)
|
||||
|
||||
if child.DoLayout then
|
||||
child:DoLayout()
|
||||
end
|
||||
elseif oversize then
|
||||
if width > 1 then
|
||||
frame:SetPoint("RIGHT", content)
|
||||
end
|
||||
end
|
||||
|
||||
if child.height == "fill" then
|
||||
frame:SetPoint("BOTTOM", content)
|
||||
isfullheight = true
|
||||
end
|
||||
end
|
||||
|
||||
--anchor the last row, if its full height needs a special case since its height has just been changed by the anchor
|
||||
if isfullheight then
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -height)
|
||||
elseif rowstart then
|
||||
rowstart:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -(height + (rowoffset - rowstartoffset) + 3))
|
||||
end
|
||||
|
||||
height = height + rowheight + 3
|
||||
safecall(content.obj.LayoutFinished, content.obj, nil, height)
|
||||
end)
|
||||
@@ -0,0 +1,28 @@
|
||||
<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">
|
||||
<Script file="AceGUI-3.0.lua"/>
|
||||
<!-- Container -->
|
||||
<Script file="widgets\AceGUIContainer-BlizOptionsGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-DropDownGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-Frame.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-InlineGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-ScrollFrame.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-SimpleGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-TabGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-TreeGroup.lua"/>
|
||||
<Script file="widgets\AceGUIContainer-Window.lua"/>
|
||||
<!-- Widgets -->
|
||||
<Script file="widgets\AceGUIWidget-Button.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-CheckBox.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-ColorPicker.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-DropDown.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-DropDown-Items.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-EditBox.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-Heading.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-Icon.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-InteractiveLabel.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-Keybinding.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-Label.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-MultiLineEditBox.lua"/>
|
||||
<Script file="widgets\AceGUIWidget-Slider.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,133 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
BlizOptionsGroup Container
|
||||
Simple container widget for the integration of AceGUI into the Blizzard Interface Options
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "BlizOptionsGroup", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function OnShow(frame)
|
||||
frame.obj:Fire("OnShow")
|
||||
end
|
||||
|
||||
local function OnHide(frame)
|
||||
frame.obj:Fire("OnHide")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function okay(frame)
|
||||
frame.obj:Fire("okay")
|
||||
end
|
||||
|
||||
local function cancel(frame)
|
||||
frame.obj:Fire("cancel")
|
||||
end
|
||||
|
||||
local function defaults(frame)
|
||||
frame.obj:Fire("defaults")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetName()
|
||||
self:SetTitle()
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 63
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 26
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetName"] = function(self, name, parent)
|
||||
self.frame.name = name
|
||||
self.frame.parent = parent
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
local content = self.content
|
||||
content:ClearAllPoints()
|
||||
if not title or title == "" then
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
self.label:SetText("")
|
||||
else
|
||||
content:SetPoint("TOPLEFT", 10, -40)
|
||||
self.label:SetText(title)
|
||||
end
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:Hide()
|
||||
|
||||
-- support functions for the Blizzard Interface Options
|
||||
frame.okay = okay
|
||||
frame.cancel = cancel
|
||||
frame.defaults = defaults
|
||||
|
||||
frame:SetScript("OnHide", OnHide)
|
||||
frame:SetScript("OnShow", OnShow)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
||||
label:SetPoint("TOPLEFT", 10, -15)
|
||||
label:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", 10, -45)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetJustifyV("TOP")
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
frame = frame,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,157 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
DropdownGroup Container
|
||||
Container controlled by a dropdown on the top.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "DropdownGroup", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local assert, pairs, type = assert, pairs, type
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function SelectedGroup(self, event, value)
|
||||
local group = self.parentgroup
|
||||
local status = group.status or group.localstatus
|
||||
status.selected = value
|
||||
self.parentgroup:Fire("OnGroupSelected", value)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.dropdown:SetText("")
|
||||
self:SetDropdownWidth(200)
|
||||
self:SetTitle("")
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.dropdown.list = nil
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
self.titletext:SetText(title)
|
||||
self.dropdown.frame:ClearAllPoints()
|
||||
if title and title ~= "" then
|
||||
self.dropdown.frame:SetPoint("TOPRIGHT", -2, 0)
|
||||
else
|
||||
self.dropdown.frame:SetPoint("TOPLEFT", -1, 0)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetGroupList"] = function(self,list)
|
||||
self.dropdown:SetList(list)
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
end,
|
||||
|
||||
["SetGroup"] = function(self,group)
|
||||
self.dropdown:SetValue(group)
|
||||
local status = self.status or self.localstatus
|
||||
status.selected = group
|
||||
self:Fire("OnGroupSelected", group)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 26
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 63
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
self:SetHeight((height or 0) + 63)
|
||||
end,
|
||||
|
||||
["SetDropdownWidth"] = function(self, width)
|
||||
self.dropdown:SetWidth(width)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame")
|
||||
frame:SetHeight(100)
|
||||
frame:SetWidth(100)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 4, -5)
|
||||
titletext:SetPoint("TOPRIGHT", -4, -5)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
|
||||
local dropdown = AceGUI:Create("Dropdown")
|
||||
dropdown.frame:SetParent(frame)
|
||||
dropdown.frame:SetFrameLevel(dropdown.frame:GetFrameLevel() + 2)
|
||||
dropdown:SetCallback("OnValueChanged", SelectedGroup)
|
||||
dropdown.frame:SetPoint("TOPLEFT", -1, 0)
|
||||
dropdown.frame:Show()
|
||||
dropdown:SetLabel("")
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 0, -26)
|
||||
border:SetPoint("BOTTOMRIGHT", 0, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1,0.1,0.1,0.5)
|
||||
border:SetBackdropBorderColor(0.4,0.4,0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
localstatus = {},
|
||||
titletext = titletext,
|
||||
dropdown = dropdown,
|
||||
border = border,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
dropdown.parentgroup = widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,298 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Frame Container
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Frame", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
local wipe = table.wipe
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: CLOSE
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Button_OnClick(frame)
|
||||
PlaySound("gsTitleOptionExit")
|
||||
frame.obj:Hide()
|
||||
end
|
||||
|
||||
local function Frame_OnClose(frame)
|
||||
frame.obj:Fire("OnClose")
|
||||
end
|
||||
|
||||
local function Frame_OnMouseDown(frame)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Title_OnMouseDown(frame)
|
||||
frame:GetParent():StartMoving()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function MoverSizer_OnMouseUp(mover)
|
||||
local frame = mover:GetParent()
|
||||
frame:StopMovingOrSizing()
|
||||
local self = frame.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.width = frame:GetWidth()
|
||||
status.height = frame:GetHeight()
|
||||
status.top = frame:GetTop()
|
||||
status.left = frame:GetLeft()
|
||||
end
|
||||
|
||||
local function SizerSE_OnMouseDown(frame)
|
||||
frame:GetParent():StartSizing("BOTTOMRIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function SizerS_OnMouseDown(frame)
|
||||
frame:GetParent():StartSizing("BOTTOM")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function SizerE_OnMouseDown(frame)
|
||||
frame:GetParent():StartSizing("RIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function StatusBar_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnterStatusBar")
|
||||
end
|
||||
|
||||
local function StatusBar_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeaveStatusBar")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self:SetTitle()
|
||||
self:SetStatusText()
|
||||
self:ApplyStatus()
|
||||
self:Show()
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
wipe(self.localstatus)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 34
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 57
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, title)
|
||||
self.titletext:SetText(title)
|
||||
end,
|
||||
|
||||
["SetStatusText"] = function(self, text)
|
||||
self.statustext:SetText(text)
|
||||
end,
|
||||
|
||||
["Hide"] = function(self)
|
||||
self.frame:Hide()
|
||||
end,
|
||||
|
||||
["Show"] = function(self)
|
||||
self.frame:Show()
|
||||
end,
|
||||
|
||||
-- called to set an external table to store status in
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
self:ApplyStatus()
|
||||
end,
|
||||
|
||||
["ApplyStatus"] = function(self)
|
||||
local status = self.status or self.localstatus
|
||||
local frame = self.frame
|
||||
self:SetWidth(status.width or 700)
|
||||
self:SetHeight(status.height or 500)
|
||||
frame:ClearAllPoints()
|
||||
if status.top and status.left then
|
||||
frame:SetPoint("TOP", UIParent, "BOTTOM", 0, status.top)
|
||||
frame:SetPoint("LEFT", UIParent, "LEFT", status.left, 0)
|
||||
else
|
||||
frame:SetPoint("CENTER")
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local FrameBackdrop = {
|
||||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
tile = true, tileSize = 32, edgeSize = 32,
|
||||
insets = { left = 8, right = 8, top = 8, bottom = 8 }
|
||||
}
|
||||
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetMovable(true)
|
||||
frame:SetResizable(true)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetBackdrop(FrameBackdrop)
|
||||
frame:SetBackdropColor(0, 0, 0, 1)
|
||||
frame:SetMinResize(400, 200)
|
||||
frame:SetToplevel(true)
|
||||
frame:SetScript("OnHide", Frame_OnClose)
|
||||
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
|
||||
|
||||
local closebutton = CreateFrame("Button", nil, frame, "UIPanelButtonTemplate")
|
||||
closebutton:SetScript("OnClick", Button_OnClick)
|
||||
closebutton:SetPoint("BOTTOMRIGHT", -27, 17)
|
||||
closebutton:SetHeight(20)
|
||||
closebutton:SetWidth(100)
|
||||
closebutton:SetText(CLOSE)
|
||||
|
||||
local statusbg = CreateFrame("Button", nil, frame)
|
||||
statusbg:SetPoint("BOTTOMLEFT", 15, 15)
|
||||
statusbg:SetPoint("BOTTOMRIGHT", -132, 15)
|
||||
statusbg:SetHeight(24)
|
||||
statusbg:SetBackdrop(PaneBackdrop)
|
||||
statusbg:SetBackdropColor(0.1,0.1,0.1)
|
||||
statusbg:SetBackdropBorderColor(0.4,0.4,0.4)
|
||||
statusbg:SetScript("OnEnter", StatusBar_OnEnter)
|
||||
statusbg:SetScript("OnLeave", StatusBar_OnLeave)
|
||||
|
||||
local statustext = statusbg:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
statustext:SetPoint("TOPLEFT", 7, -2)
|
||||
statustext:SetPoint("BOTTOMRIGHT", -7, 2)
|
||||
statustext:SetHeight(20)
|
||||
statustext:SetJustifyH("LEFT")
|
||||
statustext:SetText("")
|
||||
|
||||
local titlebg = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg:SetTexCoord(0.31, 0.67, 0, 0.63)
|
||||
titlebg:SetPoint("TOP", 0, 12)
|
||||
titlebg:SetWidth(100)
|
||||
titlebg:SetHeight(40)
|
||||
|
||||
local title = CreateFrame("Frame", nil, frame)
|
||||
title:EnableMouse(true)
|
||||
title:SetScript("OnMouseDown", Title_OnMouseDown)
|
||||
title:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
title:SetAllPoints(titlebg)
|
||||
|
||||
local titletext = title:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOP", titlebg, "TOP", 0, -14)
|
||||
|
||||
local titlebg_l = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg_l:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg_l:SetTexCoord(0.21, 0.31, 0, 0.63)
|
||||
titlebg_l:SetPoint("RIGHT", titlebg, "LEFT")
|
||||
titlebg_l:SetWidth(30)
|
||||
titlebg_l:SetHeight(40)
|
||||
|
||||
local titlebg_r = frame:CreateTexture(nil, "OVERLAY")
|
||||
titlebg_r:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Header")
|
||||
titlebg_r:SetTexCoord(0.67, 0.77, 0, 0.63)
|
||||
titlebg_r:SetPoint("LEFT", titlebg, "RIGHT")
|
||||
titlebg_r:SetWidth(30)
|
||||
titlebg_r:SetHeight(40)
|
||||
|
||||
local sizer_se = CreateFrame("Frame", nil, frame)
|
||||
sizer_se:SetPoint("BOTTOMRIGHT")
|
||||
sizer_se:SetWidth(25)
|
||||
sizer_se:SetHeight(25)
|
||||
sizer_se:EnableMouse()
|
||||
sizer_se:SetScript("OnMouseDown",SizerSE_OnMouseDown)
|
||||
sizer_se:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
line1:SetWidth(14)
|
||||
line1:SetHeight(14)
|
||||
line1:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 14/17
|
||||
line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
line2:SetWidth(8)
|
||||
line2:SetHeight(8)
|
||||
line2:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 8/17
|
||||
line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local sizer_s = CreateFrame("Frame", nil, frame)
|
||||
sizer_s:SetPoint("BOTTOMRIGHT", -25, 0)
|
||||
sizer_s:SetPoint("BOTTOMLEFT")
|
||||
sizer_s:SetHeight(25)
|
||||
sizer_s:EnableMouse(true)
|
||||
sizer_s:SetScript("OnMouseDown", SizerS_OnMouseDown)
|
||||
sizer_s:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
local sizer_e = CreateFrame("Frame", nil, frame)
|
||||
sizer_e:SetPoint("BOTTOMRIGHT", 0, 25)
|
||||
sizer_e:SetPoint("TOPRIGHT")
|
||||
sizer_e:SetWidth(25)
|
||||
sizer_e:EnableMouse(true)
|
||||
sizer_e:SetScript("OnMouseDown", SizerE_OnMouseDown)
|
||||
sizer_e:SetScript("OnMouseUp", MoverSizer_OnMouseUp)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT", 17, -27)
|
||||
content:SetPoint("BOTTOMRIGHT", -17, 40)
|
||||
|
||||
local widget = {
|
||||
localstatus = {},
|
||||
titletext = titletext,
|
||||
statustext = statustext,
|
||||
content = content,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
closebutton.obj, statusbg.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,102 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
InlineGroup Container
|
||||
Simple container widget that creates a visible "box" with an optional title.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "InlineGroup", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(300)
|
||||
self:SetHeight(100)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetTitle"] = function(self,title)
|
||||
self.titletext:SetText(title)
|
||||
end,
|
||||
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + 40)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 20
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 20
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 14, 0)
|
||||
titletext:SetPoint("TOPRIGHT", -14, 0)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 0, -17)
|
||||
border:SetPoint("BOTTOMRIGHT", -1, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
content = content,
|
||||
titletext = titletext,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,204 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
ScrollFrame Container
|
||||
Plain container that scrolls its content and doesn't grow in height.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "ScrollFrame", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
local min, max, floor = math.min, math.max, math.floor
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function FixScrollOnUpdate(frame)
|
||||
frame:SetScript("OnUpdate", nil)
|
||||
frame.obj:FixScroll()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function ScrollFrame_OnMouseWheel(frame, value)
|
||||
frame.obj:MoveScroll(value)
|
||||
end
|
||||
|
||||
local function ScrollFrame_OnSizeChanged(frame)
|
||||
frame:SetScript("OnUpdate", FixScrollOnUpdate)
|
||||
end
|
||||
|
||||
local function ScrollBar_OnScrollValueChanged(frame, value)
|
||||
frame.obj:SetScroll(value)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetScroll(0)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
self.scrollframe:SetPoint("BOTTOMRIGHT")
|
||||
self.scrollbar:Hide()
|
||||
self.scrollBarShown = nil
|
||||
self.content.height, self.content.width = nil, nil
|
||||
end,
|
||||
|
||||
["SetScroll"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local viewheight = self.scrollframe:GetHeight()
|
||||
local height = self.content:GetHeight()
|
||||
local offset
|
||||
|
||||
if viewheight > height then
|
||||
offset = 0
|
||||
else
|
||||
offset = floor((height - viewheight) / 1000.0 * value)
|
||||
end
|
||||
self.content:ClearAllPoints()
|
||||
self.content:SetPoint("TOPLEFT", 0, offset)
|
||||
self.content:SetPoint("TOPRIGHT", 0, offset)
|
||||
status.offset = offset
|
||||
status.scrollvalue = value
|
||||
end,
|
||||
|
||||
["MoveScroll"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
|
||||
|
||||
if height > viewheight then
|
||||
self.scrollbar:Hide()
|
||||
else
|
||||
self.scrollbar:Show()
|
||||
local diff = height - viewheight
|
||||
local delta = 1
|
||||
if value < 0 then
|
||||
delta = -1
|
||||
end
|
||||
self.scrollbar:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
||||
end
|
||||
end,
|
||||
|
||||
["FixScroll"] = function(self)
|
||||
if self.updateLock then return end
|
||||
self.updateLock = true
|
||||
local status = self.status or self.localstatus
|
||||
local height, viewheight = self.scrollframe:GetHeight(), self.content:GetHeight()
|
||||
local offset = status.offset or 0
|
||||
local curvalue = self.scrollbar:GetValue()
|
||||
if viewheight < height then
|
||||
if self.scrollBarShown then
|
||||
self.scrollBarShown = nil
|
||||
self.scrollbar:Hide()
|
||||
self.scrollbar:SetValue(0)
|
||||
self.scrollframe:SetPoint("BOTTOMRIGHT")
|
||||
self:DoLayout()
|
||||
end
|
||||
else
|
||||
if not self.scrollBarShown then
|
||||
self.scrollBarShown = true
|
||||
self.scrollbar:Show()
|
||||
self.scrollframe:SetPoint("BOTTOMRIGHT", -20, 0)
|
||||
self:DoLayout()
|
||||
end
|
||||
local value = (offset / (viewheight - height) * 1000)
|
||||
if value > 1000 then value = 1000 end
|
||||
self.scrollbar:SetValue(value)
|
||||
self:SetScroll(value)
|
||||
if value < 1000 then
|
||||
self.content:ClearAllPoints()
|
||||
self.content:SetPoint("TOPLEFT", 0, offset)
|
||||
self.content:SetPoint("TOPRIGHT", 0, offset)
|
||||
status.offset = offset
|
||||
end
|
||||
end
|
||||
self.updateLock = nil
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
self.content:SetHeight(height or 0 + 20)
|
||||
self.scrollframe:SetScript("OnUpdate", FixScrollOnUpdate)
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
if not status.scrollvalue then
|
||||
status.scrollvalue = 0
|
||||
end
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
content.width = width
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
content.height = height
|
||||
end
|
||||
}
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local scrollframe = CreateFrame("ScrollFrame", nil, frame)
|
||||
scrollframe:SetPoint("TOPLEFT")
|
||||
scrollframe:SetPoint("BOTTOMRIGHT")
|
||||
scrollframe:EnableMouseWheel(true)
|
||||
scrollframe:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel)
|
||||
scrollframe:SetScript("OnSizeChanged", ScrollFrame_OnSizeChanged)
|
||||
|
||||
local scrollbar = CreateFrame("Slider", ("AceConfigDialogScrollFrame%dScrollBar"):format(num), scrollframe, "UIPanelScrollBarTemplate")
|
||||
scrollbar:SetPoint("TOPLEFT", scrollframe, "TOPRIGHT", 4, -16)
|
||||
scrollbar:SetPoint("BOTTOMLEFT", scrollframe, "BOTTOMRIGHT", 4, 16)
|
||||
scrollbar:SetMinMaxValues(0, 1000)
|
||||
scrollbar:SetValueStep(1)
|
||||
scrollbar:SetValue(0)
|
||||
scrollbar:SetWidth(16)
|
||||
scrollbar:Hide()
|
||||
-- set the script as the last step, so it doesn't fire yet
|
||||
scrollbar:SetScript("OnValueChanged", ScrollBar_OnScrollValueChanged)
|
||||
|
||||
local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
|
||||
scrollbg:SetAllPoints(scrollbar)
|
||||
scrollbg:SetTexture(0, 0, 0, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, scrollframe)
|
||||
content:SetPoint("TOPLEFT")
|
||||
content:SetPoint("TOPRIGHT")
|
||||
content:SetHeight(400)
|
||||
scrollframe:SetScrollChild(content)
|
||||
|
||||
local widget = {
|
||||
localstatus = { scrollvalue = 0 },
|
||||
scrollframe = scrollframe,
|
||||
scrollbar = scrollbar,
|
||||
content = content,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
scrollframe.obj, scrollbar.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,69 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
SimpleGroup Container
|
||||
Simple container widget that just groups widgets.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "SimpleGroup", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(300)
|
||||
self:SetHeight(100)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight(height or 0)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
content:SetWidth(width)
|
||||
content.width = width
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
content:SetHeight(height)
|
||||
content.height = height
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, frame)
|
||||
content:SetPoint("TOPLEFT")
|
||||
content:SetPoint("BOTTOMRIGHT")
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,348 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
TabGroup Container
|
||||
Container that uses tabs on top to switch between groups.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "TabGroup", 30
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, ipairs, assert, type, wipe = pairs, ipairs, assert, type, wipe
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: PanelTemplates_TabResize, PanelTemplates_SetDisabledTabState, PanelTemplates_SelectTab, PanelTemplates_DeselectTab
|
||||
|
||||
-- local upvalue storage used by BuildTabs
|
||||
local widths = {}
|
||||
local rowwidths = {}
|
||||
local rowends = {}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function UpdateTabLook(frame)
|
||||
if frame.disabled then
|
||||
PanelTemplates_SetDisabledTabState(frame)
|
||||
elseif frame.selected then
|
||||
PanelTemplates_SelectTab(frame)
|
||||
else
|
||||
PanelTemplates_DeselectTab(frame)
|
||||
end
|
||||
end
|
||||
|
||||
local function Tab_SetText(frame, text)
|
||||
frame:_SetText(text)
|
||||
local width = frame.obj.frame.width or frame.obj.frame:GetWidth() or 0
|
||||
PanelTemplates_TabResize(frame, 0, nil, width)
|
||||
end
|
||||
|
||||
local function Tab_SetSelected(frame, selected)
|
||||
frame.selected = selected
|
||||
UpdateTabLook(frame)
|
||||
end
|
||||
|
||||
local function Tab_SetDisabled(frame, disabled)
|
||||
frame.disabled = disabled
|
||||
UpdateTabLook(frame)
|
||||
end
|
||||
|
||||
local function BuildTabsOnUpdate(frame)
|
||||
local self = frame.obj
|
||||
self:BuildTabs()
|
||||
frame:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Tab_OnClick(frame)
|
||||
if not (frame.selected or frame.disabled) then
|
||||
PlaySound("igCharacterInfoTab")
|
||||
frame.obj:SelectTab(frame.value)
|
||||
end
|
||||
end
|
||||
|
||||
local function Tab_OnEnter(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnTabEnter", self.tabs[frame.id].value, frame)
|
||||
end
|
||||
|
||||
local function Tab_OnLeave(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnTabLeave", self.tabs[frame.id].value, frame)
|
||||
end
|
||||
|
||||
local function Tab_OnShow(frame)
|
||||
_G[frame:GetName().."HighlightTexture"]:SetWidth(frame:GetTextWidth() + 30)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetTitle()
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
self.tablist = nil
|
||||
for _, tab in pairs(self.tabs) do
|
||||
tab:Hide()
|
||||
end
|
||||
end,
|
||||
|
||||
["CreateTab"] = function(self, id)
|
||||
local tabname = ("AceGUITabGroup%dTab%d"):format(self.num, id)
|
||||
local tab = CreateFrame("Button", tabname, self.border, "OptionsFrameTabButtonTemplate")
|
||||
tab.obj = self
|
||||
tab.id = id
|
||||
|
||||
tab.text = _G[tabname .. "Text"]
|
||||
tab.text:ClearAllPoints()
|
||||
tab.text:SetPoint("LEFT", 14, -3)
|
||||
tab.text:SetPoint("RIGHT", -12, -3)
|
||||
|
||||
tab:SetScript("OnClick", Tab_OnClick)
|
||||
tab:SetScript("OnEnter", Tab_OnEnter)
|
||||
tab:SetScript("OnLeave", Tab_OnLeave)
|
||||
tab:SetScript("OnShow", Tab_OnShow)
|
||||
|
||||
tab._SetText = tab.SetText
|
||||
tab.SetText = Tab_SetText
|
||||
tab.SetSelected = Tab_SetSelected
|
||||
tab.SetDisabled = Tab_SetDisabled
|
||||
|
||||
return tab
|
||||
end,
|
||||
|
||||
["SetTitle"] = function(self, text)
|
||||
self.titletext:SetText(text or "")
|
||||
if text and text ~= "" then
|
||||
self.alignoffset = 25
|
||||
else
|
||||
self.alignoffset = 18
|
||||
end
|
||||
self:BuildTabs()
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
end,
|
||||
|
||||
["SelectTab"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
local found
|
||||
for i, v in ipairs(self.tabs) do
|
||||
if v.value == value then
|
||||
v:SetSelected(true)
|
||||
found = true
|
||||
else
|
||||
v:SetSelected(false)
|
||||
end
|
||||
end
|
||||
status.selected = value
|
||||
if found then
|
||||
self:Fire("OnGroupSelected",value)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetTabs"] = function(self, tabs)
|
||||
self.tablist = tabs
|
||||
self:BuildTabs()
|
||||
end,
|
||||
|
||||
|
||||
["BuildTabs"] = function(self)
|
||||
local hastitle = (self.titletext:GetText() and self.titletext:GetText() ~= "")
|
||||
local status = self.status or self.localstatus
|
||||
local tablist = self.tablist
|
||||
local tabs = self.tabs
|
||||
|
||||
if not tablist then return end
|
||||
|
||||
local width = self.frame.width or self.frame:GetWidth() or 0
|
||||
|
||||
wipe(widths)
|
||||
wipe(rowwidths)
|
||||
wipe(rowends)
|
||||
|
||||
--Place Text into tabs and get thier initial width
|
||||
for i, v in ipairs(tablist) do
|
||||
local tab = tabs[i]
|
||||
if not tab then
|
||||
tab = self:CreateTab(i)
|
||||
tabs[i] = tab
|
||||
end
|
||||
|
||||
tab:Show()
|
||||
tab:SetText(v.text)
|
||||
tab:SetDisabled(v.disabled)
|
||||
tab.value = v.value
|
||||
|
||||
widths[i] = tab:GetWidth() - 6 --tabs are anchored 10 pixels from the right side of the previous one to reduce spacing, but add a fixed 4px padding for the text
|
||||
end
|
||||
|
||||
for i = (#tablist)+1, #tabs, 1 do
|
||||
tabs[i]:Hide()
|
||||
end
|
||||
|
||||
--First pass, find the minimum number of rows needed to hold all tabs and the initial tab layout
|
||||
local numtabs = #tablist
|
||||
local numrows = 1
|
||||
local usedwidth = 0
|
||||
|
||||
for i = 1, #tablist do
|
||||
--If this is not the first tab of a row and there isn't room for it
|
||||
if usedwidth ~= 0 and (width - usedwidth - widths[i]) < 0 then
|
||||
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
||||
rowends[numrows] = i - 1
|
||||
numrows = numrows + 1
|
||||
usedwidth = 0
|
||||
end
|
||||
usedwidth = usedwidth + widths[i]
|
||||
end
|
||||
rowwidths[numrows] = usedwidth + 10 --first tab in each row takes up an extra 10px
|
||||
rowends[numrows] = #tablist
|
||||
|
||||
--Fix for single tabs being left on the last row, move a tab from the row above if applicable
|
||||
if numrows > 1 then
|
||||
--if the last row has only one tab
|
||||
if rowends[numrows-1] == numtabs-1 then
|
||||
--if there are more than 2 tabs in the 2nd last row
|
||||
if (numrows == 2 and rowends[numrows-1] > 2) or (rowends[numrows] - rowends[numrows-1] > 2) then
|
||||
--move 1 tab from the second last row to the last, if there is enough space
|
||||
if (rowwidths[numrows] + widths[numtabs-1]) <= width then
|
||||
rowends[numrows-1] = rowends[numrows-1] - 1
|
||||
rowwidths[numrows] = rowwidths[numrows] + widths[numtabs-1]
|
||||
rowwidths[numrows-1] = rowwidths[numrows-1] - widths[numtabs-1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--anchor the rows as defined and resize tabs to fill thier row
|
||||
local starttab = 1
|
||||
for row, endtab in ipairs(rowends) do
|
||||
local first = true
|
||||
for tabno = starttab, endtab do
|
||||
local tab = tabs[tabno]
|
||||
tab:ClearAllPoints()
|
||||
if first then
|
||||
tab:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, -(hastitle and 14 or 7)-(row-1)*20 )
|
||||
first = false
|
||||
else
|
||||
tab:SetPoint("LEFT", tabs[tabno-1], "RIGHT", -10, 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- equal padding for each tab to fill the available width,
|
||||
-- if the used space is above 75% already
|
||||
local padding = 0
|
||||
if not (numrows == 1 and rowwidths[1] < width*0.75) then
|
||||
padding = (width - rowwidths[row]) / (endtab - starttab+1)
|
||||
end
|
||||
|
||||
for i = starttab, endtab do
|
||||
PanelTemplates_TabResize(tabs[i], padding + 4, nil, width)
|
||||
end
|
||||
starttab = endtab + 1
|
||||
end
|
||||
|
||||
self.borderoffset = (hastitle and 17 or 10)+((numrows)*20)
|
||||
self.border:SetPoint("TOPLEFT", 1, -self.borderoffset)
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 60
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
self:BuildTabs(self)
|
||||
self.frame:SetScript("OnUpdate", BuildTabsOnUpdate)
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - (self.borderoffset + 23)
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + (self.borderoffset + 23))
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame",nil,UIParent)
|
||||
frame:SetHeight(100)
|
||||
frame:SetWidth(100)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local titletext = frame:CreateFontString(nil,"OVERLAY","GameFontNormal")
|
||||
titletext:SetPoint("TOPLEFT", 14, 0)
|
||||
titletext:SetPoint("TOPRIGHT", -14, 0)
|
||||
titletext:SetJustifyH("LEFT")
|
||||
titletext:SetHeight(18)
|
||||
titletext:SetText("")
|
||||
|
||||
local border = CreateFrame("Frame", nil, frame)
|
||||
border:SetPoint("TOPLEFT", 1, -27)
|
||||
border:SetPoint("BOTTOMRIGHT", -1, 3)
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -7)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 7)
|
||||
|
||||
local widget = {
|
||||
num = num,
|
||||
frame = frame,
|
||||
localstatus = {},
|
||||
alignoffset = 18,
|
||||
titletext = titletext,
|
||||
border = border,
|
||||
borderoffset = 27,
|
||||
tabs = {},
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,670 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
TreeGroup Container
|
||||
Container that uses a tree control to switch between groups.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "TreeGroup", 30
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local next, pairs, ipairs, assert, type = next, pairs, ipairs, assert, type
|
||||
local math_min, math_max, floor = math.min, math.max, floor
|
||||
local select, tremove, unpack = select, table.remove, unpack
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameTooltip, FONT_COLOR_CODE_CLOSE
|
||||
|
||||
-- Recycling functions
|
||||
local new, del
|
||||
do
|
||||
local pool = setmetatable({},{__mode='k'})
|
||||
function new()
|
||||
local t = next(pool)
|
||||
if t then
|
||||
pool[t] = nil
|
||||
return t
|
||||
else
|
||||
return {}
|
||||
end
|
||||
end
|
||||
function del(t)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
pool[t] = true
|
||||
end
|
||||
end
|
||||
|
||||
local DEFAULT_TREE_WIDTH = 175
|
||||
local DEFAULT_TREE_SIZABLE = true
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function GetButtonUniqueValue(line)
|
||||
local parent = line.parent
|
||||
if parent and parent.value then
|
||||
return GetButtonUniqueValue(parent).."\001"..line.value
|
||||
else
|
||||
return line.value
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateButton(button, treeline, selected, canExpand, isExpanded)
|
||||
local self = button.obj
|
||||
local toggle = button.toggle
|
||||
local frame = self.frame
|
||||
local text = treeline.text or ""
|
||||
local icon = treeline.icon
|
||||
local iconCoords = treeline.iconCoords
|
||||
local level = treeline.level
|
||||
local value = treeline.value
|
||||
local uniquevalue = treeline.uniquevalue
|
||||
local disabled = treeline.disabled
|
||||
|
||||
button.treeline = treeline
|
||||
button.value = value
|
||||
button.uniquevalue = uniquevalue
|
||||
if selected then
|
||||
button:LockHighlight()
|
||||
button.selected = true
|
||||
else
|
||||
button:UnlockHighlight()
|
||||
button.selected = false
|
||||
end
|
||||
local normalTexture = button:GetNormalTexture()
|
||||
local line = button.line
|
||||
button.level = level
|
||||
if ( level == 1 ) then
|
||||
button:SetNormalFontObject("GameFontNormal")
|
||||
button:SetHighlightFontObject("GameFontHighlight")
|
||||
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8, 2)
|
||||
else
|
||||
button:SetNormalFontObject("GameFontHighlightSmall")
|
||||
button:SetHighlightFontObject("GameFontHighlightSmall")
|
||||
button.text:SetPoint("LEFT", (icon and 16 or 0) + 8 * level, 2)
|
||||
end
|
||||
|
||||
if disabled then
|
||||
button:EnableMouse(false)
|
||||
button.text:SetText("|cff808080"..text..FONT_COLOR_CODE_CLOSE)
|
||||
else
|
||||
button.text:SetText(text)
|
||||
button:EnableMouse(true)
|
||||
end
|
||||
|
||||
if icon then
|
||||
button.icon:SetTexture(icon)
|
||||
button.icon:SetPoint("LEFT", 8 * level, (level == 1) and 0 or 1)
|
||||
else
|
||||
button.icon:SetTexture(nil)
|
||||
end
|
||||
|
||||
if iconCoords then
|
||||
button.icon:SetTexCoord(unpack(iconCoords))
|
||||
else
|
||||
button.icon:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
|
||||
if canExpand then
|
||||
if not isExpanded then
|
||||
toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP")
|
||||
toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-DOWN")
|
||||
else
|
||||
toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP")
|
||||
toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN")
|
||||
end
|
||||
toggle:Show()
|
||||
else
|
||||
toggle:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function ShouldDisplayLevel(tree)
|
||||
local result = false
|
||||
for k, v in ipairs(tree) do
|
||||
if v.children == nil and v.visible ~= false then
|
||||
result = true
|
||||
elseif v.children then
|
||||
result = result or ShouldDisplayLevel(v.children)
|
||||
end
|
||||
if result then return result end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function addLine(self, v, tree, level, parent)
|
||||
local line = new()
|
||||
line.value = v.value
|
||||
line.text = v.text
|
||||
line.icon = v.icon
|
||||
line.iconCoords = v.iconCoords
|
||||
line.disabled = v.disabled
|
||||
line.tree = tree
|
||||
line.level = level
|
||||
line.parent = parent
|
||||
line.visible = v.visible
|
||||
line.uniquevalue = GetButtonUniqueValue(line)
|
||||
if v.children then
|
||||
line.hasChildren = true
|
||||
else
|
||||
line.hasChildren = nil
|
||||
end
|
||||
self.lines[#self.lines+1] = line
|
||||
return line
|
||||
end
|
||||
|
||||
--fire an update after one frame to catch the treeframes height
|
||||
local function FirstFrameUpdate(frame)
|
||||
local self = frame.obj
|
||||
frame:SetScript("OnUpdate", nil)
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local function BuildUniqueValue(...)
|
||||
local n = select('#', ...)
|
||||
if n == 1 then
|
||||
return ...
|
||||
else
|
||||
return (...).."\001"..BuildUniqueValue(select(2,...))
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Expand_OnClick(frame)
|
||||
local button = frame.button
|
||||
local self = button.obj
|
||||
local status = (self.status or self.localstatus).groups
|
||||
status[button.uniquevalue] = not status[button.uniquevalue]
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local function Button_OnClick(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnClick", frame.uniquevalue, frame.selected)
|
||||
if not frame.selected then
|
||||
self:SetSelected(frame.uniquevalue)
|
||||
frame.selected = true
|
||||
frame:LockHighlight()
|
||||
self:RefreshTree()
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Button_OnDoubleClick(button)
|
||||
local self = button.obj
|
||||
local status = self.status or self.localstatus
|
||||
local status = (self.status or self.localstatus).groups
|
||||
status[button.uniquevalue] = not status[button.uniquevalue]
|
||||
self:RefreshTree()
|
||||
end
|
||||
|
||||
local function Button_OnEnter(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnButtonEnter", frame.uniquevalue, frame)
|
||||
|
||||
if self.enabletooltips then
|
||||
GameTooltip:SetOwner(frame, "ANCHOR_NONE")
|
||||
GameTooltip:SetPoint("LEFT",frame,"RIGHT")
|
||||
GameTooltip:SetText(frame.text:GetText() or "", 1, .82, 0, 1)
|
||||
|
||||
GameTooltip:Show()
|
||||
end
|
||||
end
|
||||
|
||||
local function Button_OnLeave(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnButtonLeave", frame.uniquevalue, frame)
|
||||
|
||||
if self.enabletooltips then
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnScrollValueChanged(frame, value)
|
||||
if frame.obj.noupdate then return end
|
||||
local self = frame.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.scrollvalue = value
|
||||
self:RefreshTree()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Tree_OnSizeChanged(frame)
|
||||
frame.obj:RefreshTree()
|
||||
end
|
||||
|
||||
local function Tree_OnMouseWheel(frame, delta)
|
||||
local self = frame.obj
|
||||
if self.showscroll then
|
||||
local scrollbar = self.scrollbar
|
||||
local min, max = scrollbar:GetMinMaxValues()
|
||||
local value = scrollbar:GetValue()
|
||||
local newvalue = math_min(max,math_max(min,value - delta))
|
||||
if value ~= newvalue then
|
||||
scrollbar:SetValue(newvalue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Dragger_OnLeave(frame)
|
||||
frame:SetBackdropColor(1, 1, 1, 0)
|
||||
end
|
||||
|
||||
local function Dragger_OnEnter(frame)
|
||||
frame:SetBackdropColor(1, 1, 1, 0.8)
|
||||
end
|
||||
|
||||
local function Dragger_OnMouseDown(frame)
|
||||
local treeframe = frame:GetParent()
|
||||
treeframe:StartSizing("RIGHT")
|
||||
end
|
||||
|
||||
local function Dragger_OnMouseUp(frame)
|
||||
local treeframe = frame:GetParent()
|
||||
local self = treeframe.obj
|
||||
local frame = treeframe:GetParent()
|
||||
treeframe:StopMovingOrSizing()
|
||||
--treeframe:SetScript("OnUpdate", nil)
|
||||
treeframe:SetUserPlaced(false)
|
||||
--Without this :GetHeight will get stuck on the current height, causing the tree contents to not resize
|
||||
treeframe:SetHeight(0)
|
||||
treeframe:SetPoint("TOPLEFT", frame, "TOPLEFT",0,0)
|
||||
treeframe:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT",0,0)
|
||||
|
||||
local status = self.status or self.localstatus
|
||||
status.treewidth = treeframe:GetWidth()
|
||||
|
||||
treeframe.obj:Fire("OnTreeResize",treeframe:GetWidth())
|
||||
-- recalculate the content width
|
||||
treeframe.obj:OnWidthSet(status.fullwidth)
|
||||
-- update the layout of the content
|
||||
treeframe.obj:DoLayout()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetTreeWidth(DEFAULT_TREE_WIDTH, DEFAULT_TREE_SIZABLE)
|
||||
self:EnableButtonTooltips(true)
|
||||
end,
|
||||
|
||||
["OnRelease"] = function(self)
|
||||
self.status = nil
|
||||
for k, v in pairs(self.localstatus) do
|
||||
if k == "groups" then
|
||||
for k2 in pairs(v) do
|
||||
v[k2] = nil
|
||||
end
|
||||
else
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end
|
||||
self.localstatus.scrollvalue = 0
|
||||
self.localstatus.treewidth = DEFAULT_TREE_WIDTH
|
||||
self.localstatus.treesizable = DEFAULT_TREE_SIZABLE
|
||||
end,
|
||||
|
||||
["EnableButtonTooltips"] = function(self, enable)
|
||||
self.enabletooltips = enable
|
||||
end,
|
||||
|
||||
["CreateButton"] = function(self)
|
||||
local num = AceGUI:GetNextWidgetNum("TreeGroupButton")
|
||||
local button = CreateFrame("Button", ("AceGUI30TreeButton%d"):format(num), self.treeframe, "OptionsListButtonTemplate")
|
||||
button.obj = self
|
||||
|
||||
local icon = button:CreateTexture(nil, "OVERLAY")
|
||||
icon:SetWidth(14)
|
||||
icon:SetHeight(14)
|
||||
button.icon = icon
|
||||
|
||||
button:SetScript("OnClick",Button_OnClick)
|
||||
button:SetScript("OnDoubleClick", Button_OnDoubleClick)
|
||||
button:SetScript("OnEnter",Button_OnEnter)
|
||||
button:SetScript("OnLeave",Button_OnLeave)
|
||||
|
||||
button.toggle.button = button
|
||||
button.toggle:SetScript("OnClick",Expand_OnClick)
|
||||
|
||||
return button
|
||||
end,
|
||||
|
||||
["SetStatusTable"] = function(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
if not status.groups then
|
||||
status.groups = {}
|
||||
end
|
||||
if not status.scrollvalue then
|
||||
status.scrollvalue = 0
|
||||
end
|
||||
if not status.treewidth then
|
||||
status.treewidth = DEFAULT_TREE_WIDTH
|
||||
end
|
||||
if not status.treesizable then
|
||||
status.treesizable = DEFAULT_TREE_SIZABLE
|
||||
end
|
||||
self:SetTreeWidth(status.treewidth,status.treesizable)
|
||||
self:RefreshTree()
|
||||
end,
|
||||
|
||||
--sets the tree to be displayed
|
||||
["SetTree"] = function(self, tree, filter)
|
||||
self.filter = filter
|
||||
if tree then
|
||||
assert(type(tree) == "table")
|
||||
end
|
||||
self.tree = tree
|
||||
self:RefreshTree()
|
||||
end,
|
||||
|
||||
["BuildLevel"] = function(self, tree, level, parent)
|
||||
local groups = (self.status or self.localstatus).groups
|
||||
local hasChildren = self.hasChildren
|
||||
|
||||
for i, v in ipairs(tree) do
|
||||
if v.children then
|
||||
if not self.filter or ShouldDisplayLevel(v.children) then
|
||||
local line = addLine(self, v, tree, level, parent)
|
||||
if groups[line.uniquevalue] then
|
||||
self:BuildLevel(v.children, level+1, line)
|
||||
end
|
||||
end
|
||||
elseif v.visible ~= false or not self.filter then
|
||||
addLine(self, v, tree, level, parent)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["RefreshTree"] = function(self)
|
||||
local buttons = self.buttons
|
||||
local lines = self.lines
|
||||
|
||||
for i, v in ipairs(buttons) do
|
||||
v:Hide()
|
||||
end
|
||||
while lines[1] do
|
||||
local t = tremove(lines)
|
||||
for k in pairs(t) do
|
||||
t[k] = nil
|
||||
end
|
||||
del(t)
|
||||
end
|
||||
|
||||
if not self.tree then return end
|
||||
--Build the list of visible entries from the tree and status tables
|
||||
local status = self.status or self.localstatus
|
||||
local groupstatus = status.groups
|
||||
local tree = self.tree
|
||||
|
||||
local treeframe = self.treeframe
|
||||
|
||||
self:BuildLevel(tree, 1)
|
||||
|
||||
local numlines = #lines
|
||||
|
||||
local maxlines = (floor(((self.treeframe:GetHeight()or 0) - 20 ) / 18))
|
||||
|
||||
local first, last
|
||||
|
||||
if numlines <= maxlines then
|
||||
--the whole tree fits in the frame
|
||||
status.scrollvalue = 0
|
||||
self:ShowScroll(false)
|
||||
first, last = 1, numlines
|
||||
else
|
||||
self:ShowScroll(true)
|
||||
--scrolling will be needed
|
||||
self.noupdate = true
|
||||
self.scrollbar:SetMinMaxValues(0, numlines - maxlines)
|
||||
--check if we are scrolled down too far
|
||||
if numlines - status.scrollvalue < maxlines then
|
||||
status.scrollvalue = numlines - maxlines
|
||||
self.scrollbar:SetValue(status.scrollvalue)
|
||||
end
|
||||
self.noupdate = nil
|
||||
first, last = status.scrollvalue+1, status.scrollvalue + maxlines
|
||||
end
|
||||
|
||||
local buttonnum = 1
|
||||
for i = first, last do
|
||||
local line = lines[i]
|
||||
local button = buttons[buttonnum]
|
||||
if not button then
|
||||
button = self:CreateButton()
|
||||
|
||||
buttons[buttonnum] = button
|
||||
button:SetParent(treeframe)
|
||||
button:SetFrameLevel(treeframe:GetFrameLevel()+1)
|
||||
button:ClearAllPoints()
|
||||
if i == 1 then
|
||||
if self.showscroll then
|
||||
button:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10)
|
||||
button:SetPoint("TOPLEFT", self.treeframe, "TOPLEFT", 0, -10)
|
||||
else
|
||||
button:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10)
|
||||
button:SetPoint("TOPLEFT", self.treeframe, "TOPLEFT", 0, -10)
|
||||
end
|
||||
else
|
||||
button:SetPoint("TOPRIGHT", buttons[buttonnum-1], "BOTTOMRIGHT",0,0)
|
||||
button:SetPoint("TOPLEFT", buttons[buttonnum-1], "BOTTOMLEFT",0,0)
|
||||
end
|
||||
end
|
||||
|
||||
UpdateButton(button, line, status.selected == line.uniquevalue, line.hasChildren, groupstatus[line.uniquevalue] )
|
||||
button:Show()
|
||||
buttonnum = buttonnum + 1
|
||||
end
|
||||
end,
|
||||
|
||||
["SetSelected"] = function(self, value)
|
||||
local status = self.status or self.localstatus
|
||||
if status.selected ~= value then
|
||||
status.selected = value
|
||||
self:Fire("OnGroupSelected", value)
|
||||
end
|
||||
end,
|
||||
|
||||
["Select"] = function(self, uniquevalue, ...)
|
||||
self.filter = false
|
||||
local status = self.status or self.localstatus
|
||||
local groups = status.groups
|
||||
for i = 1, select('#', ...) do
|
||||
groups[BuildUniqueValue(select(i, ...))] = true
|
||||
end
|
||||
status.selected = uniquevalue
|
||||
self:RefreshTree()
|
||||
self:Fire("OnGroupSelected", uniquevalue)
|
||||
end,
|
||||
|
||||
["SelectByPath"] = function(self, ...)
|
||||
self:Select(BuildUniqueValue(...), ...)
|
||||
end,
|
||||
|
||||
["SelectByValue"] = function(self, uniquevalue)
|
||||
self:Select(uniquevalue, ("\001"):split(uniquevalue))
|
||||
end,
|
||||
|
||||
["ShowScroll"] = function(self, show)
|
||||
self.showscroll = show
|
||||
if show then
|
||||
self.scrollbar:Show()
|
||||
if self.buttons[1] then
|
||||
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",-22,-10)
|
||||
end
|
||||
else
|
||||
self.scrollbar:Hide()
|
||||
if self.buttons[1] then
|
||||
self.buttons[1]:SetPoint("TOPRIGHT", self.treeframe,"TOPRIGHT",0,-10)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
local content = self.content
|
||||
local treeframe = self.treeframe
|
||||
local status = self.status or self.localstatus
|
||||
status.fullwidth = width
|
||||
|
||||
local contentwidth = width - status.treewidth - 20
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
|
||||
local maxtreewidth = math_min(400, width - 50)
|
||||
|
||||
if maxtreewidth > 100 and status.treewidth > maxtreewidth then
|
||||
self:SetTreeWidth(maxtreewidth, status.treesizable)
|
||||
end
|
||||
treeframe:SetMaxResize(maxtreewidth, 1600)
|
||||
end,
|
||||
|
||||
["OnHeightSet"] = function(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 20
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end,
|
||||
|
||||
["SetTreeWidth"] = function(self, treewidth, resizable)
|
||||
if not resizable then
|
||||
if type(treewidth) == 'number' then
|
||||
resizable = false
|
||||
elseif type(treewidth) == 'boolean' then
|
||||
resizable = treewidth
|
||||
treewidth = DEFAULT_TREE_WIDTH
|
||||
else
|
||||
resizable = false
|
||||
treewidth = DEFAULT_TREE_WIDTH
|
||||
end
|
||||
end
|
||||
self.treeframe:SetWidth(treewidth)
|
||||
self.dragger:EnableMouse(resizable)
|
||||
|
||||
local status = self.status or self.localstatus
|
||||
status.treewidth = treewidth
|
||||
status.treesizable = resizable
|
||||
|
||||
-- recalculate the content width
|
||||
if status.fullwidth then
|
||||
self:OnWidthSet(status.fullwidth)
|
||||
end
|
||||
end,
|
||||
|
||||
["LayoutFinished"] = function(self, width, height)
|
||||
if self.noAutoHeight then return end
|
||||
self:SetHeight((height or 0) + 20)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local PaneBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 5, bottom = 3 }
|
||||
}
|
||||
|
||||
local DraggerBackdrop = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = nil,
|
||||
tile = true, tileSize = 16, edgeSize = 0,
|
||||
insets = { left = 3, right = 3, top = 7, bottom = 7 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
|
||||
local treeframe = CreateFrame("Frame", nil, frame)
|
||||
treeframe:SetPoint("TOPLEFT")
|
||||
treeframe:SetPoint("BOTTOMLEFT")
|
||||
treeframe:SetWidth(DEFAULT_TREE_WIDTH)
|
||||
treeframe:EnableMouseWheel(true)
|
||||
treeframe:SetBackdrop(PaneBackdrop)
|
||||
treeframe:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
treeframe:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
treeframe:SetResizable(true)
|
||||
treeframe:SetMinResize(100, 1)
|
||||
treeframe:SetMaxResize(400, 1600)
|
||||
treeframe:SetScript("OnUpdate", FirstFrameUpdate)
|
||||
treeframe:SetScript("OnSizeChanged", Tree_OnSizeChanged)
|
||||
treeframe:SetScript("OnMouseWheel", Tree_OnMouseWheel)
|
||||
|
||||
local dragger = CreateFrame("Frame", nil, treeframe)
|
||||
dragger:SetWidth(8)
|
||||
dragger:SetPoint("TOP", treeframe, "TOPRIGHT")
|
||||
dragger:SetPoint("BOTTOM", treeframe, "BOTTOMRIGHT")
|
||||
dragger:SetBackdrop(DraggerBackdrop)
|
||||
dragger:SetBackdropColor(1, 1, 1, 0)
|
||||
dragger:SetScript("OnEnter", Dragger_OnEnter)
|
||||
dragger:SetScript("OnLeave", Dragger_OnLeave)
|
||||
dragger:SetScript("OnMouseDown", Dragger_OnMouseDown)
|
||||
dragger:SetScript("OnMouseUp", Dragger_OnMouseUp)
|
||||
|
||||
local scrollbar = CreateFrame("Slider", ("AceConfigDialogTreeGroup%dScrollBar"):format(num), treeframe, "UIPanelScrollBarTemplate")
|
||||
scrollbar:SetScript("OnValueChanged", nil)
|
||||
scrollbar:SetPoint("TOPRIGHT", -10, -26)
|
||||
scrollbar:SetPoint("BOTTOMRIGHT", -10, 26)
|
||||
scrollbar:SetMinMaxValues(0,0)
|
||||
scrollbar:SetValueStep(1)
|
||||
scrollbar:SetValue(0)
|
||||
scrollbar:SetWidth(16)
|
||||
scrollbar:SetScript("OnValueChanged", OnScrollValueChanged)
|
||||
|
||||
local scrollbg = scrollbar:CreateTexture(nil, "BACKGROUND")
|
||||
scrollbg:SetAllPoints(scrollbar)
|
||||
scrollbg:SetTexture(0,0,0,0.4)
|
||||
|
||||
local border = CreateFrame("Frame",nil,frame)
|
||||
border:SetPoint("TOPLEFT", treeframe, "TOPRIGHT")
|
||||
border:SetPoint("BOTTOMRIGHT")
|
||||
border:SetBackdrop(PaneBackdrop)
|
||||
border:SetBackdropColor(0.1, 0.1, 0.1, 0.5)
|
||||
border:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame", nil, border)
|
||||
content:SetPoint("TOPLEFT", 10, -10)
|
||||
content:SetPoint("BOTTOMRIGHT", -10, 10)
|
||||
|
||||
local widget = {
|
||||
frame = frame,
|
||||
lines = {},
|
||||
levels = {},
|
||||
buttons = {},
|
||||
hasChildren = {},
|
||||
localstatus = { groups = {}, scrollvalue = 0 },
|
||||
filter = false,
|
||||
treeframe = treeframe,
|
||||
dragger = dragger,
|
||||
scrollbar = scrollbar,
|
||||
border = border,
|
||||
content = content,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
treeframe.obj, dragger.obj, scrollbar.obj = widget, widget, widget
|
||||
|
||||
return AceGUI:RegisterAsContainer(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,331 @@
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, assert, type = pairs, assert, type
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontNormal
|
||||
|
||||
----------------
|
||||
-- Main Frame --
|
||||
----------------
|
||||
--[[
|
||||
Events :
|
||||
OnClose
|
||||
|
||||
]]
|
||||
do
|
||||
local Type = "Window"
|
||||
local Version = 4
|
||||
|
||||
local function frameOnClose(this)
|
||||
this.obj:Fire("OnClose")
|
||||
end
|
||||
|
||||
local function closeOnClick(this)
|
||||
PlaySound("gsTitleOptionExit")
|
||||
this.obj:Hide()
|
||||
end
|
||||
|
||||
local function frameOnMouseDown(this)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function titleOnMouseDown(this)
|
||||
this:GetParent():StartMoving()
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function frameOnMouseUp(this)
|
||||
local frame = this:GetParent()
|
||||
frame:StopMovingOrSizing()
|
||||
local self = frame.obj
|
||||
local status = self.status or self.localstatus
|
||||
status.width = frame:GetWidth()
|
||||
status.height = frame:GetHeight()
|
||||
status.top = frame:GetTop()
|
||||
status.left = frame:GetLeft()
|
||||
end
|
||||
|
||||
local function sizerseOnMouseDown(this)
|
||||
this:GetParent():StartSizing("BOTTOMRIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizersOnMouseDown(this)
|
||||
this:GetParent():StartSizing("BOTTOM")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizereOnMouseDown(this)
|
||||
this:GetParent():StartSizing("RIGHT")
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function sizerOnMouseUp(this)
|
||||
this:GetParent():StopMovingOrSizing()
|
||||
end
|
||||
|
||||
local function SetTitle(self,title)
|
||||
self.titletext:SetText(title)
|
||||
end
|
||||
|
||||
local function SetStatusText(self,text)
|
||||
-- self.statustext:SetText(text)
|
||||
end
|
||||
|
||||
local function Hide(self)
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
local function Show(self)
|
||||
self.frame:Show()
|
||||
end
|
||||
|
||||
local function OnAcquire(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self:ApplyStatus()
|
||||
self:EnableResize(true)
|
||||
self:Show()
|
||||
end
|
||||
|
||||
local function OnRelease(self)
|
||||
self.status = nil
|
||||
for k in pairs(self.localstatus) do
|
||||
self.localstatus[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- called to set an external table to store status in
|
||||
local function SetStatusTable(self, status)
|
||||
assert(type(status) == "table")
|
||||
self.status = status
|
||||
self:ApplyStatus()
|
||||
end
|
||||
|
||||
local function ApplyStatus(self)
|
||||
local status = self.status or self.localstatus
|
||||
local frame = self.frame
|
||||
self:SetWidth(status.width or 700)
|
||||
self:SetHeight(status.height or 500)
|
||||
if status.top and status.left then
|
||||
frame:SetPoint("TOP",UIParent,"BOTTOM",0,status.top)
|
||||
frame:SetPoint("LEFT",UIParent,"LEFT",status.left,0)
|
||||
else
|
||||
frame:SetPoint("CENTER",UIParent,"CENTER")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnWidthSet(self, width)
|
||||
local content = self.content
|
||||
local contentwidth = width - 34
|
||||
if contentwidth < 0 then
|
||||
contentwidth = 0
|
||||
end
|
||||
content:SetWidth(contentwidth)
|
||||
content.width = contentwidth
|
||||
end
|
||||
|
||||
|
||||
local function OnHeightSet(self, height)
|
||||
local content = self.content
|
||||
local contentheight = height - 57
|
||||
if contentheight < 0 then
|
||||
contentheight = 0
|
||||
end
|
||||
content:SetHeight(contentheight)
|
||||
content.height = contentheight
|
||||
end
|
||||
|
||||
local function EnableResize(self, state)
|
||||
local func = state and "Show" or "Hide"
|
||||
self.sizer_se[func](self.sizer_se)
|
||||
self.sizer_s[func](self.sizer_s)
|
||||
self.sizer_e[func](self.sizer_e)
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame",nil,UIParent)
|
||||
local self = {}
|
||||
self.type = "Window"
|
||||
|
||||
self.Hide = Hide
|
||||
self.Show = Show
|
||||
self.SetTitle = SetTitle
|
||||
self.OnRelease = OnRelease
|
||||
self.OnAcquire = OnAcquire
|
||||
self.SetStatusText = SetStatusText
|
||||
self.SetStatusTable = SetStatusTable
|
||||
self.ApplyStatus = ApplyStatus
|
||||
self.OnWidthSet = OnWidthSet
|
||||
self.OnHeightSet = OnHeightSet
|
||||
self.EnableResize = EnableResize
|
||||
|
||||
self.localstatus = {}
|
||||
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
frame:SetWidth(700)
|
||||
frame:SetHeight(500)
|
||||
frame:SetPoint("CENTER",UIParent,"CENTER",0,0)
|
||||
frame:EnableMouse()
|
||||
frame:SetMovable(true)
|
||||
frame:SetResizable(true)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetScript("OnMouseDown", frameOnMouseDown)
|
||||
|
||||
frame:SetScript("OnHide",frameOnClose)
|
||||
frame:SetMinResize(240,240)
|
||||
frame:SetToplevel(true)
|
||||
|
||||
local titlebg = frame:CreateTexture(nil, "BACKGROUND")
|
||||
titlebg:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Title-Background]])
|
||||
titlebg:SetPoint("TOPLEFT", 9, -6)
|
||||
titlebg:SetPoint("BOTTOMRIGHT", frame, "TOPRIGHT", -28, -24)
|
||||
|
||||
local dialogbg = frame:CreateTexture(nil, "BACKGROUND")
|
||||
dialogbg:SetTexture([[Interface\Tooltips\UI-Tooltip-Background]])
|
||||
dialogbg:SetPoint("TOPLEFT", 8, -24)
|
||||
dialogbg:SetPoint("BOTTOMRIGHT", -6, 8)
|
||||
dialogbg:SetVertexColor(0, 0, 0, .75)
|
||||
|
||||
local topleft = frame:CreateTexture(nil, "BORDER")
|
||||
topleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
topleft:SetWidth(64)
|
||||
topleft:SetHeight(64)
|
||||
topleft:SetPoint("TOPLEFT")
|
||||
topleft:SetTexCoord(0.501953125, 0.625, 0, 1)
|
||||
|
||||
local topright = frame:CreateTexture(nil, "BORDER")
|
||||
topright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
topright:SetWidth(64)
|
||||
topright:SetHeight(64)
|
||||
topright:SetPoint("TOPRIGHT")
|
||||
topright:SetTexCoord(0.625, 0.75, 0, 1)
|
||||
|
||||
local top = frame:CreateTexture(nil, "BORDER")
|
||||
top:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
top:SetHeight(64)
|
||||
top:SetPoint("TOPLEFT", topleft, "TOPRIGHT")
|
||||
top:SetPoint("TOPRIGHT", topright, "TOPLEFT")
|
||||
top:SetTexCoord(0.25, 0.369140625, 0, 1)
|
||||
|
||||
local bottomleft = frame:CreateTexture(nil, "BORDER")
|
||||
bottomleft:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottomleft:SetWidth(64)
|
||||
bottomleft:SetHeight(64)
|
||||
bottomleft:SetPoint("BOTTOMLEFT")
|
||||
bottomleft:SetTexCoord(0.751953125, 0.875, 0, 1)
|
||||
|
||||
local bottomright = frame:CreateTexture(nil, "BORDER")
|
||||
bottomright:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottomright:SetWidth(64)
|
||||
bottomright:SetHeight(64)
|
||||
bottomright:SetPoint("BOTTOMRIGHT")
|
||||
bottomright:SetTexCoord(0.875, 1, 0, 1)
|
||||
|
||||
local bottom = frame:CreateTexture(nil, "BORDER")
|
||||
bottom:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
bottom:SetHeight(64)
|
||||
bottom:SetPoint("BOTTOMLEFT", bottomleft, "BOTTOMRIGHT")
|
||||
bottom:SetPoint("BOTTOMRIGHT", bottomright, "BOTTOMLEFT")
|
||||
bottom:SetTexCoord(0.376953125, 0.498046875, 0, 1)
|
||||
|
||||
local left = frame:CreateTexture(nil, "BORDER")
|
||||
left:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
left:SetWidth(64)
|
||||
left:SetPoint("TOPLEFT", topleft, "BOTTOMLEFT")
|
||||
left:SetPoint("BOTTOMLEFT", bottomleft, "TOPLEFT")
|
||||
left:SetTexCoord(0.001953125, 0.125, 0, 1)
|
||||
|
||||
local right = frame:CreateTexture(nil, "BORDER")
|
||||
right:SetTexture([[Interface\PaperDollInfoFrame\UI-GearManager-Border]])
|
||||
right:SetWidth(64)
|
||||
right:SetPoint("TOPRIGHT", topright, "BOTTOMRIGHT")
|
||||
right:SetPoint("BOTTOMRIGHT", bottomright, "TOPRIGHT")
|
||||
right:SetTexCoord(0.1171875, 0.2421875, 0, 1)
|
||||
|
||||
local close = CreateFrame("Button", nil, frame, "UIPanelCloseButton")
|
||||
close:SetPoint("TOPRIGHT", 2, 1)
|
||||
close:SetScript("OnClick", closeOnClick)
|
||||
self.closebutton = close
|
||||
close.obj = self
|
||||
|
||||
local titletext = frame:CreateFontString(nil, "ARTWORK")
|
||||
titletext:SetFontObject(GameFontNormal)
|
||||
titletext:SetPoint("TOPLEFT", 12, -8)
|
||||
titletext:SetPoint("TOPRIGHT", -32, -8)
|
||||
self.titletext = titletext
|
||||
|
||||
local title = CreateFrame("Button", nil, frame)
|
||||
title:SetPoint("TOPLEFT", titlebg)
|
||||
title:SetPoint("BOTTOMRIGHT", titlebg)
|
||||
title:EnableMouse()
|
||||
title:SetScript("OnMouseDown",titleOnMouseDown)
|
||||
title:SetScript("OnMouseUp", frameOnMouseUp)
|
||||
self.title = title
|
||||
|
||||
local sizer_se = CreateFrame("Frame",nil,frame)
|
||||
sizer_se:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,0)
|
||||
sizer_se:SetWidth(25)
|
||||
sizer_se:SetHeight(25)
|
||||
sizer_se:EnableMouse()
|
||||
sizer_se:SetScript("OnMouseDown",sizerseOnMouseDown)
|
||||
sizer_se:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_se = sizer_se
|
||||
|
||||
local line1 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
self.line1 = line1
|
||||
line1:SetWidth(14)
|
||||
line1:SetHeight(14)
|
||||
line1:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line1:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 14/17
|
||||
line1:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local line2 = sizer_se:CreateTexture(nil, "BACKGROUND")
|
||||
self.line2 = line2
|
||||
line2:SetWidth(8)
|
||||
line2:SetHeight(8)
|
||||
line2:SetPoint("BOTTOMRIGHT", -8, 8)
|
||||
line2:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
local x = 0.1 * 8/17
|
||||
line2:SetTexCoord(0.05 - x, 0.5, 0.05, 0.5 + x, 0.05, 0.5 - x, 0.5 + x, 0.5)
|
||||
|
||||
local sizer_s = CreateFrame("Frame",nil,frame)
|
||||
sizer_s:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-25,0)
|
||||
sizer_s:SetPoint("BOTTOMLEFT",frame,"BOTTOMLEFT",0,0)
|
||||
sizer_s:SetHeight(25)
|
||||
sizer_s:EnableMouse()
|
||||
sizer_s:SetScript("OnMouseDown",sizersOnMouseDown)
|
||||
sizer_s:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_s = sizer_s
|
||||
|
||||
local sizer_e = CreateFrame("Frame",nil,frame)
|
||||
sizer_e:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",0,25)
|
||||
sizer_e:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
|
||||
sizer_e:SetWidth(25)
|
||||
sizer_e:EnableMouse()
|
||||
sizer_e:SetScript("OnMouseDown",sizereOnMouseDown)
|
||||
sizer_e:SetScript("OnMouseUp", sizerOnMouseUp)
|
||||
self.sizer_e = sizer_e
|
||||
|
||||
--Container Support
|
||||
local content = CreateFrame("Frame",nil,frame)
|
||||
self.content = content
|
||||
content.obj = self
|
||||
content:SetPoint("TOPLEFT",frame,"TOPLEFT",12,-32)
|
||||
content:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-12,13)
|
||||
|
||||
AceGUI:RegisterAsContainer(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type,Constructor,Version)
|
||||
end
|
||||
@@ -0,0 +1,92 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Button Widget
|
||||
Graphical Button.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Button", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local _G = _G
|
||||
local PlaySound, CreateFrame, UIParent = PlaySound, CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Button_OnClick(frame, ...)
|
||||
PlaySound("igMainMenuOption")
|
||||
frame.obj:Fire("OnClick", ...)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- restore default values
|
||||
self:SetHeight(24)
|
||||
self:SetWidth(200)
|
||||
self:SetDisabled(false)
|
||||
self:SetText()
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.text:SetText(text)
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
else
|
||||
self.frame:Enable()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local name = "AceGUI30Button" .. AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Button", name, UIParent, "UIPanelButtonTemplate2")
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnClick", Button_OnClick)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
|
||||
local text = frame:GetFontString()
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("TOPLEFT", 15, -1)
|
||||
text:SetPoint("BOTTOMRIGHT", -15, 1)
|
||||
text:SetJustifyV("MIDDLE")
|
||||
|
||||
local widget = {
|
||||
text = text,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,289 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Checkbox Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "CheckBox", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local select, pairs = select, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: SetDesaturation, GameFontHighlight
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function AlignImage(self)
|
||||
local img = self.image:GetTexture()
|
||||
self.text:ClearAllPoints()
|
||||
if not img then
|
||||
self.text:SetPoint("LEFT", self.checkbg, "RIGHT")
|
||||
self.text:SetPoint("RIGHT")
|
||||
else
|
||||
self.text:SetPoint("LEFT", self.image,"RIGHT", 1, 0)
|
||||
self.text:SetPoint("RIGHT")
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function CheckBox_OnMouseDown(frame)
|
||||
local self = frame.obj
|
||||
if not self.disabled then
|
||||
if self.image:GetTexture() then
|
||||
self.text:SetPoint("LEFT", self.image,"RIGHT", 2, -1)
|
||||
else
|
||||
self.text:SetPoint("LEFT", self.checkbg, "RIGHT", 1, -1)
|
||||
end
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function CheckBox_OnMouseUp(frame)
|
||||
local self = frame.obj
|
||||
if not self.disabled then
|
||||
self:ToggleChecked()
|
||||
|
||||
if self.checked then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
else -- for both nil and false (tristate)
|
||||
PlaySound("igMainMenuOptionCheckBoxOff")
|
||||
end
|
||||
|
||||
self:Fire("OnValueChanged", self.checked)
|
||||
AlignImage(self)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetType()
|
||||
self:SetValue(false)
|
||||
self:SetTriState(nil)
|
||||
-- height is calculated from the width and required space for the description
|
||||
self:SetWidth(200)
|
||||
self:SetImage()
|
||||
self:SetDisabled(nil)
|
||||
self:SetDescription(nil)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
if self.desc then
|
||||
self.desc:SetWidth(width - 30)
|
||||
if self.desc:GetText() and self.desc:GetText() ~= "" then
|
||||
self:SetHeight(28 + self.desc:GetHeight())
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
self.text:SetTextColor(0.5, 0.5, 0.5)
|
||||
SetDesaturation(self.check, true)
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
if self.tristate and self.checked == nil then
|
||||
SetDesaturation(self.check, true)
|
||||
else
|
||||
SetDesaturation(self.check, false)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetValue"] = function(self,value)
|
||||
local check = self.check
|
||||
self.checked = value
|
||||
if value then
|
||||
SetDesaturation(self.check, false)
|
||||
self.check:Show()
|
||||
else
|
||||
--Nil is the unknown tristate value
|
||||
if self.tristate and value == nil then
|
||||
SetDesaturation(self.check, true)
|
||||
self.check:Show()
|
||||
else
|
||||
SetDesaturation(self.check, false)
|
||||
self.check:Hide()
|
||||
end
|
||||
end
|
||||
self:SetDisabled(self.disabled)
|
||||
end,
|
||||
|
||||
["GetValue"] = function(self)
|
||||
return self.checked
|
||||
end,
|
||||
|
||||
["SetTriState"] = function(self, enabled)
|
||||
self.tristate = enabled
|
||||
self:SetValue(self:GetValue())
|
||||
end,
|
||||
|
||||
["SetType"] = function(self, type)
|
||||
local checkbg = self.checkbg
|
||||
local check = self.check
|
||||
local highlight = self.highlight
|
||||
|
||||
local size
|
||||
if type == "radio" then
|
||||
size = 16
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
checkbg:SetTexCoord(0, 0.25, 0, 1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
check:SetTexCoord(0.25, 0.5, 0, 1)
|
||||
check:SetBlendMode("ADD")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-RadioButton")
|
||||
highlight:SetTexCoord(0.5, 0.75, 0, 1)
|
||||
else
|
||||
size = 24
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
|
||||
checkbg:SetTexCoord(0, 1, 0, 1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
check:SetTexCoord(0, 1, 0, 1)
|
||||
check:SetBlendMode("BLEND")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
|
||||
highlight:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
checkbg:SetHeight(size)
|
||||
checkbg:SetWidth(size)
|
||||
end,
|
||||
|
||||
["ToggleChecked"] = function(self)
|
||||
local value = self:GetValue()
|
||||
if self.tristate then
|
||||
--cycle in true, nil, false order
|
||||
if value then
|
||||
self:SetValue(nil)
|
||||
elseif value == nil then
|
||||
self:SetValue(false)
|
||||
else
|
||||
self:SetValue(true)
|
||||
end
|
||||
else
|
||||
self:SetValue(not self:GetValue())
|
||||
end
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, label)
|
||||
self.text:SetText(label)
|
||||
end,
|
||||
|
||||
["SetDescription"] = function(self, desc)
|
||||
if desc then
|
||||
if not self.desc then
|
||||
local desc = self.frame:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
||||
desc:ClearAllPoints()
|
||||
desc:SetPoint("TOPLEFT", self.checkbg, "TOPRIGHT", 5, -21)
|
||||
desc:SetWidth(self.frame.width - 30)
|
||||
desc:SetJustifyH("LEFT")
|
||||
desc:SetJustifyV("TOP")
|
||||
self.desc = desc
|
||||
end
|
||||
self.desc:Show()
|
||||
--self.text:SetFontObject(GameFontNormal)
|
||||
self.desc:SetText(desc)
|
||||
self:SetHeight(28 + self.desc:GetHeight())
|
||||
else
|
||||
if self.desc then
|
||||
self.desc:SetText("")
|
||||
self.desc:Hide()
|
||||
end
|
||||
--self.text:SetFontObject(GameFontHighlight)
|
||||
self:SetHeight(24)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, ...)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
local n = select("#", ...)
|
||||
if n == 4 or n == 8 then
|
||||
image:SetTexCoord(...)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end
|
||||
AlignImage(self)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnMouseDown", CheckBox_OnMouseDown)
|
||||
frame:SetScript("OnMouseUp", CheckBox_OnMouseUp)
|
||||
|
||||
local checkbg = frame:CreateTexture(nil, "ARTWORK")
|
||||
checkbg:SetWidth(24)
|
||||
checkbg:SetHeight(24)
|
||||
checkbg:SetPoint("TOPLEFT")
|
||||
checkbg:SetTexture("Interface\\Buttons\\UI-CheckBox-Up")
|
||||
|
||||
local check = frame:CreateTexture(nil, "OVERLAY")
|
||||
check:SetAllPoints(checkbg)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
|
||||
local text = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetHeight(18)
|
||||
text:SetPoint("LEFT", checkbg, "RIGHT")
|
||||
text:SetPoint("RIGHT")
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
|
||||
highlight:SetBlendMode("ADD")
|
||||
highlight:SetAllPoints(checkbg)
|
||||
|
||||
local image = frame:CreateTexture(nil, "OVERLAY")
|
||||
image:SetHeight(16)
|
||||
image:SetWidth(16)
|
||||
image:SetPoint("LEFT", checkbg, "RIGHT", 1, 0)
|
||||
|
||||
local widget = {
|
||||
checkbg = checkbg,
|
||||
check = check,
|
||||
text = text,
|
||||
highlight = highlight,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,186 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
ColorPicker Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "ColorPicker", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: ShowUIPanel, HideUIPanel, ColorPickerFrame, OpacitySliderFrame
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function ColorCallback(self, r, g, b, a, isAlpha)
|
||||
if not self.HasAlpha then
|
||||
a = 1
|
||||
end
|
||||
self:SetColor(r, g, b, a)
|
||||
if ColorPickerFrame:IsVisible() then
|
||||
--colorpicker is still open
|
||||
self:Fire("OnValueChanged", r, g, b, a)
|
||||
else
|
||||
--colorpicker is closed, color callback is first, ignore it,
|
||||
--alpha callback is the final call after it closes so confirm now
|
||||
if isAlpha then
|
||||
self:Fire("OnValueConfirmed", r, g, b, a)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function ColorSwatch_OnClick(frame)
|
||||
HideUIPanel(ColorPickerFrame)
|
||||
local self = frame.obj
|
||||
if not self.disabled then
|
||||
ColorPickerFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
ColorPickerFrame.func = function()
|
||||
local r, g, b = ColorPickerFrame:GetColorRGB()
|
||||
local a = 1 - OpacitySliderFrame:GetValue()
|
||||
ColorCallback(self, r, g, b, a)
|
||||
end
|
||||
|
||||
ColorPickerFrame.hasOpacity = self.HasAlpha
|
||||
ColorPickerFrame.opacityFunc = function()
|
||||
local r, g, b = ColorPickerFrame:GetColorRGB()
|
||||
local a = 1 - OpacitySliderFrame:GetValue()
|
||||
ColorCallback(self, r, g, b, a, true)
|
||||
end
|
||||
|
||||
local r, g, b, a = self.r, self.g, self.b, self.a
|
||||
if self.HasAlpha then
|
||||
ColorPickerFrame.opacity = 1 - (a or 0)
|
||||
end
|
||||
ColorPickerFrame:SetColorRGB(r, g, b)
|
||||
|
||||
ColorPickerFrame.cancelFunc = function()
|
||||
ColorCallback(self, r, g, b, a, true)
|
||||
end
|
||||
|
||||
ShowUIPanel(ColorPickerFrame)
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetHeight(24)
|
||||
self:SetWidth(200)
|
||||
self:SetHasAlpha(false)
|
||||
self:SetColor(0, 0, 0, 1)
|
||||
self:SetDisabled(nil)
|
||||
self:SetLabel(nil)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
self.text:SetText(text)
|
||||
end,
|
||||
|
||||
["SetColor"] = function(self, r, g, b, a)
|
||||
self.r = r
|
||||
self.g = g
|
||||
self.b = b
|
||||
self.a = a or 1
|
||||
self.colorSwatch:SetVertexColor(r, g, b, a)
|
||||
end,
|
||||
|
||||
["SetHasAlpha"] = function(self, HasAlpha)
|
||||
self.HasAlpha = HasAlpha
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if self.disabled then
|
||||
self.frame:Disable()
|
||||
self.text:SetTextColor(0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnClick", ColorSwatch_OnClick)
|
||||
|
||||
local colorSwatch = frame:CreateTexture(nil, "OVERLAY")
|
||||
colorSwatch:SetWidth(19)
|
||||
colorSwatch:SetHeight(19)
|
||||
colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")
|
||||
colorSwatch:SetPoint("LEFT")
|
||||
|
||||
local texture = frame:CreateTexture(nil, "BACKGROUND")
|
||||
texture:SetWidth(16)
|
||||
texture:SetHeight(16)
|
||||
texture:SetTexture(1, 1, 1)
|
||||
texture:SetPoint("CENTER", colorSwatch)
|
||||
texture:Show()
|
||||
|
||||
local checkers = frame:CreateTexture(nil, "BACKGROUND")
|
||||
checkers:SetWidth(14)
|
||||
checkers:SetHeight(14)
|
||||
checkers:SetTexture("Tileset\\Generic\\Checkers")
|
||||
checkers:SetTexCoord(.25, 0, 0.5, .25)
|
||||
checkers:SetDesaturated(true)
|
||||
checkers:SetVertexColor(1, 1, 1, 0.75)
|
||||
checkers:SetPoint("CENTER", colorSwatch)
|
||||
checkers:Show()
|
||||
|
||||
local text = frame:CreateFontString(nil,"OVERLAY","GameFontHighlight")
|
||||
text:SetHeight(24)
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetTextColor(1, 1, 1)
|
||||
text:SetPoint("LEFT", colorSwatch, "RIGHT", 2, 0)
|
||||
text:SetPoint("RIGHT")
|
||||
|
||||
--local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
--highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||||
--highlight:SetBlendMode("ADD")
|
||||
--highlight:SetAllPoints(frame)
|
||||
|
||||
local widget = {
|
||||
colorSwatch = colorSwatch,
|
||||
text = text,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,465 @@
|
||||
--[[ $Id: AceGUIWidget-DropDown-Items.lua 916 2010-03-15 12:24:36Z nevcairiel $ ]]--
|
||||
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local select, assert = select, assert
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame = CreateFrame
|
||||
|
||||
local function fixlevels(parent,...)
|
||||
local i = 1
|
||||
local child = select(i, ...)
|
||||
while child do
|
||||
child:SetFrameLevel(parent:GetFrameLevel()+1)
|
||||
fixlevels(child, child:GetChildren())
|
||||
i = i + 1
|
||||
child = select(i, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function fixstrata(strata, parent, ...)
|
||||
local i = 1
|
||||
local child = select(i, ...)
|
||||
parent:SetFrameStrata(strata)
|
||||
while child do
|
||||
fixstrata(strata, child, child:GetChildren())
|
||||
i = i + 1
|
||||
child = select(i, ...)
|
||||
end
|
||||
end
|
||||
|
||||
-- ItemBase is the base "class" for all dropdown items.
|
||||
-- Each item has to use ItemBase.Create(widgetType) to
|
||||
-- create an initial 'self' value.
|
||||
-- ItemBase will add common functions and ui event handlers.
|
||||
-- Be sure to keep basic usage when you override functions.
|
||||
|
||||
local ItemBase = {
|
||||
-- NOTE: The ItemBase version is added to each item's version number
|
||||
-- to ensure proper updates on ItemBase changes.
|
||||
-- Use at least 1000er steps.
|
||||
version = 1000,
|
||||
counter = 0,
|
||||
}
|
||||
|
||||
function ItemBase.Frame_OnEnter(this)
|
||||
local self = this.obj
|
||||
|
||||
if self.useHighlight then
|
||||
self.highlight:Show()
|
||||
end
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
end
|
||||
|
||||
function ItemBase.Frame_OnLeave(this)
|
||||
local self = this.obj
|
||||
|
||||
self.highlight:Hide()
|
||||
self:Fire("OnLeave")
|
||||
|
||||
if self.specialOnLeave then
|
||||
self.specialOnLeave(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
function ItemBase.OnAcquire(self)
|
||||
self.frame:SetToplevel(true)
|
||||
self.frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
function ItemBase.OnRelease(self)
|
||||
self:SetDisabled(false)
|
||||
self.pullout = nil
|
||||
self.frame:SetParent(nil)
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetPullout(self, pullout)
|
||||
self.pullout = pullout
|
||||
|
||||
self.frame:SetParent(nil)
|
||||
self.frame:SetParent(pullout.itemFrame)
|
||||
self.parent = pullout.itemFrame
|
||||
fixlevels(pullout.itemFrame, pullout.itemFrame:GetChildren())
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetText(self, text)
|
||||
self.text:SetText(text or "")
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.GetText(self)
|
||||
return self.text:GetText()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetPoint(self, ...)
|
||||
self.frame:SetPoint(...)
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.Show(self)
|
||||
self.frame:Show()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.Hide(self)
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
function ItemBase.SetDisabled(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.useHighlight = false
|
||||
self.text:SetTextColor(.5, .5, .5)
|
||||
else
|
||||
self.useHighlight = true
|
||||
self.text:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetOnLeave(self, func)
|
||||
self.specialOnLeave = func
|
||||
end
|
||||
|
||||
-- exported
|
||||
-- NOTE: this is called by a Dropdown-Pullout.
|
||||
-- Do not call this method directly
|
||||
function ItemBase.SetOnEnter(self, func)
|
||||
self.specialOnEnter = func
|
||||
end
|
||||
|
||||
function ItemBase.Create(type)
|
||||
-- NOTE: Most of the following code is copied from AceGUI-3.0/Dropdown widget
|
||||
local count = AceGUI:GetNextWidgetNum(type)
|
||||
local frame = CreateFrame("Button", "AceGUI30DropDownItem"..count)
|
||||
local self = {}
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
self.type = type
|
||||
|
||||
self.useHighlight = true
|
||||
|
||||
frame:SetHeight(17)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
local text = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
|
||||
text:SetTextColor(1,1,1)
|
||||
text:SetJustifyH("LEFT")
|
||||
text:SetPoint("TOPLEFT",frame,"TOPLEFT",18,0)
|
||||
text:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",-8,0)
|
||||
self.text = text
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "OVERLAY")
|
||||
highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||||
highlight:SetBlendMode("ADD")
|
||||
highlight:SetHeight(14)
|
||||
highlight:ClearAllPoints()
|
||||
highlight:SetPoint("RIGHT",frame,"RIGHT",-3,0)
|
||||
highlight:SetPoint("LEFT",frame,"LEFT",5,0)
|
||||
highlight:Hide()
|
||||
self.highlight = highlight
|
||||
|
||||
local check = frame:CreateTexture("OVERLAY")
|
||||
check:SetWidth(16)
|
||||
check:SetHeight(16)
|
||||
check:SetPoint("LEFT",frame,"LEFT",3,-1)
|
||||
check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||||
check:Hide()
|
||||
self.check = check
|
||||
|
||||
local sub = frame:CreateTexture("OVERLAY")
|
||||
sub:SetWidth(16)
|
||||
sub:SetHeight(16)
|
||||
sub:SetPoint("RIGHT",frame,"RIGHT",-3,-1)
|
||||
sub:SetTexture("Interface\\ChatFrame\\ChatFrameExpandArrow")
|
||||
sub:Hide()
|
||||
self.sub = sub
|
||||
|
||||
frame:SetScript("OnEnter", ItemBase.Frame_OnEnter)
|
||||
frame:SetScript("OnLeave", ItemBase.Frame_OnLeave)
|
||||
|
||||
self.OnAcquire = ItemBase.OnAcquire
|
||||
self.OnRelease = ItemBase.OnRelease
|
||||
|
||||
self.SetPullout = ItemBase.SetPullout
|
||||
self.GetText = ItemBase.GetText
|
||||
self.SetText = ItemBase.SetText
|
||||
self.SetDisabled = ItemBase.SetDisabled
|
||||
|
||||
self.SetPoint = ItemBase.SetPoint
|
||||
self.Show = ItemBase.Show
|
||||
self.Hide = ItemBase.Hide
|
||||
|
||||
self.SetOnLeave = ItemBase.SetOnLeave
|
||||
self.SetOnEnter = ItemBase.SetOnEnter
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--[[
|
||||
Template for items:
|
||||
|
||||
-- Item:
|
||||
--
|
||||
do
|
||||
local widgetType = "Dropdown-Item-"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
--]]
|
||||
|
||||
-- Item: Header
|
||||
-- A single text entry.
|
||||
-- Special: Different text color and no highlight
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Header"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function OnEnter(this)
|
||||
local self = this.obj
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnLeave(this)
|
||||
local self = this.obj
|
||||
self:Fire("OnLeave")
|
||||
|
||||
if self.specialOnLeave then
|
||||
self.specialOnLeave(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, override
|
||||
local function SetDisabled(self, disabled)
|
||||
ItemBase.SetDisabled(self, disabled)
|
||||
if not disabled then
|
||||
self.text:SetTextColor(1, 1, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.SetDisabled = SetDisabled
|
||||
|
||||
self.frame:SetScript("OnEnter", OnEnter)
|
||||
self.frame:SetScript("OnLeave", OnLeave)
|
||||
|
||||
self.text:SetTextColor(1, 1, 0)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Execute
|
||||
-- A simple button
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Execute"
|
||||
local widgetVersion = 1
|
||||
|
||||
local function Frame_OnClick(this, button)
|
||||
local self = this.obj
|
||||
if self.disabled then return end
|
||||
self:Fire("OnClick")
|
||||
if self.pullout then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.frame:SetScript("OnClick", Frame_OnClick)
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Toggle
|
||||
-- Some sort of checkbox for dropdown menus.
|
||||
-- Does not close the pullout on click.
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Toggle"
|
||||
local widgetVersion = 3
|
||||
|
||||
local function UpdateToggle(self)
|
||||
if self.value then
|
||||
self.check:Show()
|
||||
else
|
||||
self.check:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnRelease(self)
|
||||
ItemBase.OnRelease(self)
|
||||
self:SetValue(nil)
|
||||
end
|
||||
|
||||
local function Frame_OnClick(this, button)
|
||||
local self = this.obj
|
||||
if self.disabled then return end
|
||||
self.value = not self.value
|
||||
if self.value then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
else
|
||||
PlaySound("igMainMenuOptionCheckBoxOff")
|
||||
end
|
||||
UpdateToggle(self)
|
||||
self:Fire("OnValueChanged", self.value)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetValue(self, value)
|
||||
self.value = value
|
||||
UpdateToggle(self)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetValue(self)
|
||||
return self.value
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.frame:SetScript("OnClick", Frame_OnClick)
|
||||
|
||||
self.SetValue = SetValue
|
||||
self.GetValue = GetValue
|
||||
self.OnRelease = OnRelease
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Menu
|
||||
-- Shows a submenu on mouse over
|
||||
-- Does not close the pullout on click
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Menu"
|
||||
local widgetVersion = 2
|
||||
|
||||
local function OnEnter(this)
|
||||
local self = this.obj
|
||||
self:Fire("OnEnter")
|
||||
|
||||
if self.specialOnEnter then
|
||||
self.specialOnEnter(self)
|
||||
end
|
||||
|
||||
self.highlight:Show()
|
||||
|
||||
if not self.disabled and self.submenu then
|
||||
self.submenu:Open("TOPLEFT", self.frame, "TOPRIGHT", self.pullout:GetRightBorderWidth(), 0, self.frame:GetFrameLevel() + 100)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnHide(this)
|
||||
local self = this.obj
|
||||
if self.submenu then
|
||||
self.submenu:Close()
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMenu(self, menu)
|
||||
assert(menu.type == "Dropdown-Pullout")
|
||||
self.submenu = menu
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function CloseMenu(self)
|
||||
self.submenu:Close()
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.sub:Show()
|
||||
|
||||
self.frame:SetScript("OnEnter", OnEnter)
|
||||
self.frame:SetScript("OnHide", OnHide)
|
||||
|
||||
self.SetMenu = SetMenu
|
||||
self.CloseMenu = CloseMenu
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
|
||||
-- Item: Separator
|
||||
-- A single line to separate items
|
||||
do
|
||||
local widgetType = "Dropdown-Item-Separator"
|
||||
local widgetVersion = 1
|
||||
|
||||
-- exported, override
|
||||
local function SetDisabled(self, disabled)
|
||||
ItemBase.SetDisabled(self, disabled)
|
||||
self.useHighlight = false
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local self = ItemBase.Create(widgetType)
|
||||
|
||||
self.SetDisabled = SetDisabled
|
||||
|
||||
local line = self.frame:CreateTexture(nil, "OVERLAY")
|
||||
line:SetHeight(1)
|
||||
line:SetTexture(.5, .5, .5)
|
||||
line:SetPoint("LEFT", self.frame, "LEFT", 10, 0)
|
||||
line:SetPoint("RIGHT", self.frame, "RIGHT", -10, 0)
|
||||
|
||||
self.text:Hide()
|
||||
|
||||
self.useHighlight = false
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion + ItemBase.version)
|
||||
end
|
||||
@@ -0,0 +1,707 @@
|
||||
--[[ $Id: AceGUIWidget-DropDown.lua 916 2010-03-15 12:24:36Z nevcairiel $ ]]--
|
||||
local AceGUI = LibStub("AceGUI-3.0")
|
||||
|
||||
-- Lua APIs
|
||||
local min, max, floor = math.min, math.max, math.floor
|
||||
local select, pairs, ipairs = select, pairs, ipairs
|
||||
local tsort = table.sort
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local UIParent, CreateFrame = UIParent, CreateFrame
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: CLOSE
|
||||
|
||||
local function fixlevels(parent,...)
|
||||
local i = 1
|
||||
local child = select(i, ...)
|
||||
while child do
|
||||
child:SetFrameLevel(parent:GetFrameLevel()+1)
|
||||
fixlevels(child, child:GetChildren())
|
||||
i = i + 1
|
||||
child = select(i, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local function fixstrata(strata, parent, ...)
|
||||
local i = 1
|
||||
local child = select(i, ...)
|
||||
parent:SetFrameStrata(strata)
|
||||
while child do
|
||||
fixstrata(strata, child, child:GetChildren())
|
||||
i = i + 1
|
||||
child = select(i, ...)
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local widgetType = "Dropdown-Pullout"
|
||||
local widgetVersion = 3
|
||||
|
||||
--[[ Static data ]]--
|
||||
|
||||
local backdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||||
edgeSize = 32,
|
||||
tileSize = 32,
|
||||
tile = true,
|
||||
insets = { left = 11, right = 12, top = 12, bottom = 11 },
|
||||
}
|
||||
local sliderBackdrop = {
|
||||
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
|
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
||||
tile = true, tileSize = 8, edgeSize = 8,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||||
}
|
||||
|
||||
local defaultWidth = 200
|
||||
local defaultMaxHeight = 600
|
||||
|
||||
--[[ UI Event Handlers ]]--
|
||||
|
||||
-- HACK: This should be no part of the pullout, but there
|
||||
-- is no other 'clean' way to response to any item-OnEnter
|
||||
-- Used to close Submenus when an other item is entered
|
||||
local function OnEnter(item)
|
||||
local self = item.pullout
|
||||
for k, v in ipairs(self.items) do
|
||||
if v.CloseMenu and v ~= item then
|
||||
v:CloseMenu()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- See the note in Constructor() for each scroll related function
|
||||
local function OnMouseWheel(this, value)
|
||||
this.obj:MoveScroll(value)
|
||||
end
|
||||
|
||||
local function OnScrollValueChanged(this, value)
|
||||
this.obj:SetScroll(value)
|
||||
end
|
||||
|
||||
local function OnSizeChanged(this)
|
||||
this.obj:FixScroll()
|
||||
end
|
||||
|
||||
--[[ Exported methods ]]--
|
||||
|
||||
-- exported
|
||||
local function SetScroll(self, value)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
|
||||
local offset
|
||||
if height > viewheight then
|
||||
offset = 0
|
||||
else
|
||||
offset = floor((viewheight - height) / 1000 * value)
|
||||
end
|
||||
child:ClearAllPoints()
|
||||
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
|
||||
status.offset = offset
|
||||
status.scrollvalue = value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function MoveScroll(self, value)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
|
||||
if height > viewheight then
|
||||
self.slider:Hide()
|
||||
else
|
||||
self.slider:Show()
|
||||
local diff = height - viewheight
|
||||
local delta = 1
|
||||
if value < 0 then
|
||||
delta = -1
|
||||
end
|
||||
self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function FixScroll(self)
|
||||
local status = self.scrollStatus
|
||||
local frame, child = self.scrollFrame, self.itemFrame
|
||||
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
||||
local offset = status.offset or 0
|
||||
|
||||
if viewheight < height then
|
||||
self.slider:Hide()
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
|
||||
self.slider:SetValue(0)
|
||||
else
|
||||
self.slider:Show()
|
||||
local value = (offset / (viewheight - height) * 1000)
|
||||
if value > 1000 then value = 1000 end
|
||||
self.slider:SetValue(value)
|
||||
self:SetScroll(value)
|
||||
if value < 1000 then
|
||||
child:ClearAllPoints()
|
||||
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
||||
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
|
||||
status.offset = offset
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnAcquire(self)
|
||||
self.frame:SetParent(UIParent)
|
||||
--self.itemFrame:SetToplevel(true)
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnRelease(self)
|
||||
self:Clear()
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function AddItem(self, item)
|
||||
self.items[#self.items + 1] = item
|
||||
|
||||
local h = #self.items * 16
|
||||
self.itemFrame:SetHeight(h)
|
||||
self.frame:SetHeight(min(h + 34, self.maxHeight)) -- +34: 20 for scrollFrame placement (10 offset) and +14 for item placement
|
||||
|
||||
item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
|
||||
item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
|
||||
|
||||
item:SetPullout(self)
|
||||
item:SetOnEnter(OnEnter)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Open(self, point, relFrame, relPoint, x, y)
|
||||
local items = self.items
|
||||
local frame = self.frame
|
||||
local itemFrame = self.itemFrame
|
||||
|
||||
frame:SetPoint(point, relFrame, relPoint, x, y)
|
||||
|
||||
|
||||
local height = 8
|
||||
for i, item in pairs(items) do
|
||||
if i == 1 then
|
||||
item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
|
||||
else
|
||||
item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
|
||||
end
|
||||
|
||||
item:Show()
|
||||
|
||||
height = height + 16
|
||||
end
|
||||
itemFrame:SetHeight(height)
|
||||
fixstrata("TOOLTIP", frame, frame:GetChildren())
|
||||
frame:Show()
|
||||
self:Fire("OnOpen")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Close(self)
|
||||
self.frame:Hide()
|
||||
self:Fire("OnClose")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function Clear(self)
|
||||
local items = self.items
|
||||
for i, item in pairs(items) do
|
||||
AceGUI:Release(item)
|
||||
items[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function IterateItems(self)
|
||||
return ipairs(self.items)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetHideOnLeave(self, val)
|
||||
self.hideOnLeave = val
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMaxHeight(self, height)
|
||||
self.maxHeight = height or defaultMaxHeight
|
||||
if self.frame:GetHeight() > height then
|
||||
self.frame:SetHeight(height)
|
||||
elseif (self.itemFrame:GetHeight() + 34) < height then
|
||||
self.frame:SetHeight(self.itemFrame:GetHeight() + 34) -- see :AddItem
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetRightBorderWidth(self)
|
||||
return 6 + (self.slider:IsShown() and 12 or 0)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetLeftBorderWidth(self)
|
||||
return 6
|
||||
end
|
||||
|
||||
--[[ Constructor ]]--
|
||||
|
||||
local function Constructor()
|
||||
local count = AceGUI:GetNextWidgetNum(widgetType)
|
||||
local frame = CreateFrame("Frame", "AceGUI30Pullout"..count, UIParent)
|
||||
local self = {}
|
||||
self.count = count
|
||||
self.type = widgetType
|
||||
self.frame = frame
|
||||
frame.obj = self
|
||||
|
||||
self.OnAcquire = OnAcquire
|
||||
self.OnRelease = OnRelease
|
||||
|
||||
self.AddItem = AddItem
|
||||
self.Open = Open
|
||||
self.Close = Close
|
||||
self.Clear = Clear
|
||||
self.IterateItems = IterateItems
|
||||
self.SetHideOnLeave = SetHideOnLeave
|
||||
|
||||
self.SetScroll = SetScroll
|
||||
self.MoveScroll = MoveScroll
|
||||
self.FixScroll = FixScroll
|
||||
|
||||
self.SetMaxHeight = SetMaxHeight
|
||||
self.GetRightBorderWidth = GetRightBorderWidth
|
||||
self.GetLeftBorderWidth = GetLeftBorderWidth
|
||||
|
||||
self.items = {}
|
||||
|
||||
self.scrollStatus = {
|
||||
scrollvalue = 0,
|
||||
}
|
||||
|
||||
self.maxHeight = defaultMaxHeight
|
||||
|
||||
frame:SetBackdrop(backdrop)
|
||||
frame:SetBackdropColor(0, 0, 0)
|
||||
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
frame:SetClampedToScreen(true)
|
||||
frame:SetWidth(defaultWidth)
|
||||
frame:SetHeight(self.maxHeight)
|
||||
--frame:SetToplevel(true)
|
||||
|
||||
-- NOTE: The whole scroll frame code is copied from the AceGUI-3.0 widget ScrollFrame
|
||||
local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
|
||||
local itemFrame = CreateFrame("Frame", nil, scrollFrame)
|
||||
|
||||
self.scrollFrame = scrollFrame
|
||||
self.itemFrame = itemFrame
|
||||
|
||||
scrollFrame.obj = self
|
||||
itemFrame.obj = self
|
||||
|
||||
local slider = CreateFrame("Slider", "AceGUI30PulloutScrollbar"..count, scrollFrame)
|
||||
slider:SetOrientation("VERTICAL")
|
||||
slider:SetHitRectInsets(0, 0, -10, 0)
|
||||
slider:SetBackdrop(sliderBackdrop)
|
||||
slider:SetWidth(8)
|
||||
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
|
||||
slider:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
self.slider = slider
|
||||
slider.obj = self
|
||||
|
||||
scrollFrame:SetScrollChild(itemFrame)
|
||||
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 6, -12)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -6, 12)
|
||||
scrollFrame:EnableMouseWheel(true)
|
||||
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
|
||||
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
|
||||
scrollFrame:SetToplevel(true)
|
||||
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
|
||||
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
|
||||
itemFrame:SetHeight(400)
|
||||
itemFrame:SetToplevel(true)
|
||||
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
|
||||
slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
|
||||
slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
|
||||
slider:SetScript("OnValueChanged", OnScrollValueChanged)
|
||||
slider:SetMinMaxValues(0, 1000)
|
||||
slider:SetValueStep(1)
|
||||
slider:SetValue(0)
|
||||
|
||||
scrollFrame:Show()
|
||||
itemFrame:Show()
|
||||
slider:Hide()
|
||||
|
||||
self:FixScroll()
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
|
||||
end
|
||||
|
||||
do
|
||||
local widgetType = "Dropdown"
|
||||
local widgetVersion = 22
|
||||
|
||||
--[[ Static data ]]--
|
||||
|
||||
--[[ UI event handler ]]--
|
||||
|
||||
local function Control_OnEnter(this)
|
||||
this.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(this)
|
||||
this.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Dropdown_OnHide(this)
|
||||
local self = this.obj
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
local function Dropdown_TogglePullout(this)
|
||||
local self = this.obj
|
||||
PlaySound("igMainMenuOptionCheckBoxOn") -- missleading name, but the Blizzard code uses this sound
|
||||
if self.open then
|
||||
self.open = nil
|
||||
self.pullout:Close()
|
||||
AceGUI:ClearFocus()
|
||||
else
|
||||
self.open = true
|
||||
self.pullout:SetWidth(self.frame:GetWidth())
|
||||
self.pullout:Open("TOPLEFT", self.frame, "BOTTOMLEFT", 0, self.label:IsShown() and -2 or 0)
|
||||
AceGUI:SetFocus(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function OnPulloutOpen(this)
|
||||
local self = this.userdata.obj
|
||||
local value = self.value
|
||||
|
||||
if not self.multiselect then
|
||||
for i, item in this:IterateItems() do
|
||||
item:SetValue(item.userdata.value == value)
|
||||
end
|
||||
end
|
||||
|
||||
self.open = true
|
||||
end
|
||||
|
||||
local function OnPulloutClose(this)
|
||||
local self = this.userdata.obj
|
||||
self.open = nil
|
||||
self:Fire("OnClosed")
|
||||
end
|
||||
|
||||
local function ShowMultiText(self)
|
||||
local text
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.type == "Dropdown-Item-Toggle" then
|
||||
if widget:GetValue() then
|
||||
if text then
|
||||
text = text..", "..widget:GetText()
|
||||
else
|
||||
text = widget:GetText()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self:SetText(text)
|
||||
end
|
||||
|
||||
local function OnItemValueChanged(this, event, checked)
|
||||
local self = this.userdata.obj
|
||||
|
||||
if self.multiselect then
|
||||
self:Fire("OnValueChanged", this.userdata.value, checked)
|
||||
ShowMultiText(self)
|
||||
else
|
||||
if checked then
|
||||
self:SetValue(this.userdata.value)
|
||||
self:Fire("OnValueChanged", this.userdata.value)
|
||||
else
|
||||
this:SetValue(true)
|
||||
end
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Exported methods ]]--
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnAcquire(self)
|
||||
local pullout = AceGUI:Create("Dropdown-Pullout")
|
||||
self.pullout = pullout
|
||||
pullout.userdata.obj = self
|
||||
pullout:SetCallback("OnClose", OnPulloutClose)
|
||||
pullout:SetCallback("OnOpen", OnPulloutOpen)
|
||||
self.pullout.frame:SetFrameLevel(self.frame:GetFrameLevel() + 1)
|
||||
fixlevels(self.pullout.frame, self.pullout.frame:GetChildren())
|
||||
|
||||
self:SetHeight(44)
|
||||
self:SetWidth(200)
|
||||
end
|
||||
|
||||
-- exported, AceGUI callback
|
||||
local function OnRelease(self)
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
AceGUI:Release(self.pullout)
|
||||
self.pullout = nil
|
||||
|
||||
self:SetText("")
|
||||
self:SetLabel("")
|
||||
self:SetDisabled(false)
|
||||
self:SetMultiselect(false)
|
||||
|
||||
self.value = nil
|
||||
self.list = nil
|
||||
self.open = nil
|
||||
self.hasClose = nil
|
||||
|
||||
self.frame:ClearAllPoints()
|
||||
self.frame:Hide()
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetDisabled(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.text:SetTextColor(0.5,0.5,0.5)
|
||||
self.button:Disable()
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.button:Enable()
|
||||
self.label:SetTextColor(1,.82,0)
|
||||
self.text:SetTextColor(1,1,1)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function ClearFocus(self)
|
||||
if self.open then
|
||||
self.pullout:Close()
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetText(self, text)
|
||||
self.text:SetText(text or "")
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetLabel(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
self.label:Show()
|
||||
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,-18)
|
||||
self.frame:SetHeight(44)
|
||||
else
|
||||
self.label:SetText("")
|
||||
self.label:Hide()
|
||||
self.dropdown:SetPoint("TOPLEFT",self.frame,"TOPLEFT",-15,0)
|
||||
self.frame:SetHeight(26)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetValue(self, value)
|
||||
if self.list then
|
||||
self:SetText(self.list[value] or "")
|
||||
end
|
||||
self.value = value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetValue(self)
|
||||
return self.value
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetItemValue(self, item, value)
|
||||
if not self.multiselect then return end
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.userdata.value == item then
|
||||
if widget.SetValue then
|
||||
widget:SetValue(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
ShowMultiText(self)
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetItemDisabled(self, item, disabled)
|
||||
for i, widget in self.pullout:IterateItems() do
|
||||
if widget.userdata.value == item then
|
||||
widget:SetDisabled(disabled)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function AddListItem(self, value, text)
|
||||
local item = AceGUI:Create("Dropdown-Item-Toggle")
|
||||
item:SetText(text)
|
||||
item.userdata.obj = self
|
||||
item.userdata.value = value
|
||||
item:SetCallback("OnValueChanged", OnItemValueChanged)
|
||||
self.pullout:AddItem(item)
|
||||
end
|
||||
|
||||
local function AddCloseButton(self)
|
||||
if not self.hasClose then
|
||||
local close = AceGUI:Create("Dropdown-Item-Execute")
|
||||
close:SetText(CLOSE)
|
||||
self.pullout:AddItem(close)
|
||||
self.hasClose = true
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local sortlist = {}
|
||||
local function SetList(self, list)
|
||||
self.list = list
|
||||
self.pullout:Clear()
|
||||
self.hasClose = nil
|
||||
if not list then return end
|
||||
|
||||
for v in pairs(list) do
|
||||
sortlist[#sortlist + 1] = v
|
||||
end
|
||||
tsort(sortlist)
|
||||
|
||||
for i, value in pairs(sortlist) do
|
||||
AddListItem(self, value, list[value])
|
||||
sortlist[i] = nil
|
||||
end
|
||||
if self.multiselect then
|
||||
ShowMultiText(self)
|
||||
AddCloseButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function AddItem(self, value, text)
|
||||
if self.list then
|
||||
self.list[value] = text
|
||||
AddListItem(self, value, text)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function SetMultiselect(self, multi)
|
||||
self.multiselect = multi
|
||||
if multi then
|
||||
ShowMultiText(self)
|
||||
AddCloseButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
-- exported
|
||||
local function GetMultiselect(self)
|
||||
return self.multiselect
|
||||
end
|
||||
|
||||
--[[ Constructor ]]--
|
||||
|
||||
local function Constructor()
|
||||
local count = AceGUI:GetNextWidgetNum(widgetType)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local dropdown = CreateFrame("Frame", "AceGUI30DropDown"..count, frame, "UIDropDownMenuTemplate")
|
||||
|
||||
local self = {}
|
||||
self.type = widgetType
|
||||
self.frame = frame
|
||||
self.dropdown = dropdown
|
||||
self.count = count
|
||||
frame.obj = self
|
||||
dropdown.obj = self
|
||||
|
||||
self.OnRelease = OnRelease
|
||||
self.OnAcquire = OnAcquire
|
||||
|
||||
self.ClearFocus = ClearFocus
|
||||
|
||||
self.SetText = SetText
|
||||
self.SetValue = SetValue
|
||||
self.GetValue = GetValue
|
||||
self.SetList = SetList
|
||||
self.SetLabel = SetLabel
|
||||
self.SetDisabled = SetDisabled
|
||||
self.AddItem = AddItem
|
||||
self.SetMultiselect = SetMultiselect
|
||||
self.GetMultiselect = GetMultiselect
|
||||
self.SetItemValue = SetItemValue
|
||||
self.SetItemDisabled = SetItemDisabled
|
||||
|
||||
self.alignoffset = 31
|
||||
|
||||
frame:SetHeight(44)
|
||||
frame:SetWidth(200)
|
||||
frame:SetScript("OnHide",Dropdown_OnHide)
|
||||
|
||||
dropdown:ClearAllPoints()
|
||||
dropdown:SetPoint("TOPLEFT",frame,"TOPLEFT",-15,0)
|
||||
dropdown:SetPoint("BOTTOMRIGHT",frame,"BOTTOMRIGHT",17,0)
|
||||
dropdown:SetScript("OnHide", nil)
|
||||
|
||||
local left = _G[dropdown:GetName() .. "Left"]
|
||||
local middle = _G[dropdown:GetName() .. "Middle"]
|
||||
local right = _G[dropdown:GetName() .. "Right"]
|
||||
|
||||
middle:ClearAllPoints()
|
||||
right:ClearAllPoints()
|
||||
|
||||
middle:SetPoint("LEFT", left, "RIGHT", 0, 0)
|
||||
middle:SetPoint("RIGHT", right, "LEFT", 0, 0)
|
||||
right:SetPoint("TOPRIGHT", dropdown, "TOPRIGHT", 0, 17)
|
||||
|
||||
local button = _G[dropdown:GetName() .. "Button"]
|
||||
self.button = button
|
||||
button.obj = self
|
||||
button:SetScript("OnEnter",Control_OnEnter)
|
||||
button:SetScript("OnLeave",Control_OnLeave)
|
||||
button:SetScript("OnClick",Dropdown_TogglePullout)
|
||||
|
||||
local text = _G[dropdown:GetName() .. "Text"]
|
||||
self.text = text
|
||||
text.obj = self
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("RIGHT", right, "RIGHT" ,-43, 2)
|
||||
text:SetPoint("LEFT", left, "LEFT", 25, 2)
|
||||
|
||||
local label = frame:CreateFontString(nil,"OVERLAY","GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT",frame,"TOPLEFT",0,0)
|
||||
label:SetPoint("TOPRIGHT",frame,"TOPRIGHT",0,0)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetHeight(18)
|
||||
label:Hide()
|
||||
self.label = label
|
||||
|
||||
AceGUI:RegisterAsWidget(self)
|
||||
return self
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(widgetType, Constructor, widgetVersion)
|
||||
end
|
||||
@@ -0,0 +1,235 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
EditBox Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "EditBox", 22
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local tostring, pairs = tostring, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local GetCursorInfo, ClearCursor, GetSpellName = GetCursorInfo, ClearCursor, GetSpellName
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: AceGUIEditBoxInsertLink, ChatFontNormal, OKAY
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
if not AceGUIEditBoxInsertLink then
|
||||
-- upgradeable hook
|
||||
hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIEditBoxInsertLink(...) end)
|
||||
end
|
||||
|
||||
function _G.AceGUIEditBoxInsertLink(text)
|
||||
for i = 1, AceGUI:GetWidgetCount(Type) do
|
||||
local editbox = _G["AceGUI-3.0EditBox"..i]
|
||||
if editbox and editbox:IsVisible() and editbox:HasFocus() then
|
||||
editbox:Insert(text)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function ShowButton(self)
|
||||
if not self.disablebutton then
|
||||
self.button:Show()
|
||||
self.editbox:SetTextInsets(0, 20, 3, 3)
|
||||
end
|
||||
end
|
||||
|
||||
local function HideButton(self)
|
||||
self.button:Hide()
|
||||
self.editbox:SetTextInsets(0, 0, 3, 3)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function EditBox_OnEscapePressed(frame)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function EditBox_OnEnterPressed(frame)
|
||||
local self = frame.obj
|
||||
local value = frame:GetText()
|
||||
local cancel = self:Fire("OnEnterPressed", value)
|
||||
if not cancel then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
HideButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnReceiveDrag(frame)
|
||||
local self = frame.obj
|
||||
local type, id, info = GetCursorInfo()
|
||||
if type == "item" then
|
||||
self:SetText(info)
|
||||
self:Fire("OnEnterPressed", info)
|
||||
ClearCursor()
|
||||
elseif type == "spell" then
|
||||
local name, rank = GetSpellName(id, info)
|
||||
if rank and rank:match("%d") then
|
||||
name = name.."("..rank..")"
|
||||
end
|
||||
self:SetText(name)
|
||||
self:Fire("OnEnterPressed", name)
|
||||
ClearCursor()
|
||||
end
|
||||
HideButton(self)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function EditBox_OnTextChanged(frame)
|
||||
local self = frame.obj
|
||||
local value = frame:GetText()
|
||||
if tostring(value) ~= tostring(self.lasttext) then
|
||||
self:Fire("OnTextChanged", value)
|
||||
self.lasttext = value
|
||||
ShowButton(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function Button_OnClick(frame)
|
||||
local editbox = frame.obj.editbox
|
||||
editbox:ClearFocus()
|
||||
EditBox_OnEnterPressed(editbox)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- height is controlled by SetLabel
|
||||
self:SetWidth(200)
|
||||
self:SetDisabled(false)
|
||||
self:SetLabel()
|
||||
self:SetText()
|
||||
self:DisableButton(false)
|
||||
self:SetMaxLetters(0)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.editbox:EnableMouse(false)
|
||||
self.editbox:ClearFocus()
|
||||
self.editbox:SetTextColor(0.5,0.5,0.5)
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.editbox:EnableMouse(true)
|
||||
self.editbox:SetTextColor(1,1,1)
|
||||
self.label:SetTextColor(1,.82,0)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.lasttext = text or ""
|
||||
self.editbox:SetText(text or "")
|
||||
self.editbox:SetCursorPosition(0)
|
||||
HideButton(self)
|
||||
end,
|
||||
|
||||
["GetText"] = function(self, text)
|
||||
return self.editbox:GetText()
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
self.label:Show()
|
||||
self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,-18)
|
||||
self:SetHeight(44)
|
||||
self.alignoffset = 30
|
||||
else
|
||||
self.label:SetText("")
|
||||
self.label:Hide()
|
||||
self.editbox:SetPoint("TOPLEFT",self.frame,"TOPLEFT",7,0)
|
||||
self:SetHeight(26)
|
||||
self.alignoffset = 12
|
||||
end
|
||||
end,
|
||||
|
||||
["DisableButton"] = function(self, disabled)
|
||||
self.disablebutton = disabled
|
||||
if disabled then
|
||||
HideButton(self)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetMaxLetters"] = function (self, num)
|
||||
self.editbox:SetMaxLetters(num or 0)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local num = AceGUI:GetNextWidgetNum(Type)
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local editbox = CreateFrame("EditBox", "AceGUI-3.0EditBox"..num, frame, "InputBoxTemplate")
|
||||
editbox:SetAutoFocus(false)
|
||||
editbox:SetFontObject(ChatFontNormal)
|
||||
editbox:SetScript("OnEnter", Control_OnEnter)
|
||||
editbox:SetScript("OnLeave", Control_OnLeave)
|
||||
editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
|
||||
editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
|
||||
editbox:SetScript("OnTextChanged", EditBox_OnTextChanged)
|
||||
editbox:SetScript("OnReceiveDrag", EditBox_OnReceiveDrag)
|
||||
editbox:SetScript("OnMouseDown", EditBox_OnReceiveDrag)
|
||||
editbox:SetTextInsets(0, 0, 3, 3)
|
||||
editbox:SetMaxLetters(256)
|
||||
editbox:SetPoint("BOTTOMLEFT", 6, 0)
|
||||
editbox:SetPoint("BOTTOMRIGHT")
|
||||
editbox:SetHeight(19)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT", 0, -2)
|
||||
label:SetPoint("TOPRIGHT", 0, -2)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetHeight(18)
|
||||
|
||||
local button = CreateFrame("Button", nil, editbox, "UIPanelButtonTemplate")
|
||||
button:SetWidth(40)
|
||||
button:SetHeight(20)
|
||||
button:SetPoint("RIGHT", -2, 0)
|
||||
button:SetText(OKAY)
|
||||
button:SetScript("OnClick", Button_OnClick)
|
||||
button:Hide()
|
||||
|
||||
local widget = {
|
||||
alignoffset = 30,
|
||||
editbox = editbox,
|
||||
label = label,
|
||||
button = button,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
editbox.obj, button.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,78 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Heading Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Heading", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetText()
|
||||
self:SetFullWidth()
|
||||
self:SetHeight(18)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.label:SetText(text or "")
|
||||
if text and text ~= "" then
|
||||
self.left:SetPoint("RIGHT", self.label, "LEFT", -5, 0)
|
||||
self.right:Show()
|
||||
else
|
||||
self.left:SetPoint("RIGHT", -3, 0)
|
||||
self.right:Hide()
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontNormal")
|
||||
label:SetPoint("TOP")
|
||||
label:SetPoint("BOTTOM")
|
||||
label:SetJustifyH("CENTER")
|
||||
|
||||
local left = frame:CreateTexture(nil, "BACKGROUND")
|
||||
left:SetHeight(8)
|
||||
left:SetPoint("LEFT", 3, 0)
|
||||
left:SetPoint("RIGHT", label, "LEFT", -5, 0)
|
||||
left:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
left:SetTexCoord(0.81, 0.94, 0.5, 1)
|
||||
|
||||
local right = frame:CreateTexture(nil, "BACKGROUND")
|
||||
right:SetHeight(8)
|
||||
right:SetPoint("RIGHT", -3, 0)
|
||||
right:SetPoint("LEFT", label, "RIGHT", 5, 0)
|
||||
right:SetTexture("Interface\\Tooltips\\UI-Tooltip-Border")
|
||||
right:SetTexCoord(0.81, 0.94, 0.5, 1)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
left = left,
|
||||
right = right,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,144 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Icon Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Icon", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local select, pairs, print = select, pairs, print
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent, GetBuildInfo = CreateFrame, UIParent, GetBuildInfo
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Button_OnClick(frame, button)
|
||||
frame.obj:Fire("OnClick", button)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetHeight(110)
|
||||
self:SetWidth(110)
|
||||
self:SetLabel()
|
||||
self:SetImage(nil)
|
||||
self:SetImageSize(64, 64)
|
||||
self:SetDisabled(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:Show()
|
||||
self.label:SetText(text)
|
||||
self:SetHeight(self.image:GetHeight() + 25)
|
||||
else
|
||||
self.label:Hide()
|
||||
self:SetHeight(self.image:GetHeight() + 10)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, ...)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
local n = select("#", ...)
|
||||
if n == 4 or n == 8 then
|
||||
image:SetTexCoord(...)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
["SetImageSize"] = function(self, width, height)
|
||||
self.image:SetWidth(width)
|
||||
self.image:SetHeight(height)
|
||||
--self.frame:SetWidth(width + 30)
|
||||
if self.label:IsShown() then
|
||||
self:SetHeight(height + 25)
|
||||
else
|
||||
self:SetHeight(height + 10)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:Disable()
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.image:SetVertexColor(0.5, 0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:Enable()
|
||||
self.label:SetTextColor(1, 1, 1)
|
||||
self.image:SetVertexColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Button", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnClick", Button_OnClick)
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlight")
|
||||
label:SetPoint("BOTTOMLEFT")
|
||||
label:SetPoint("BOTTOMRIGHT")
|
||||
label:SetJustifyH("CENTER")
|
||||
label:SetJustifyV("TOP")
|
||||
label:SetHeight(18)
|
||||
|
||||
local image = frame:CreateTexture(nil, "BACKGROUND")
|
||||
image:SetWidth(64)
|
||||
image:SetHeight(64)
|
||||
image:SetPoint("TOP", 0, -5)
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetAllPoints(image)
|
||||
highlight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-Tab-Highlight")
|
||||
highlight:SetTexCoord(0, 1, 0.23, 0.77)
|
||||
highlight:SetBlendMode("ADD")
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
-- SetText is deprecated, but keep it around for a while. (say, to WoW 4.0)
|
||||
if (select(4, GetBuildInfo()) < 40000) then
|
||||
widget.SetText = widget.SetLabel
|
||||
else
|
||||
widget.SetText = function(self, ...) print("AceGUI-3.0-Icon: SetText is deprecated! Use SetLabel instead!"); self:SetLabel(...) end
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,101 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
InteractiveLabel Widget
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "InteractiveLabel", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local select, pairs = select, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Label_OnClick(frame, button)
|
||||
frame.obj:Fire("OnClick", button)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:LabelOnAcquire()
|
||||
self:SetHighlight()
|
||||
self:SetHighlightTexCoord()
|
||||
self:SetDisabled(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetHighlight"] = function(self, ...)
|
||||
self.highlight:SetTexture(...)
|
||||
end,
|
||||
|
||||
["SetHighlightTexCoord"] = function(self, ...)
|
||||
local c = select("#", ...)
|
||||
if c == 4 or c == 8 then
|
||||
self.highlight:SetTexCoord(...)
|
||||
else
|
||||
self.highlight:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetDisabled"] = function(self,disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.frame:EnableMouse(false)
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
else
|
||||
self.frame:EnableMouse(true)
|
||||
self.label:SetTextColor(1, 1, 1)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
-- create a Label type that we will hijack
|
||||
local label = AceGUI:Create("Label")
|
||||
|
||||
local frame = label.frame
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnEnter", Control_OnEnter)
|
||||
frame:SetScript("OnLeave", Control_OnLeave)
|
||||
frame:SetScript("OnMouseDown", Label_OnClick)
|
||||
|
||||
local highlight = frame:CreateTexture(nil, "HIGHLIGHT")
|
||||
highlight:SetTexture(nil)
|
||||
highlight:SetAllPoints()
|
||||
highlight:SetBlendMode("ADD")
|
||||
|
||||
label.highlight = highlight
|
||||
label.type = Type
|
||||
label.LabelOnAcquire = label.OnAcquire
|
||||
for method, func in pairs(methods) do
|
||||
label[method] = func
|
||||
end
|
||||
|
||||
return label
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Keybinding Widget
|
||||
Set Keybindings in the Config UI.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Keybinding", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown = IsShiftKeyDown, IsControlKeyDown, IsAltKeyDown
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: NOT_BOUND
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Keybinding_OnClick(frame, button)
|
||||
if button == "LeftButton" or button == "RightButton" then
|
||||
local self = frame.obj
|
||||
if self.waitingForKey then
|
||||
frame:EnableKeyboard(false)
|
||||
self.msgframe:Hide()
|
||||
frame:UnlockHighlight()
|
||||
self.waitingForKey = nil
|
||||
else
|
||||
frame:EnableKeyboard(true)
|
||||
self.msgframe:Show()
|
||||
frame:LockHighlight()
|
||||
self.waitingForKey = true
|
||||
end
|
||||
end
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local ignoreKeys = {
|
||||
["BUTTON1"] = true, ["BUTTON2"] = true,
|
||||
["UNKNOWN"] = true,
|
||||
["LSHIFT"] = true, ["LCTRL"] = true, ["LALT"] = true,
|
||||
["RSHIFT"] = true, ["RCTRL"] = true, ["RALT"] = true,
|
||||
}
|
||||
local function Keybinding_OnKeyDown(frame, key)
|
||||
local self = frame.obj
|
||||
if self.waitingForKey then
|
||||
local keyPressed = key
|
||||
if keyPressed == "ESCAPE" then
|
||||
keyPressed = ""
|
||||
else
|
||||
if ignoreKeys[keyPressed] then return end
|
||||
if IsShiftKeyDown() then
|
||||
keyPressed = "SHIFT-"..keyPressed
|
||||
end
|
||||
if IsControlKeyDown() then
|
||||
keyPressed = "CTRL-"..keyPressed
|
||||
end
|
||||
if IsAltKeyDown() then
|
||||
keyPressed = "ALT-"..keyPressed
|
||||
end
|
||||
end
|
||||
|
||||
frame:EnableKeyboard(false)
|
||||
self.msgframe:Hide()
|
||||
frame:UnlockHighlight()
|
||||
self.waitingForKey = nil
|
||||
|
||||
if not self.disabled then
|
||||
self:SetKey(keyPressed)
|
||||
self:Fire("OnKeyChanged", keyPressed)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Keybinding_OnMouseDown(frame, button)
|
||||
if button == "LeftButton" or button == "RightButton" then
|
||||
return
|
||||
elseif button == "MiddleButton" then
|
||||
button = "BUTTON3"
|
||||
elseif button == "Button4" then
|
||||
button = "BUTTON4"
|
||||
elseif button == "Button5" then
|
||||
button = "BUTTON5"
|
||||
end
|
||||
Keybinding_OnKeyDown(frame, button)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(200)
|
||||
self:SetLabel("")
|
||||
self:SetKey("")
|
||||
self.waitingForKey = nil
|
||||
self.msgframe:Hide()
|
||||
self:SetDisabled(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.button:Disable()
|
||||
self.label:SetTextColor(0.5,0.5,0.5)
|
||||
else
|
||||
self.button:Enable()
|
||||
self.label:SetTextColor(1,1,1)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetKey"] = function(self, key)
|
||||
if (key or "") == "" then
|
||||
self.button:SetText(NOT_BOUND)
|
||||
self.button:SetNormalFontObject("GameFontNormal")
|
||||
else
|
||||
self.button:SetText(key)
|
||||
self.button:SetNormalFontObject("GameFontHighlight")
|
||||
end
|
||||
end,
|
||||
|
||||
["GetKey"] = function(self)
|
||||
local key = self.button:GetText()
|
||||
if key == NOT_BOUND then
|
||||
key = nil
|
||||
end
|
||||
return key
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, label)
|
||||
self.label:SetText(label or "")
|
||||
if (label or "") == "" then
|
||||
self.alignoffset = nil
|
||||
self:SetHeight(24)
|
||||
else
|
||||
self.alignoffset = 30
|
||||
self:SetHeight(44)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local ControlBackdrop = {
|
||||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||||
tile = true, tileSize = 16, edgeSize = 16,
|
||||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||||
}
|
||||
|
||||
local function keybindingMsgFixWidth(frame)
|
||||
frame:SetWidth(frame.msg:GetWidth() + 10)
|
||||
frame:SetScript("OnUpdate", nil)
|
||||
end
|
||||
|
||||
local function Constructor()
|
||||
local name = "AceGUI30KeybindingButton" .. AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
local button = CreateFrame("Button", name, frame, "UIPanelButtonTemplate2")
|
||||
|
||||
button:EnableMouse(true)
|
||||
button:RegisterForClicks("AnyDown")
|
||||
button:SetScript("OnEnter", Control_OnEnter)
|
||||
button:SetScript("OnLeave", Control_OnLeave)
|
||||
button:SetScript("OnClick", Keybinding_OnClick)
|
||||
button:SetScript("OnKeyDown", Keybinding_OnKeyDown)
|
||||
button:SetScript("OnMouseDown", Keybinding_OnMouseDown)
|
||||
button:SetPoint("BOTTOMLEFT")
|
||||
button:SetPoint("BOTTOMRIGHT")
|
||||
button:SetHeight(24)
|
||||
|
||||
local text = button:GetFontString()
|
||||
text:SetPoint("LEFT", 7, 0)
|
||||
text:SetPoint("RIGHT", -7, 0)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
||||
label:SetPoint("TOPLEFT")
|
||||
label:SetPoint("TOPRIGHT")
|
||||
label:SetJustifyH("CENTER")
|
||||
label:SetHeight(18)
|
||||
|
||||
local msgframe = CreateFrame("Frame", nil, UIParent)
|
||||
msgframe:SetHeight(30)
|
||||
msgframe:SetBackdrop(ControlBackdrop)
|
||||
msgframe:SetBackdropColor(0,0,0)
|
||||
msgframe:SetFrameStrata("FULLSCREEN_DIALOG")
|
||||
msgframe:SetFrameLevel(1000)
|
||||
|
||||
local msg = msgframe:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
msg:SetText("Press a key to bind, ESC to clear the binding or click the button again to cancel.")
|
||||
msgframe.msg = msg
|
||||
msg:SetPoint("TOPLEFT", 5, -5)
|
||||
msgframe:SetScript("OnUpdate", keybindingMsgFixWidth)
|
||||
msgframe:SetPoint("BOTTOM", button, "TOP")
|
||||
msgframe:Hide()
|
||||
|
||||
local widget = {
|
||||
button = button,
|
||||
label = label,
|
||||
msgframe = msgframe,
|
||||
frame = frame,
|
||||
alignoffset = 30,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
button.obj = widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,162 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Label Widget
|
||||
Displays text and optionally an icon.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Label", 21
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local max, select, pairs = math.max, select, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
|
||||
local function UpdateImageAnchor(self)
|
||||
if self.resizing then return end
|
||||
local frame = self.frame
|
||||
local width = frame.width or frame:GetWidth() or 0
|
||||
local image = self.image
|
||||
local label = self.label
|
||||
local height
|
||||
|
||||
label:ClearAllPoints()
|
||||
image:ClearAllPoints()
|
||||
|
||||
if self.imageshown then
|
||||
local imagewidth = image:GetWidth()
|
||||
if (width - imagewidth) < 200 or (label:GetText() or "") == "" then
|
||||
-- image goes on top centered when less than 200 width for the text, or if there is no text
|
||||
image:SetPoint("TOP")
|
||||
label:SetPoint("TOP", image, "BOTTOM")
|
||||
label:SetPoint("LEFT")
|
||||
label:SetWidth(width)
|
||||
height = image:GetHeight() + label:GetHeight()
|
||||
else
|
||||
-- image on the left
|
||||
image:SetPoint("TOPLEFT")
|
||||
label:SetPoint("TOPLEFT", image, "TOPRIGHT", 4, 0)
|
||||
label:SetWidth(width - imagewidth - 4)
|
||||
height = max(image:GetHeight(), label:GetHeight())
|
||||
end
|
||||
else
|
||||
-- no image shown
|
||||
label:SetPoint("TOPLEFT")
|
||||
label:SetWidth(width)
|
||||
height = label:GetHeight()
|
||||
end
|
||||
|
||||
self.resizing = true
|
||||
frame:SetHeight(height)
|
||||
frame.height = height
|
||||
self.resizing = nil
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
-- set the flag to stop constant size updates
|
||||
self.resizing = true
|
||||
-- height is set dynamically by the text and image size
|
||||
self:SetWidth(200)
|
||||
self:SetText()
|
||||
self:SetImage(nil)
|
||||
self:SetImageSize(16, 16)
|
||||
self:SetColor()
|
||||
self:SetFontObject()
|
||||
|
||||
-- reset the flag
|
||||
self.resizing = nil
|
||||
-- run the update explicitly
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["OnWidthSet"] = function(self, width)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.label:SetText(text)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetColor"] = function(self, r, g, b)
|
||||
if not (r and g and b) then
|
||||
r, g, b = 1, 1, 1
|
||||
end
|
||||
self.label:SetVertexColor(r, g, b)
|
||||
end,
|
||||
|
||||
["SetImage"] = function(self, path, ...)
|
||||
local image = self.image
|
||||
image:SetTexture(path)
|
||||
|
||||
if image:GetTexture() then
|
||||
self.imageshown = true
|
||||
local n = select("#", ...)
|
||||
if n == 4 or n == 8 then
|
||||
image:SetTexCoord(...)
|
||||
else
|
||||
image:SetTexCoord(0, 1, 0, 1)
|
||||
end
|
||||
else
|
||||
self.imageshown = nil
|
||||
end
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
|
||||
["SetFont"] = function(self, font, height, flags)
|
||||
self.label:SetFont(font, height, flags)
|
||||
end,
|
||||
|
||||
["SetFontObject"] = function(self, font)
|
||||
self:SetFont((font or GameFontHighlightSmall):GetFont())
|
||||
end,
|
||||
|
||||
["SetImageSize"] = function(self, width, height)
|
||||
self.image:SetWidth(width)
|
||||
self.image:SetHeight(height)
|
||||
UpdateImageAnchor(self)
|
||||
end,
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local label = frame:CreateFontString(nil, "BACKGROUND", "GameFontHighlightSmall")
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetJustifyV("TOP")
|
||||
|
||||
local image = frame:CreateTexture(nil, "BACKGROUND")
|
||||
|
||||
-- create widget
|
||||
local widget = {
|
||||
label = label,
|
||||
image = image,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,311 @@
|
||||
local Type, Version = "MultiLineEditBox", 23
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local pairs = pairs
|
||||
|
||||
-- WoW APIs
|
||||
local GetCursorInfo, GetSpellName, ClearCursor = GetCursorInfo, GetSpellName, ClearCursor
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
local _G = _G
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: ACCEPT, ChatFontNormal
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Layout(self)
|
||||
self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
|
||||
|
||||
if self.labelHeight == 0 then
|
||||
self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
|
||||
else
|
||||
self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
|
||||
end
|
||||
|
||||
if self.disablebutton then
|
||||
self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
|
||||
self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
|
||||
else
|
||||
self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
|
||||
self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function OnClick(self) -- Button
|
||||
self = self.obj
|
||||
self.editBox:ClearFocus()
|
||||
if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
|
||||
self.button:Disable()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnCursorChanged(self, _, y, _, cursorHeight) -- EditBox
|
||||
self, y = self.obj.scrollFrame, -y
|
||||
local offset = self:GetVerticalScroll()
|
||||
if y < offset then
|
||||
self:SetVerticalScroll(y)
|
||||
else
|
||||
y = y + cursorHeight - self:GetHeight()
|
||||
if y > offset then
|
||||
self:SetVerticalScroll(y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function OnEditFocusLost(self) -- EditBox
|
||||
self:HighlightText(0, 0)
|
||||
end
|
||||
|
||||
local function OnEnter(self) -- EditBox / ScrollFrame
|
||||
self = self.obj
|
||||
if not self.entered then
|
||||
self.entered = true
|
||||
self:Fire("OnEnter")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnLeave(self) -- EditBox / ScrollFrame
|
||||
self = self.obj
|
||||
if self.entered then
|
||||
self.entered = nil
|
||||
self:Fire("OnLeave")
|
||||
end
|
||||
end
|
||||
|
||||
local function OnMouseUp(self) -- ScrollFrame
|
||||
self = self.obj.editBox
|
||||
self:SetFocus()
|
||||
self:SetCursorPosition(self:GetNumLetters())
|
||||
end
|
||||
|
||||
local function OnReceiveDrag(self) -- EditBox / ScrollFrame
|
||||
local type, id, info = GetCursorInfo()
|
||||
if type == "spell" then
|
||||
info, id = GetSpellName(id, info)
|
||||
if id and id:match("%d") then
|
||||
info = info .. "(" .. id .. ")"
|
||||
end
|
||||
elseif type ~= "item" then
|
||||
return
|
||||
end
|
||||
ClearCursor()
|
||||
self = self.obj
|
||||
local editBox = self.editBox
|
||||
if not editBox:HasFocus() then
|
||||
editBox:SetFocus()
|
||||
editBox:SetCursorPosition(editBox:GetNumLetters())
|
||||
end
|
||||
editBox:Insert(info)
|
||||
self.button:Enable()
|
||||
end
|
||||
|
||||
local function OnSizeChanged(self, width, height) -- ScrollFrame
|
||||
self.obj.editBox:SetWidth(width)
|
||||
end
|
||||
|
||||
local function OnTextChanged(self, userInput) -- EditBox
|
||||
if userInput then
|
||||
self = self.obj
|
||||
self:Fire("OnTextChanged", self.editBox:GetText())
|
||||
self.button:Enable()
|
||||
end
|
||||
end
|
||||
|
||||
local function OnTextSet(self) -- EditBox
|
||||
self:HighlightText(0, 0)
|
||||
self:SetCursorPosition(self:GetNumLetters())
|
||||
self:SetCursorPosition(0)
|
||||
self.obj.button:Disable()
|
||||
end
|
||||
|
||||
local function OnVerticalScroll(self, offset) -- ScrollFrame
|
||||
local editBox = self.obj.editBox
|
||||
editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self.editBox:SetText("")
|
||||
self:SetDisabled(false)
|
||||
self:SetWidth(200)
|
||||
self:DisableButton(false)
|
||||
self:SetNumLines()
|
||||
self.entered = nil
|
||||
self:SetMaxLetters(0)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
local editBox = self.editBox
|
||||
if disabled then
|
||||
editBox:ClearFocus()
|
||||
editBox:EnableMouse(false)
|
||||
editBox:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.label:SetTextColor(0.5, 0.5, 0.5)
|
||||
self.scrollFrame:EnableMouse(false)
|
||||
self.button:Disable()
|
||||
else
|
||||
editBox:EnableMouse(true)
|
||||
editBox:SetTextColor(1, 1, 1)
|
||||
self.label:SetTextColor(1, 0.82, 0)
|
||||
self.scrollFrame:EnableMouse(true)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
if text and text ~= "" then
|
||||
self.label:SetText(text)
|
||||
if self.labelHeight ~= 10 then
|
||||
self.labelHeight = 10
|
||||
self.label:Show()
|
||||
end
|
||||
elseif self.labelHeight ~= 0 then
|
||||
self.labelHeight = 0
|
||||
self.label:Hide()
|
||||
end
|
||||
Layout(self)
|
||||
end,
|
||||
|
||||
["SetNumLines"] = function(self, value)
|
||||
if not value or value < 4 then
|
||||
value = 4
|
||||
end
|
||||
self.numlines = value
|
||||
Layout(self)
|
||||
end,
|
||||
|
||||
["SetText"] = function(self, text)
|
||||
self.editBox:SetText(text)
|
||||
end,
|
||||
|
||||
["GetText"] = function(self)
|
||||
return self.editBox:GetText()
|
||||
end,
|
||||
|
||||
["SetMaxLetters"] = function (self, num)
|
||||
self.editBox:SetMaxLetters(num or 0)
|
||||
end,
|
||||
|
||||
["DisableButton"] = function(self, disabled)
|
||||
self.disablebutton = disabled
|
||||
if disabled then
|
||||
self.button:Hide()
|
||||
else
|
||||
self.button:Show()
|
||||
end
|
||||
Layout(self)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local backdrop = {
|
||||
bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
|
||||
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
|
||||
insets = { left = 4, right = 3, top = 4, bottom = 3 }
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
frame:Hide()
|
||||
|
||||
local widgetNum = AceGUI:GetNextWidgetNum(Type)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
||||
label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
|
||||
label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
|
||||
label:SetJustifyH("LEFT")
|
||||
label:SetText(ACCEPT)
|
||||
label:SetHeight(10)
|
||||
|
||||
local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate2")
|
||||
button:SetPoint("BOTTOMLEFT", 0, 4)
|
||||
button:SetHeight(22)
|
||||
button:SetWidth(label:GetStringWidth() + 24)
|
||||
button:SetText(ACCEPT)
|
||||
button:SetScript("OnClick", OnClick)
|
||||
button:Disable()
|
||||
|
||||
local text = button:GetFontString()
|
||||
text:ClearAllPoints()
|
||||
text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
|
||||
text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
|
||||
text:SetJustifyV("MIDDLE")
|
||||
|
||||
local scrollBG = CreateFrame("Frame", nil, frame)
|
||||
scrollBG:SetBackdrop(backdrop)
|
||||
scrollBG:SetBackdropColor(0, 0, 0)
|
||||
scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
|
||||
|
||||
local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
|
||||
|
||||
local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
|
||||
scrollBar:ClearAllPoints()
|
||||
scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
|
||||
scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
|
||||
scrollBar:SetPoint("RIGHT", frame, "RIGHT")
|
||||
|
||||
scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
|
||||
scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
|
||||
|
||||
scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
|
||||
scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
|
||||
scrollFrame:SetScript("OnEnter", OnEnter)
|
||||
scrollFrame:SetScript("OnLeave", OnLeave)
|
||||
scrollFrame:SetScript("OnMouseUp", OnMouseUp)
|
||||
scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
|
||||
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
|
||||
scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
|
||||
|
||||
local editBox = CreateFrame("EditBox", nil, scrollFrame)
|
||||
editBox:SetAllPoints()
|
||||
editBox:SetFontObject(ChatFontNormal)
|
||||
editBox:SetMultiLine(true)
|
||||
editBox:EnableMouse(true)
|
||||
editBox:SetAutoFocus(false)
|
||||
editBox:SetCountInvisibleLetters(false)
|
||||
editBox:SetScript("OnCursorChanged", OnCursorChanged)
|
||||
editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
|
||||
editBox:SetScript("OnEnter", OnEnter)
|
||||
editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
|
||||
editBox:SetScript("OnLeave", OnLeave)
|
||||
editBox:SetScript("OnMouseDown", OnReceiveDrag)
|
||||
editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
|
||||
editBox:SetScript("OnTextChanged", OnTextChanged)
|
||||
editBox:SetScript("OnTextSet", OnTextSet)
|
||||
|
||||
scrollFrame:SetScrollChild(editBox)
|
||||
|
||||
local widget = {
|
||||
button = button,
|
||||
editBox = editBox,
|
||||
frame = frame,
|
||||
label = label,
|
||||
labelHeight = 10,
|
||||
numlines = 4,
|
||||
scrollBar = scrollBar,
|
||||
scrollBG = scrollBG,
|
||||
scrollFrame = scrollFrame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type, Constructor, Version)
|
||||
@@ -0,0 +1,281 @@
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Slider Widget
|
||||
Graphical Slider, like, for Range values.
|
||||
-------------------------------------------------------------------------------]]
|
||||
local Type, Version = "Slider", 20
|
||||
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
||||
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
||||
|
||||
-- Lua APIs
|
||||
local min, max, floor = math.min, math.max, math.floor
|
||||
local tonumber, pairs = tonumber, pairs
|
||||
|
||||
-- WoW APIs
|
||||
local PlaySound = PlaySound
|
||||
local CreateFrame, UIParent = CreateFrame, UIParent
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GameFontHighlightSmall
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Support functions
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function UpdateText(self)
|
||||
local value = self.value or 0
|
||||
if self.ispercent then
|
||||
self.editbox:SetText(("%s%%"):format(floor(value * 1000 + 0.5) / 10))
|
||||
else
|
||||
self.editbox:SetText(floor(value * 100 + 0.5) / 100)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateLabels(self)
|
||||
local min, max = (self.min or 0), (self.max or 100)
|
||||
if self.ispercent then
|
||||
self.lowtext:SetFormattedText("%s%%", (min * 100))
|
||||
self.hightext:SetFormattedText("%s%%", (max * 100))
|
||||
else
|
||||
self.lowtext:SetText(min)
|
||||
self.hightext:SetText(max)
|
||||
end
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Scripts
|
||||
-------------------------------------------------------------------------------]]
|
||||
local function Control_OnEnter(frame)
|
||||
frame.obj:Fire("OnEnter")
|
||||
end
|
||||
|
||||
local function Control_OnLeave(frame)
|
||||
frame.obj:Fire("OnLeave")
|
||||
end
|
||||
|
||||
local function Frame_OnMouseDown(frame)
|
||||
frame.obj.slider:EnableMouseWheel(true)
|
||||
AceGUI:ClearFocus()
|
||||
end
|
||||
|
||||
local function Slider_OnValueChanged(frame)
|
||||
local self = frame.obj
|
||||
if not frame.setup then
|
||||
local newvalue = frame:GetValue()
|
||||
if newvalue ~= self.value and not self.disabled then
|
||||
self.value = newvalue
|
||||
self:Fire("OnValueChanged", newvalue)
|
||||
end
|
||||
if self.value then
|
||||
UpdateText(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function Slider_OnMouseUp(frame)
|
||||
local self = frame.obj
|
||||
self:Fire("OnMouseUp", self.value)
|
||||
end
|
||||
|
||||
local function Slider_OnMouseWheel(frame, v)
|
||||
local self = frame.obj
|
||||
if not self.disabled then
|
||||
local value = self.value
|
||||
if v > 0 then
|
||||
value = min(value + (self.step or 1), self.max)
|
||||
else
|
||||
value = max(value - (self.step or 1), self.min)
|
||||
end
|
||||
self.slider:SetValue(value)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnEscapePressed(frame)
|
||||
frame:ClearFocus()
|
||||
end
|
||||
|
||||
local function EditBox_OnEnterPressed(frame)
|
||||
local self = frame.obj
|
||||
local value = frame:GetText()
|
||||
if self.ispercent then
|
||||
value = value:gsub('%%', '')
|
||||
value = tonumber(value) / 100
|
||||
else
|
||||
value = tonumber(value)
|
||||
end
|
||||
|
||||
if value then
|
||||
PlaySound("igMainMenuOptionCheckBoxOn")
|
||||
self.slider:SetValue(value)
|
||||
self:Fire("OnMouseUp", value)
|
||||
end
|
||||
end
|
||||
|
||||
local function EditBox_OnEnter(frame)
|
||||
frame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||||
end
|
||||
|
||||
local function EditBox_OnLeave(frame)
|
||||
frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 0.8)
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Methods
|
||||
-------------------------------------------------------------------------------]]
|
||||
local methods = {
|
||||
["OnAcquire"] = function(self)
|
||||
self:SetWidth(200)
|
||||
self:SetHeight(44)
|
||||
self:SetDisabled(false)
|
||||
self:SetIsPercent(nil)
|
||||
self:SetSliderValues(0,100,1)
|
||||
self:SetValue(0)
|
||||
self.slider:EnableMouseWheel(false)
|
||||
end,
|
||||
|
||||
-- ["OnRelease"] = nil,
|
||||
|
||||
["SetDisabled"] = function(self, disabled)
|
||||
self.disabled = disabled
|
||||
if disabled then
|
||||
self.slider:EnableMouse(false)
|
||||
self.label:SetTextColor(.5, .5, .5)
|
||||
self.hightext:SetTextColor(.5, .5, .5)
|
||||
self.lowtext:SetTextColor(.5, .5, .5)
|
||||
--self.valuetext:SetTextColor(.5, .5, .5)
|
||||
self.editbox:SetTextColor(.5, .5, .5)
|
||||
self.editbox:EnableMouse(false)
|
||||
self.editbox:ClearFocus()
|
||||
else
|
||||
self.slider:EnableMouse(true)
|
||||
self.label:SetTextColor(1, .82, 0)
|
||||
self.hightext:SetTextColor(1, 1, 1)
|
||||
self.lowtext:SetTextColor(1, 1, 1)
|
||||
--self.valuetext:SetTextColor(1, 1, 1)
|
||||
self.editbox:SetTextColor(1, 1, 1)
|
||||
self.editbox:EnableMouse(true)
|
||||
end
|
||||
end,
|
||||
|
||||
["SetValue"] = function(self, value)
|
||||
self.slider.setup = true
|
||||
self.slider:SetValue(value)
|
||||
self.value = value
|
||||
UpdateText(self)
|
||||
self.slider.setup = nil
|
||||
end,
|
||||
|
||||
["GetValue"] = function(self)
|
||||
return self.value
|
||||
end,
|
||||
|
||||
["SetLabel"] = function(self, text)
|
||||
self.label:SetText(text)
|
||||
end,
|
||||
|
||||
["SetSliderValues"] = function(self, min, max, step)
|
||||
local frame = self.slider
|
||||
frame.setup = true
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.step = step
|
||||
frame:SetMinMaxValues(min or 0,max or 100)
|
||||
UpdateLabels(self)
|
||||
frame:SetValueStep(step or 1)
|
||||
if self.value then
|
||||
frame:SetValue(self.value)
|
||||
end
|
||||
frame.setup = nil
|
||||
end,
|
||||
|
||||
["SetIsPercent"] = function(self, value)
|
||||
self.ispercent = value
|
||||
UpdateLabels(self)
|
||||
UpdateText(self)
|
||||
end
|
||||
}
|
||||
|
||||
--[[-----------------------------------------------------------------------------
|
||||
Constructor
|
||||
-------------------------------------------------------------------------------]]
|
||||
local SliderBackdrop = {
|
||||
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
|
||||
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
||||
tile = true, tileSize = 8, edgeSize = 8,
|
||||
insets = { left = 3, right = 3, top = 6, bottom = 6 }
|
||||
}
|
||||
|
||||
local ManualBackdrop = {
|
||||
bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
|
||||
tile = true, edgeSize = 1, tileSize = 5,
|
||||
}
|
||||
|
||||
local function Constructor()
|
||||
local frame = CreateFrame("Frame", nil, UIParent)
|
||||
|
||||
frame:EnableMouse(true)
|
||||
frame:SetScript("OnMouseDown", Frame_OnMouseDown)
|
||||
|
||||
local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
||||
label:SetPoint("TOPLEFT")
|
||||
label:SetPoint("TOPRIGHT")
|
||||
label:SetJustifyH("CENTER")
|
||||
label:SetHeight(15)
|
||||
|
||||
local slider = CreateFrame("Slider", nil, frame)
|
||||
slider:SetOrientation("HORIZONTAL")
|
||||
slider:SetHeight(15)
|
||||
slider:SetHitRectInsets(0, 0, -10, 0)
|
||||
slider:SetBackdrop(SliderBackdrop)
|
||||
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Horizontal")
|
||||
slider:SetPoint("TOP", label, "BOTTOM")
|
||||
slider:SetPoint("LEFT", 3, 0)
|
||||
slider:SetPoint("RIGHT", -3, 0)
|
||||
slider:SetValue(0)
|
||||
slider:SetScript("OnValueChanged",Slider_OnValueChanged)
|
||||
slider:SetScript("OnEnter", Control_OnEnter)
|
||||
slider:SetScript("OnLeave", Control_OnLeave)
|
||||
slider:SetScript("OnMouseUp", Slider_OnMouseUp)
|
||||
slider:SetScript("OnMouseWheel", Slider_OnMouseWheel)
|
||||
|
||||
local lowtext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
lowtext:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 2, 3)
|
||||
|
||||
local hightext = slider:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
||||
hightext:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", -2, 3)
|
||||
|
||||
local editbox = CreateFrame("EditBox", nil, frame)
|
||||
editbox:SetAutoFocus(false)
|
||||
editbox:SetFontObject(GameFontHighlightSmall)
|
||||
editbox:SetPoint("TOP", slider, "BOTTOM")
|
||||
editbox:SetHeight(14)
|
||||
editbox:SetWidth(70)
|
||||
editbox:SetJustifyH("CENTER")
|
||||
editbox:EnableMouse(true)
|
||||
editbox:SetBackdrop(ManualBackdrop)
|
||||
editbox:SetBackdropColor(0, 0, 0, 0.5)
|
||||
editbox:SetBackdropBorderColor(0.3, 0.3, 0.30, 0.80)
|
||||
editbox:SetScript("OnEnter", EditBox_OnEnter)
|
||||
editbox:SetScript("OnLeave", EditBox_OnLeave)
|
||||
editbox:SetScript("OnEnterPressed", EditBox_OnEnterPressed)
|
||||
editbox:SetScript("OnEscapePressed", EditBox_OnEscapePressed)
|
||||
|
||||
local widget = {
|
||||
label = label,
|
||||
slider = slider,
|
||||
lowtext = lowtext,
|
||||
hightext = hightext,
|
||||
editbox = editbox,
|
||||
alignoffset = 25,
|
||||
frame = frame,
|
||||
type = Type
|
||||
}
|
||||
for method, func in pairs(methods) do
|
||||
widget[method] = func
|
||||
end
|
||||
slider.obj, editbox.obj = widget, widget
|
||||
|
||||
return AceGUI:RegisterAsWidget(widget)
|
||||
end
|
||||
|
||||
AceGUI:RegisterWidgetType(Type,Constructor,Version)
|
||||
@@ -0,0 +1,514 @@
|
||||
--- **AceHook-3.0** offers safe Hooking/Unhooking of functions, methods and frame scripts.
|
||||
-- Using AceHook-3.0 is recommended when you need to unhook your hooks again, so the hook chain isn't broken
|
||||
-- when you manually restore the original function.
|
||||
--
|
||||
-- **AceHook-3.0** can be embeded into your addon, either explicitly by calling AceHook:Embed(MyAddon) or by
|
||||
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
|
||||
-- and can be accessed directly, without having to explicitly call AceHook itself.\\
|
||||
-- It is recommended to embed AceHook, otherwise you'll have to specify a custom `self` on all calls you
|
||||
-- make into AceHook.
|
||||
-- @class file
|
||||
-- @name AceHook-3.0
|
||||
-- @release $Id: AceHook-3.0.lua 877 2009-11-02 15:56:50Z nevcairiel $
|
||||
local ACEHOOK_MAJOR, ACEHOOK_MINOR = "AceHook-3.0", 5
|
||||
local AceHook, oldminor = LibStub:NewLibrary(ACEHOOK_MAJOR, ACEHOOK_MINOR)
|
||||
|
||||
if not AceHook then return end -- No upgrade needed
|
||||
|
||||
AceHook.embeded = AceHook.embeded or {}
|
||||
AceHook.registry = AceHook.registry or setmetatable({}, {__index = function(tbl, key) tbl[key] = {} return tbl[key] end })
|
||||
AceHook.handlers = AceHook.handlers or {}
|
||||
AceHook.actives = AceHook.actives or {}
|
||||
AceHook.scripts = AceHook.scripts or {}
|
||||
AceHook.onceSecure = AceHook.onceSecure or {}
|
||||
AceHook.hooks = AceHook.hooks or {}
|
||||
|
||||
-- local upvalues
|
||||
local registry = AceHook.registry
|
||||
local handlers = AceHook.handlers
|
||||
local actives = AceHook.actives
|
||||
local scripts = AceHook.scripts
|
||||
local onceSecure = AceHook.onceSecure
|
||||
|
||||
-- Lua APIs
|
||||
local pairs, next, type = pairs, next, type
|
||||
local format = string.format
|
||||
local assert, error = assert, error
|
||||
|
||||
-- WoW APIs
|
||||
local issecurevariable, hooksecurefunc = issecurevariable, hooksecurefunc
|
||||
local _G = _G
|
||||
|
||||
-- functions for later definition
|
||||
local donothing, createHook, hook
|
||||
|
||||
local protectedScripts = {
|
||||
OnClick = true,
|
||||
}
|
||||
|
||||
-- upgrading of embeded is done at the bottom of the file
|
||||
|
||||
local mixins = {
|
||||
"Hook", "SecureHook",
|
||||
"HookScript", "SecureHookScript",
|
||||
"Unhook", "UnhookAll",
|
||||
"IsHooked",
|
||||
"RawHook", "RawHookScript"
|
||||
}
|
||||
|
||||
-- AceHook:Embed( target )
|
||||
-- target (object) - target object to embed AceHook in
|
||||
--
|
||||
-- Embeds AceEevent into the target object making the functions from the mixins list available on target:..
|
||||
function AceHook:Embed( target )
|
||||
for k, v in pairs( mixins ) do
|
||||
target[v] = self[v]
|
||||
end
|
||||
self.embeded[target] = true
|
||||
-- inject the hooks table safely
|
||||
target.hooks = target.hooks or {}
|
||||
return target
|
||||
end
|
||||
|
||||
-- AceHook:OnEmbedDisable( target )
|
||||
-- target (object) - target object that is being disabled
|
||||
--
|
||||
-- Unhooks all hooks when the target disables.
|
||||
-- this method should be called by the target manually or by an addon framework
|
||||
function AceHook:OnEmbedDisable( target )
|
||||
target:UnhookAll()
|
||||
end
|
||||
|
||||
function createHook(self, handler, orig, secure, failsafe)
|
||||
local uid
|
||||
local method = type(handler) == "string"
|
||||
if failsafe and not secure then
|
||||
-- failsafe hook creation
|
||||
uid = function(...)
|
||||
if actives[uid] then
|
||||
if method then
|
||||
self[handler](self, ...)
|
||||
else
|
||||
handler(...)
|
||||
end
|
||||
end
|
||||
return orig(...)
|
||||
end
|
||||
-- /failsafe hook
|
||||
else
|
||||
-- all other hooks
|
||||
uid = function(...)
|
||||
if actives[uid] then
|
||||
if method then
|
||||
return self[handler](self, ...)
|
||||
else
|
||||
return handler(...)
|
||||
end
|
||||
elseif not secure then -- backup on non secure
|
||||
return orig(...)
|
||||
end
|
||||
end
|
||||
-- /hook
|
||||
end
|
||||
return uid
|
||||
end
|
||||
|
||||
function donothing() end
|
||||
|
||||
function hook(self, obj, method, handler, script, secure, raw, forceSecure, usage)
|
||||
if not handler then handler = method end
|
||||
|
||||
-- These asserts make sure AceHooks's devs play by the rules.
|
||||
assert(not script or type(script) == "boolean")
|
||||
assert(not secure or type(secure) == "boolean")
|
||||
assert(not raw or type(raw) == "boolean")
|
||||
assert(not forceSecure or type(forceSecure) == "boolean")
|
||||
assert(usage)
|
||||
|
||||
-- Error checking Battery!
|
||||
if obj and type(obj) ~= "table" then
|
||||
error(format("%s: 'object' - nil or table expected got %s", usage, type(obj)), 3)
|
||||
end
|
||||
if type(method) ~= "string" then
|
||||
error(format("%s: 'method' - string expected got %s", usage, type(method)), 3)
|
||||
end
|
||||
if type(handler) ~= "string" and type(handler) ~= "function" then
|
||||
error(format("%s: 'handler' - nil, string, or function expected got %s", usage, type(handler)), 3)
|
||||
end
|
||||
if type(handler) == "string" and type(self[handler]) ~= "function" then
|
||||
error(format("%s: 'handler' - Handler specified does not exist at self[handler]", usage), 3)
|
||||
end
|
||||
if script then
|
||||
if not secure and obj:IsProtected() and protectedScripts[method] then
|
||||
error(format("Cannot hook secure script %q; Use SecureHookScript(obj, method, [handler]) instead.", method), 3)
|
||||
end
|
||||
if not obj or not obj.GetScript or not obj:HasScript(method) then
|
||||
error(format("%s: You can only hook a script on a frame object", usage), 3)
|
||||
end
|
||||
else
|
||||
local issecure
|
||||
if obj then
|
||||
issecure = onceSecure[obj] and onceSecure[obj][method] or issecurevariable(obj, method)
|
||||
else
|
||||
issecure = onceSecure[method] or issecurevariable(method)
|
||||
end
|
||||
if issecure then
|
||||
if forceSecure then
|
||||
if obj then
|
||||
onceSecure[obj] = onceSecure[obj] or {}
|
||||
onceSecure[obj][method] = true
|
||||
else
|
||||
onceSecure[method] = true
|
||||
end
|
||||
elseif not secure then
|
||||
error(format("%s: Attempt to hook secure function %s. Use `SecureHook' or add `true' to the argument list to override.", usage, method), 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local uid
|
||||
if obj then
|
||||
uid = registry[self][obj] and registry[self][obj][method]
|
||||
else
|
||||
uid = registry[self][method]
|
||||
end
|
||||
|
||||
if uid then
|
||||
if actives[uid] then
|
||||
-- Only two sane choices exist here. We either a) error 100% of the time or b) always unhook and then hook
|
||||
-- choice b would likely lead to odd debuging conditions or other mysteries so we're going with a.
|
||||
error(format("Attempting to rehook already active hook %s.", method))
|
||||
end
|
||||
|
||||
if handlers[uid] == handler then -- turn on a decative hook, note enclosures break this ability, small memory leak
|
||||
actives[uid] = true
|
||||
return
|
||||
elseif obj then -- is there any reason not to call unhook instead of doing the following several lines?
|
||||
if self.hooks and self.hooks[obj] then
|
||||
self.hooks[obj][method] = nil
|
||||
end
|
||||
registry[self][obj][method] = nil
|
||||
else
|
||||
if self.hooks then
|
||||
self.hooks[method] = nil
|
||||
end
|
||||
registry[self][method] = nil
|
||||
end
|
||||
handlers[uid], actives[uid], scripts[uid] = nil, nil, nil
|
||||
uid = nil
|
||||
end
|
||||
|
||||
local orig
|
||||
if script then
|
||||
orig = obj:GetScript(method) or donothing
|
||||
elseif obj then
|
||||
orig = obj[method]
|
||||
else
|
||||
orig = _G[method]
|
||||
end
|
||||
|
||||
if not orig then
|
||||
error(format("%s: Attempting to hook a non existing target", usage), 3)
|
||||
end
|
||||
|
||||
uid = createHook(self, handler, orig, secure, not (raw or secure))
|
||||
|
||||
if obj then
|
||||
self.hooks[obj] = self.hooks[obj] or {}
|
||||
registry[self][obj] = registry[self][obj] or {}
|
||||
registry[self][obj][method] = uid
|
||||
|
||||
if not secure then
|
||||
self.hooks[obj][method] = orig
|
||||
end
|
||||
|
||||
if script then
|
||||
-- If the script is empty before, HookScript will not work, so use SetScript instead
|
||||
-- This will make the hook insecure, but shouldnt matter, since it was empty before.
|
||||
-- It does not taint the full frame.
|
||||
if not secure or orig == donothing then
|
||||
obj:SetScript(method, uid)
|
||||
elseif secure then
|
||||
obj:HookScript(method, uid)
|
||||
end
|
||||
else
|
||||
if not secure then
|
||||
obj[method] = uid
|
||||
else
|
||||
hooksecurefunc(obj, method, uid)
|
||||
end
|
||||
end
|
||||
else
|
||||
registry[self][method] = uid
|
||||
|
||||
if not secure then
|
||||
_G[method] = uid
|
||||
self.hooks[method] = orig
|
||||
else
|
||||
hooksecurefunc(method, uid)
|
||||
end
|
||||
end
|
||||
|
||||
actives[uid], handlers[uid], scripts[uid] = true, handler, script and true or nil
|
||||
end
|
||||
|
||||
--- Hook a function or a method on an object.
|
||||
-- The hook created will be a "safe hook", that means that your handler will be called
|
||||
-- before the hooked function ("Pre-Hook"), and you don't have to call the original function yourself,
|
||||
-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
|
||||
-- This type of hook is typically used if you need to know if some function got called, and don't want to modify it.
|
||||
-- @paramsig [object], method, [handler], [hookSecure]
|
||||
-- @param object The object to hook a method from
|
||||
-- @param method If object was specified, the name of the method, or the name of the function to hook.
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
|
||||
-- @param hookSecure If true, AceHook will allow hooking of secure functions.
|
||||
-- @usage
|
||||
-- -- create an addon with AceHook embeded
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
|
||||
-- self:Hook("ActionButton_UpdateHotkeys", true)
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
|
||||
-- print(button:GetName() .. " is updating its HotKey")
|
||||
-- end
|
||||
function AceHook:Hook(object, method, handler, hookSecure)
|
||||
if type(object) == "string" then
|
||||
method, handler, hookSecure, object = object, method, handler, nil
|
||||
end
|
||||
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
|
||||
hook(self, object, method, handler, false, false, false, hookSecure or false, "Usage: Hook([object], method, [handler], [hookSecure])")
|
||||
end
|
||||
|
||||
--- RawHook a function or a method on an object.
|
||||
-- The hook created will be a "raw hook", that means that your handler will completly replace
|
||||
-- the original function, and your handler has to call the original function (or not, depending on your intentions).\\
|
||||
-- The original function will be stored in `self.hooks[object][method]` or `self.hooks[functionName]` respectively.\\
|
||||
-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
|
||||
-- or want to control execution of the original function.
|
||||
-- @paramsig [object], method, [handler], [hookSecure]
|
||||
-- @param object The object to hook a method from
|
||||
-- @param method If object was specified, the name of the method, or the name of the function to hook.
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
|
||||
-- @param hookSecure If true, AceHook will allow hooking of secure functions.
|
||||
-- @usage
|
||||
-- -- create an addon with AceHook embeded
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- -- Hook ActionButton_UpdateHotkeys, overwriting the secure status
|
||||
-- self:RawHook("ActionButton_UpdateHotkeys", true)
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:ActionButton_UpdateHotkeys(button, type)
|
||||
-- if button:GetName() == "MyButton" then
|
||||
-- -- do stuff here
|
||||
-- else
|
||||
-- self.hooks.ActionButton_UpdateHotkeys(button, type)
|
||||
-- end
|
||||
-- end
|
||||
function AceHook:RawHook(object, method, handler, hookSecure)
|
||||
if type(object) == "string" then
|
||||
method, handler, hookSecure, object = object, method, handler, nil
|
||||
end
|
||||
|
||||
if handler == true then
|
||||
handler, hookSecure = nil, true
|
||||
end
|
||||
|
||||
hook(self, object, method, handler, false, false, true, hookSecure or false, "Usage: RawHook([object], method, [handler], [hookSecure])")
|
||||
end
|
||||
|
||||
--- SecureHook a function or a method on an object.
|
||||
-- This function is a wrapper around the `hooksecurefunc` function in the WoW API. Using AceHook
|
||||
-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
|
||||
-- required anymore, or the addon is being disabled.\\
|
||||
-- Secure Hooks should be used if the secure-status of the function is vital to its function,
|
||||
-- and taint would block execution. Secure Hooks are always called after the original function was called
|
||||
-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
|
||||
-- @paramsig [object], method, [handler]
|
||||
-- @param object The object to hook a method from
|
||||
-- @param method If object was specified, the name of the method, or the name of the function to hook.
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked function)
|
||||
function AceHook:SecureHook(object, method, handler)
|
||||
if type(object) == "string" then
|
||||
method, handler, object = object, method, nil
|
||||
end
|
||||
|
||||
hook(self, object, method, handler, false, true, false, false, "Usage: SecureHook([object], method, [handler])")
|
||||
end
|
||||
|
||||
--- Hook a script handler on a frame.
|
||||
-- The hook created will be a "safe hook", that means that your handler will be called
|
||||
-- before the hooked script ("Pre-Hook"), and you don't have to call the original function yourself,
|
||||
-- however you cannot stop the execution of the function, or modify any of the arguments/return values.\\
|
||||
-- This is the frame script equivalent of the :Hook safe-hook. It would typically be used to be notified
|
||||
-- when a certain event happens to a frame.
|
||||
-- @paramsig frame, script, [handler]
|
||||
-- @param frame The Frame to hook the script on
|
||||
-- @param script The script to hook
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
|
||||
-- @usage
|
||||
-- -- create an addon with AceHook embeded
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- -- Hook the OnShow of FriendsFrame
|
||||
-- self:HookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:FriendsFrameOnShow(frame)
|
||||
-- print("The FriendsFrame was shown!")
|
||||
-- end
|
||||
function AceHook:HookScript(frame, script, handler)
|
||||
hook(self, frame, script, handler, true, false, false, false, "Usage: HookScript(object, method, [handler])")
|
||||
end
|
||||
|
||||
--- RawHook a script handler on a frame.
|
||||
-- The hook created will be a "raw hook", that means that your handler will completly replace
|
||||
-- the original script, and your handler has to call the original script (or not, depending on your intentions).\\
|
||||
-- The original script will be stored in `self.hooks[frame][script]`.\\
|
||||
-- This type of hook can be used for all purposes, and is usually the most common case when you need to modify arguments
|
||||
-- or want to control execution of the original script.
|
||||
-- @paramsig frame, script, [handler]
|
||||
-- @param frame The Frame to hook the script on
|
||||
-- @param script The script to hook
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
|
||||
-- @usage
|
||||
-- -- create an addon with AceHook embeded
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("HookDemo", "AceHook-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- -- Hook the OnShow of FriendsFrame
|
||||
-- self:RawHookScript(FriendsFrame, "OnShow", "FriendsFrameOnShow")
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:FriendsFrameOnShow(frame)
|
||||
-- -- Call the original function
|
||||
-- self.hooks[frame].OnShow(frame)
|
||||
-- -- Do our processing
|
||||
-- -- .. stuff
|
||||
-- end
|
||||
function AceHook:RawHookScript(frame, script, handler)
|
||||
hook(self, frame, script, handler, true, false, true, false, "Usage: RawHookScript(object, method, [handler])")
|
||||
end
|
||||
|
||||
--- SecureHook a script handler on a frame.
|
||||
-- This function is a wrapper around the `frame:HookScript` function in the WoW API. Using AceHook
|
||||
-- extends the functionality of secure hooks, and adds the ability to unhook once the hook isn't
|
||||
-- required anymore, or the addon is being disabled.\\
|
||||
-- Secure Hooks should be used if the secure-status of the function is vital to its function,
|
||||
-- and taint would block execution. Secure Hooks are always called after the original function was called
|
||||
-- ("Post Hook"), and you cannot modify the arguments, return values or control the execution.
|
||||
-- @paramsig frame, script, [handler]
|
||||
-- @param frame The Frame to hook the script on
|
||||
-- @param script The script to hook
|
||||
-- @param handler The handler for the hook, a funcref or a method name. (Defaults to the name of the hooked script)
|
||||
function AceHook:SecureHookScript(frame, script, handler)
|
||||
hook(self, frame, script, handler, true, true, false, false, "Usage: SecureHookScript(object, method, [handler])")
|
||||
end
|
||||
|
||||
--- Unhook from the specified function, method or script.
|
||||
-- @paramsig [obj], method
|
||||
-- @param obj The object or frame to unhook from
|
||||
-- @param method The name of the method, function or script to unhook from.
|
||||
function AceHook:Unhook(obj, method)
|
||||
local usage = "Usage: Unhook([obj], method)"
|
||||
if type(obj) == "string" then
|
||||
method, obj = obj, nil
|
||||
end
|
||||
|
||||
if obj and type(obj) ~= "table" then
|
||||
error(format("%s: 'obj' - expecting nil or table got %s", usage, type(obj)), 2)
|
||||
end
|
||||
if type(method) ~= "string" then
|
||||
error(format("%s: 'method' - expeting string got %s", usage, type(method)), 2)
|
||||
end
|
||||
|
||||
local uid
|
||||
if obj then
|
||||
uid = registry[self][obj] and registry[self][obj][method]
|
||||
else
|
||||
uid = registry[self][method]
|
||||
end
|
||||
|
||||
if not uid or not actives[uid] then
|
||||
-- Declining to error on an unneeded unhook since the end effect is the same and this would just be annoying.
|
||||
return false
|
||||
end
|
||||
|
||||
actives[uid], handlers[uid] = nil, nil
|
||||
|
||||
if obj then
|
||||
registry[self][obj][method] = nil
|
||||
registry[self][obj] = next(registry[self][obj]) and registry[self][obj] or nil
|
||||
|
||||
-- if the hook reference doesnt exist, then its a secure hook, just bail out and dont do any unhooking
|
||||
if not self.hooks[obj] or not self.hooks[obj][method] then return true end
|
||||
|
||||
if scripts[uid] and obj:GetScript(method) == uid then -- unhooks scripts
|
||||
obj:SetScript(method, self.hooks[obj][method] ~= donothing and self.hooks[obj][method] or nil)
|
||||
scripts[uid] = nil
|
||||
elseif obj and self.hooks[obj] and self.hooks[obj][method] and obj[method] == uid then -- unhooks methods
|
||||
obj[method] = self.hooks[obj][method]
|
||||
end
|
||||
|
||||
self.hooks[obj][method] = nil
|
||||
self.hooks[obj] = next(self.hooks[obj]) and self.hooks[obj] or nil
|
||||
else
|
||||
registry[self][method] = nil
|
||||
|
||||
-- if self.hooks[method] doesn't exist, then this is a SecureHook, just bail out
|
||||
if not self.hooks[method] then return true end
|
||||
|
||||
if self.hooks[method] and _G[method] == uid then -- unhooks functions
|
||||
_G[method] = self.hooks[method]
|
||||
end
|
||||
|
||||
self.hooks[method] = nil
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- Unhook all existing hooks for this addon.
|
||||
function AceHook:UnhookAll()
|
||||
for key, value in pairs(registry[self]) do
|
||||
if type(key) == "table" then
|
||||
for method in pairs(value) do
|
||||
self:Unhook(key, method)
|
||||
end
|
||||
else
|
||||
self:Unhook(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Check if the specific function, method or script is already hooked.
|
||||
-- @paramsig [obj], method
|
||||
-- @param obj The object or frame to unhook from
|
||||
-- @param method The name of the method, function or script to unhook from.
|
||||
function AceHook:IsHooked(obj, method)
|
||||
-- we don't check if registry[self] exists, this is done by evil magicks in the metatable
|
||||
if type(obj) == "string" then
|
||||
if registry[self][obj] and actives[registry[self][obj]] then
|
||||
return true, handlers[registry[self][obj]]
|
||||
end
|
||||
else
|
||||
if registry[self][obj] and registry[self][obj][method] and actives[registry[self][obj][method]] then
|
||||
return true, handlers[registry[self][obj][method]]
|
||||
end
|
||||
end
|
||||
|
||||
return false, nil
|
||||
end
|
||||
|
||||
--- Upgrade our old embeded
|
||||
for target, v in pairs( AceHook.embeded ) do
|
||||
AceHook:Embed( target )
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceHook-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,136 @@
|
||||
--- **AceLocale-3.0** manages localization in addons, allowing for multiple locale to be registered with fallback to the base locale for untranslated strings.
|
||||
-- @class file
|
||||
-- @name AceLocale-3.0
|
||||
-- @release $Id: AceLocale-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
|
||||
local MAJOR,MINOR = "AceLocale-3.0", 2
|
||||
|
||||
local AceLocale, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceLocale then return end -- no upgrade needed
|
||||
|
||||
-- Lua APIs
|
||||
local assert, tostring, error = assert, tostring, error
|
||||
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: GAME_LOCALE, geterrorhandler
|
||||
|
||||
local gameLocale = GetLocale()
|
||||
if gameLocale == "enGB" then
|
||||
gameLocale = "enUS"
|
||||
end
|
||||
|
||||
AceLocale.apps = AceLocale.apps or {} -- array of ["AppName"]=localetableref
|
||||
AceLocale.appnames = AceLocale.appnames or {} -- array of [localetableref]="AppName"
|
||||
|
||||
-- This metatable is used on all tables returned from GetLocale
|
||||
local readmeta = {
|
||||
__index = function(self, key) -- requesting totally unknown entries: fire off a nonbreaking error and return key
|
||||
rawset(self, key, key) -- only need to see the warning once, really
|
||||
geterrorhandler()(MAJOR..": "..tostring(AceLocale.appnames[self])..": Missing entry for '"..tostring(key).."'")
|
||||
return key
|
||||
end
|
||||
}
|
||||
|
||||
-- This metatable is used on all tables returned from GetLocale if the silent flag is true, it does not issue a warning on unknown keys
|
||||
local readmetasilent = {
|
||||
__index = function(self, key) -- requesting totally unknown entries: return key
|
||||
rawset(self, key, key) -- only need to invoke this function once
|
||||
return key
|
||||
end
|
||||
}
|
||||
|
||||
-- Remember the locale table being registered right now (it gets set by :NewLocale())
|
||||
-- NOTE: Do never try to register 2 locale tables at once and mix their definition.
|
||||
local registering
|
||||
|
||||
-- local assert false function
|
||||
local assertfalse = function() assert(false) end
|
||||
|
||||
-- This metatable proxy is used when registering nondefault locales
|
||||
local writeproxy = setmetatable({}, {
|
||||
__newindex = function(self, key, value)
|
||||
rawset(registering, key, value == true and key or value) -- assigning values: replace 'true' with key string
|
||||
end,
|
||||
__index = assertfalse
|
||||
})
|
||||
|
||||
-- This metatable proxy is used when registering the default locale.
|
||||
-- It refuses to overwrite existing values
|
||||
-- Reason 1: Allows loading locales in any order
|
||||
-- Reason 2: If 2 modules have the same string, but only the first one to be
|
||||
-- loaded has a translation for the current locale, the translation
|
||||
-- doesn't get overwritten.
|
||||
--
|
||||
local writedefaultproxy = setmetatable({}, {
|
||||
__newindex = function(self, key, value)
|
||||
if not rawget(registering, key) then
|
||||
rawset(registering, key, value == true and key or value)
|
||||
end
|
||||
end,
|
||||
__index = assertfalse
|
||||
})
|
||||
|
||||
--- Register a new locale (or extend an existing one) for the specified application.
|
||||
-- :NewLocale will return a table you can fill your locale into, or nil if the locale isn't needed for the players
|
||||
-- game locale.
|
||||
-- @paramsig application, locale[, isDefault[, silent]]
|
||||
-- @param application Unique name of addon / module
|
||||
-- @param locale Name of the locale to register, e.g. "enUS", "deDE", etc.
|
||||
-- @param isDefault If this is the default locale being registered (your addon is written in this language, generally enUS)
|
||||
-- @param silent If true, the locale will not issue warnings for missing keys. Can only be set on the default locale.
|
||||
-- @usage
|
||||
-- -- enUS.lua
|
||||
-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "enUS", true)
|
||||
-- L["string1"] = true
|
||||
--
|
||||
-- -- deDE.lua
|
||||
-- local L = LibStub("AceLocale-3.0"):NewLocale("TestLocale", "deDE")
|
||||
-- if not L then return end
|
||||
-- L["string1"] = "Zeichenkette1"
|
||||
-- @return Locale Table to add localizations to, or nil if the current locale is not required.
|
||||
function AceLocale:NewLocale(application, locale, isDefault, silent)
|
||||
|
||||
if silent and not isDefault then
|
||||
error("Usage: NewLocale(application, locale[, isDefault[, silent]]): 'silent' can only be specified for the default locale", 2)
|
||||
end
|
||||
|
||||
-- GAME_LOCALE allows translators to test translations of addons without having that wow client installed
|
||||
-- Ammo: I still think this is a bad idea, for instance an addon that checks for some ingame string will fail, just because some other addon
|
||||
-- gives the user the illusion that they can run in a different locale? Ditch this whole thing or allow a setting per 'application'. I'm of the
|
||||
-- opinion to remove this.
|
||||
local gameLocale = GAME_LOCALE or gameLocale
|
||||
|
||||
if locale ~= gameLocale and not isDefault then
|
||||
return -- nop, we don't need these translations
|
||||
end
|
||||
|
||||
local app = AceLocale.apps[application]
|
||||
|
||||
if not app then
|
||||
app = setmetatable({}, silent and readmetasilent or readmeta)
|
||||
AceLocale.apps[application] = app
|
||||
AceLocale.appnames[app] = application
|
||||
end
|
||||
|
||||
registering = app -- remember globally for writeproxy and writedefaultproxy
|
||||
|
||||
if isDefault then
|
||||
return writedefaultproxy
|
||||
end
|
||||
|
||||
return writeproxy
|
||||
end
|
||||
|
||||
--- Returns localizations for the current locale (or default locale if translations are missing).
|
||||
-- Errors if nothing is registered (spank developer, not just a missing translation)
|
||||
-- @param application Unique name of addon / module
|
||||
-- @param silent If true, the locale is optional, silently return nil if it's not found (defaults to false, optional)
|
||||
-- @return The locale table for the current language.
|
||||
function AceLocale:GetLocale(application, silent)
|
||||
if not silent and not AceLocale.apps[application] then
|
||||
error("Usage: GetLocale(application[, silent]): 'application' - No locales registered for '"..tostring(application).."'", 2)
|
||||
end
|
||||
return AceLocale.apps[application]
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceLocale-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,473 @@
|
||||
--- **AceTimer-3.0** provides a central facility for registering timers.
|
||||
-- AceTimer supports one-shot timers and repeating timers. All timers are stored in an efficient
|
||||
-- data structure that allows easy dispatching and fast rescheduling. Timers can be registered, rescheduled
|
||||
-- or canceled at any time, even from within a running timer, without conflict or large overhead.\\
|
||||
-- AceTimer is currently limited to firing timers at a frequency of 0.1s. This constant may change
|
||||
-- in the future, but for now it seemed like a good compromise in efficiency and accuracy.
|
||||
--
|
||||
-- All `:Schedule` functions will return a handle to the current timer, which you will need to store if you
|
||||
-- need to cancel or reschedule the timer you just registered.
|
||||
--
|
||||
-- **AceTimer-3.0** can be embeded into your addon, either explicitly by calling AceTimer:Embed(MyAddon) or by
|
||||
-- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
|
||||
-- and can be accessed directly, without having to explicitly call AceTimer itself.\\
|
||||
-- It is recommended to embed AceTimer, otherwise you'll have to specify a custom `self` on all calls you
|
||||
-- make into AceTimer.
|
||||
-- @class file
|
||||
-- @name AceTimer-3.0
|
||||
-- @release $Id: AceTimer-3.0.lua 895 2009-12-06 16:28:55Z nevcairiel $
|
||||
|
||||
--[[
|
||||
Basic assumptions:
|
||||
* In a typical system, we do more re-scheduling per second than there are timer pulses per second
|
||||
* Regardless of timer implementation, we cannot guarantee timely delivery due to FPS restriction (may be as low as 10)
|
||||
|
||||
This implementation:
|
||||
CON: The smallest timer interval is constrained by HZ (currently 1/10s).
|
||||
PRO: It will still correctly fire any timer slower than HZ over a length of time, e.g. 0.11s interval -> 90 times over 10 seconds
|
||||
PRO: In lag bursts, the system simly skips missed timer intervals to decrease load
|
||||
CON: Algorithms depending on a timer firing "N times per minute" will fail
|
||||
PRO: (Re-)scheduling is O(1) with a VERY small constant. It's a simple linked list insertion in a hash bucket.
|
||||
CAUTION: The BUCKETS constant constrains how many timers can be efficiently handled. With too many hash collisions, performance will decrease.
|
||||
|
||||
Major assumptions upheld:
|
||||
- ALLOWS scheduling multiple timers with the same funcref/method
|
||||
- ALLOWS scheduling more timers during OnUpdate processing
|
||||
- ALLOWS unscheduling ANY timer (including the current running one) at any time, including during OnUpdate processing
|
||||
]]
|
||||
|
||||
local MAJOR, MINOR = "AceTimer-3.0", 5
|
||||
local AceTimer, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not AceTimer then return end -- No upgrade needed
|
||||
|
||||
AceTimer.hash = AceTimer.hash or {} -- Array of [0..BUCKET-1] = linked list of timers (using .next member)
|
||||
-- Linked list gets around ACE-88 and ACE-90.
|
||||
AceTimer.selfs = AceTimer.selfs or {} -- Array of [self]={[handle]=timerobj, [handle2]=timerobj2, ...}
|
||||
AceTimer.frame = AceTimer.frame or CreateFrame("Frame", "AceTimer30Frame")
|
||||
|
||||
-- Lua APIs
|
||||
local assert, error, loadstring = assert, error, loadstring
|
||||
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
|
||||
local select, pairs, type, next, tostring = select, pairs, type, next, tostring
|
||||
local floor, max, min = math.floor, math.max, math.min
|
||||
local tconcat = table.concat
|
||||
|
||||
-- WoW APIs
|
||||
local GetTime = GetTime
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: DEFAULT_CHAT_FRAME, geterrorhandler
|
||||
|
||||
-- Simple ONE-SHOT timer cache. Much more efficient than a full compost for our purposes.
|
||||
local timerCache = nil
|
||||
|
||||
--[[
|
||||
Timers will not be fired more often than HZ-1 times per second.
|
||||
Keep at intended speed PLUS ONE or we get bitten by floating point rounding errors (n.5 + 0.1 can be n.599999)
|
||||
If this is ever LOWERED, all existing timers need to be enforced to have a delay >= 1/HZ on lib upgrade.
|
||||
If this number is ever changed, all entries need to be rehashed on lib upgrade.
|
||||
]]
|
||||
local HZ = 11
|
||||
|
||||
--[[
|
||||
Prime for good distribution
|
||||
If this number is ever changed, all entries need to be rehashed on lib upgrade.
|
||||
]]
|
||||
local BUCKETS = 131
|
||||
|
||||
local hash = AceTimer.hash
|
||||
for i=1,BUCKETS do
|
||||
hash[i] = hash[i] or false -- make it an integer-indexed array; it's faster than hashes
|
||||
end
|
||||
|
||||
--[[
|
||||
xpcall safecall implementation
|
||||
]]
|
||||
local xpcall = xpcall
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
|
||||
local function CreateDispatcher(argCount)
|
||||
local code = [[
|
||||
local xpcall, eh = ... -- our arguments are received as unnamed values in "..." since we don't have a proper function declaration
|
||||
local method, ARGS
|
||||
local function call() return method(ARGS) end
|
||||
|
||||
local function dispatch(func, ...)
|
||||
method = func
|
||||
if not method then return end
|
||||
ARGS = ...
|
||||
return xpcall(call, eh)
|
||||
end
|
||||
|
||||
return dispatch
|
||||
]]
|
||||
|
||||
local ARGS = {}
|
||||
for i = 1, argCount do ARGS[i] = "arg"..i end
|
||||
code = code:gsub("ARGS", tconcat(ARGS, ", "))
|
||||
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(xpcall, errorhandler)
|
||||
end
|
||||
|
||||
local Dispatchers = setmetatable({}, {
|
||||
__index=function(self, argCount)
|
||||
local dispatcher = CreateDispatcher(argCount)
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end
|
||||
})
|
||||
Dispatchers[0] = function(func)
|
||||
return xpcall(func, errorhandler)
|
||||
end
|
||||
|
||||
local function safecall(func, ...)
|
||||
return Dispatchers[select('#', ...)](func, ...)
|
||||
end
|
||||
|
||||
local lastint = floor(GetTime() * HZ)
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- OnUpdate handler
|
||||
--
|
||||
-- traverse buckets, always chasing "now", and fire timers that have expired
|
||||
|
||||
local function OnUpdate()
|
||||
local now = GetTime()
|
||||
local nowint = floor(now * HZ)
|
||||
|
||||
-- Have we passed into a new hash bucket?
|
||||
if nowint == lastint then return end
|
||||
|
||||
local soon = now + 1 -- +1 is safe as long as 1 < HZ < BUCKETS/2
|
||||
|
||||
-- Pass through each bucket at most once
|
||||
-- Happens on e.g. instance loads, but COULD happen on high local load situations also
|
||||
for curint = (max(lastint, nowint - BUCKETS) + 1), nowint do -- loop until we catch up with "now", usually only 1 iteration
|
||||
local curbucket = (curint % BUCKETS)+1
|
||||
-- Yank the list of timers out of the bucket and empty it. This allows reinsertion in the currently-processed bucket from callbacks.
|
||||
local nexttimer = hash[curbucket]
|
||||
hash[curbucket] = false -- false rather than nil to prevent the array from becoming a hash
|
||||
|
||||
while nexttimer do
|
||||
local timer = nexttimer
|
||||
nexttimer = timer.next
|
||||
local when = timer.when
|
||||
|
||||
if when < soon then
|
||||
-- Call the timer func, either as a method on given object, or a straight function ref
|
||||
local callback = timer.callback
|
||||
if type(callback) == "string" then
|
||||
safecall(timer.object[callback], timer.object, timer.arg)
|
||||
elseif callback then
|
||||
safecall(callback, timer.arg)
|
||||
else
|
||||
-- probably nilled out by CancelTimer
|
||||
timer.delay = nil -- don't reschedule it
|
||||
end
|
||||
|
||||
local delay = timer.delay -- NOW make a local copy, can't do it earlier in case the timer cancelled itself in the callback
|
||||
|
||||
if not delay then
|
||||
-- single-shot timer (or cancelled)
|
||||
AceTimer.selfs[timer.object][tostring(timer)] = nil
|
||||
timerCache = timer
|
||||
else
|
||||
-- repeating timer
|
||||
local newtime = when + delay
|
||||
if newtime < now then -- Keep lag from making us firing a timer unnecessarily. (Note that this still won't catch too-short-delay timers though.)
|
||||
newtime = now + delay
|
||||
end
|
||||
timer.when = newtime
|
||||
|
||||
-- add next timer execution to the correct bucket
|
||||
local bucket = (floor(newtime * HZ) % BUCKETS) + 1
|
||||
timer.next = hash[bucket]
|
||||
hash[bucket] = timer
|
||||
end
|
||||
else -- if when>=soon
|
||||
-- reinsert (yeah, somewhat expensive, but shouldn't be happening too often either due to hash distribution)
|
||||
timer.next = hash[curbucket]
|
||||
hash[curbucket] = timer
|
||||
end -- if when<soon ... else
|
||||
end -- while nexttimer do
|
||||
end -- for curint=lastint,nowint
|
||||
|
||||
lastint = nowint
|
||||
end
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Reg( callback, delay, arg, repeating )
|
||||
--
|
||||
-- callback( function or string ) - direct function ref or method name in our object for the callback
|
||||
-- delay(int) - delay for the timer
|
||||
-- arg(variant) - any argument to be passed to the callback function
|
||||
-- repeating(boolean) - repeating timer, or oneshot
|
||||
--
|
||||
-- returns the handle of the timer for later processing (canceling etc)
|
||||
local function Reg(self, callback, delay, arg, repeating)
|
||||
if type(callback) ~= "string" and type(callback) ~= "function" then
|
||||
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
|
||||
error(MAJOR..": " .. error_origin .. "(callback, delay, arg): 'callback' - function or method name expected.", 3)
|
||||
end
|
||||
if type(callback) == "string" then
|
||||
if type(self)~="table" then
|
||||
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
|
||||
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'self' - must be a table.", 3)
|
||||
end
|
||||
if type(self[callback]) ~= "function" then
|
||||
local error_origin = repeating and "ScheduleRepeatingTimer" or "ScheduleTimer"
|
||||
error(MAJOR..": " .. error_origin .. "(\"methodName\", delay, arg): 'methodName' - method not found on target object.", 3)
|
||||
end
|
||||
end
|
||||
|
||||
if delay < (1 / (HZ - 1)) then
|
||||
delay = 1 / (HZ - 1)
|
||||
end
|
||||
|
||||
-- Create and stuff timer in the correct hash bucket
|
||||
local now = GetTime()
|
||||
|
||||
local timer = timerCache or {} -- Get new timer object (from cache if available)
|
||||
timerCache = nil
|
||||
|
||||
timer.object = self
|
||||
timer.callback = callback
|
||||
timer.delay = (repeating and delay)
|
||||
timer.arg = arg
|
||||
timer.when = now + delay
|
||||
|
||||
local bucket = (floor((now+delay)*HZ) % BUCKETS) + 1
|
||||
timer.next = hash[bucket]
|
||||
hash[bucket] = timer
|
||||
|
||||
-- Insert timer in our self->handle->timer registry
|
||||
local handle = tostring(timer)
|
||||
|
||||
local selftimers = AceTimer.selfs[self]
|
||||
if not selftimers then
|
||||
selftimers = {}
|
||||
AceTimer.selfs[self] = selftimers
|
||||
end
|
||||
selftimers[handle] = timer
|
||||
selftimers.__ops = (selftimers.__ops or 0) + 1
|
||||
|
||||
return handle
|
||||
end
|
||||
|
||||
--- Schedule a new one-shot timer.
|
||||
-- The timer will fire once in `delay` seconds, unless canceled before.
|
||||
-- @param callback Callback function for the timer pulse (funcref or method name).
|
||||
-- @param delay Delay for the timer, in seconds.
|
||||
-- @param arg An optional argument to be passed to the callback function.
|
||||
-- @usage
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- self:ScheduleTimer("TimerFeedback", 5)
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:TimerFeedback()
|
||||
-- print("5 seconds passed")
|
||||
-- end
|
||||
function AceTimer:ScheduleTimer(callback, delay, arg)
|
||||
return Reg(self, callback, delay, arg)
|
||||
end
|
||||
|
||||
--- Schedule a repeating timer.
|
||||
-- The timer will fire every `delay` seconds, until canceled.
|
||||
-- @param callback Callback function for the timer pulse (funcref or method name).
|
||||
-- @param delay Delay for the timer, in seconds.
|
||||
-- @param arg An optional argument to be passed to the callback function.
|
||||
-- @usage
|
||||
-- MyAddon = LibStub("AceAddon-3.0"):NewAddon("TimerTest", "AceTimer-3.0")
|
||||
--
|
||||
-- function MyAddon:OnEnable()
|
||||
-- self.timerCount = 0
|
||||
-- self.testTimer = self:ScheduleRepeatingTimer("TimerFeedback", 5)
|
||||
-- end
|
||||
--
|
||||
-- function MyAddon:TimerFeedback()
|
||||
-- self.timerCount = self.timerCount + 1
|
||||
-- print(("%d seconds passed"):format(5 * self.timerCount))
|
||||
-- -- run 30 seconds in total
|
||||
-- if self.timerCount == 6 then
|
||||
-- self:CancelTimer(self.testTimer)
|
||||
-- end
|
||||
-- end
|
||||
function AceTimer:ScheduleRepeatingTimer(callback, delay, arg)
|
||||
return Reg(self, callback, delay, arg, true)
|
||||
end
|
||||
|
||||
--- Cancels a timer with the given handle, registered by the same addon object as used for `:ScheduleTimer`
|
||||
-- Both one-shot and repeating timers can be canceled with this function, as long as the `handle` is valid
|
||||
-- and the timer has not fired yet or was canceled before.
|
||||
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
|
||||
-- @param silent If true, no error is raised if the timer handle is invalid (expired or already canceled)
|
||||
-- @return True if the timer was successfully cancelled.
|
||||
function AceTimer:CancelTimer(handle, silent)
|
||||
if not handle then return end -- nil handle -> bail out without erroring
|
||||
if type(handle) ~= "string" then
|
||||
error(MAJOR..": CancelTimer(handle): 'handle' - expected a string", 2) -- for now, anyway
|
||||
end
|
||||
local selftimers = AceTimer.selfs[self]
|
||||
local timer = selftimers and selftimers[handle]
|
||||
if silent then
|
||||
if timer then
|
||||
timer.callback = nil -- don't run it again
|
||||
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
|
||||
-- The timer object is removed in the OnUpdate loop
|
||||
end
|
||||
return not not timer -- might return "true" even if we double-cancel. we'll live.
|
||||
else
|
||||
if not timer then
|
||||
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - no such timer registered")
|
||||
return false
|
||||
end
|
||||
if not timer.callback then
|
||||
geterrorhandler()(MAJOR..": CancelTimer(handle[, silent]): '"..tostring(handle).."' - timer already cancelled or expired")
|
||||
return false
|
||||
end
|
||||
timer.callback = nil -- don't run it again
|
||||
timer.delay = nil -- if this is the currently-executing one: don't even reschedule
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
--- Cancels all timers registered to the current addon object ('self')
|
||||
function AceTimer:CancelAllTimers()
|
||||
if not(type(self) == "string" or type(self) == "table") then
|
||||
error(MAJOR..": CancelAllTimers(): 'self' - must be a string or a table",2)
|
||||
end
|
||||
if self == AceTimer then
|
||||
error(MAJOR..": CancelAllTimers(): supply a meaningful 'self'", 2)
|
||||
end
|
||||
|
||||
local selftimers = AceTimer.selfs[self]
|
||||
if selftimers then
|
||||
for handle,v in pairs(selftimers) do
|
||||
if type(v) == "table" then -- avoid __ops, etc
|
||||
AceTimer.CancelTimer(self, handle, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Returns the time left for a timer with the given handle, registered by the current addon object ('self').
|
||||
-- This function will raise a warning when the handle is invalid, but not stop execution.
|
||||
-- @param handle The handle of the timer, as returned by `:ScheduleTimer` or `:ScheduleRepeatingTimer`
|
||||
-- @return The time left on the timer, or false if the handle is invalid.
|
||||
function AceTimer:TimeLeft(handle)
|
||||
if not handle then return end
|
||||
if type(handle) ~= "string" then
|
||||
error(MAJOR..": TimeLeft(handle): 'handle' - expected a string", 2) -- for now, anyway
|
||||
end
|
||||
local selftimers = AceTimer.selfs[self]
|
||||
local timer = selftimers and selftimers[handle]
|
||||
if not timer then
|
||||
geterrorhandler()(MAJOR..": TimeLeft(handle): '"..tostring(handle).."' - no such timer registered")
|
||||
return false
|
||||
end
|
||||
return timer.when - GetTime()
|
||||
end
|
||||
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- PLAYER_REGEN_ENABLED: Run through our .selfs[] array step by step
|
||||
-- and clean it out - otherwise the table indices can grow indefinitely
|
||||
-- if an addon starts and stops a lot of timers. AceBucket does this!
|
||||
--
|
||||
-- See ACE-94 and tests/AceTimer-3.0-ACE-94.lua
|
||||
|
||||
local lastCleaned = nil
|
||||
|
||||
local function OnEvent(this, event)
|
||||
if event~="PLAYER_REGEN_ENABLED" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Get the next 'self' to process
|
||||
local selfs = AceTimer.selfs
|
||||
local self = next(selfs, lastCleaned)
|
||||
if not self then
|
||||
self = next(selfs)
|
||||
end
|
||||
lastCleaned = self
|
||||
if not self then -- should only happen if .selfs[] is empty
|
||||
return
|
||||
end
|
||||
|
||||
-- Time to clean it out?
|
||||
local list = selfs[self]
|
||||
if (list.__ops or 0) < 250 then -- 250 slosh indices = ~10KB wasted (max!). For one 'self'.
|
||||
return
|
||||
end
|
||||
|
||||
-- Create a new table and copy all members over
|
||||
local newlist = {}
|
||||
local n=0
|
||||
for k,v in pairs(list) do
|
||||
newlist[k] = v
|
||||
n=n+1
|
||||
end
|
||||
newlist.__ops = 0 -- Reset operation count
|
||||
|
||||
-- And since we now have a count of the number of live timers, check that it's reasonable. Emit a warning if not.
|
||||
if n>BUCKETS then
|
||||
DEFAULT_CHAT_FRAME:AddMessage(MAJOR..": Warning: The addon/module '"..tostring(self).."' has "..n.." live timers. Surely that's not intended?")
|
||||
end
|
||||
|
||||
selfs[self] = newlist
|
||||
end
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Embed handling
|
||||
|
||||
AceTimer.embeds = AceTimer.embeds or {}
|
||||
|
||||
local mixins = {
|
||||
"ScheduleTimer", "ScheduleRepeatingTimer",
|
||||
"CancelTimer", "CancelAllTimers",
|
||||
"TimeLeft"
|
||||
}
|
||||
|
||||
function AceTimer:Embed(target)
|
||||
AceTimer.embeds[target] = true
|
||||
for _,v in pairs(mixins) do
|
||||
target[v] = AceTimer[v]
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
-- AceTimer:OnEmbedDisable( target )
|
||||
-- target (object) - target object that AceTimer is embedded in.
|
||||
--
|
||||
-- cancel all timers registered for the object
|
||||
function AceTimer:OnEmbedDisable( target )
|
||||
target:CancelAllTimers()
|
||||
end
|
||||
|
||||
|
||||
for addon in pairs(AceTimer.embeds) do
|
||||
AceTimer:Embed(addon)
|
||||
end
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Debug tools (expose copies of internals to test suites)
|
||||
AceTimer.debug = AceTimer.debug or {}
|
||||
AceTimer.debug.HZ = HZ
|
||||
AceTimer.debug.BUCKETS = BUCKETS
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Finishing touchups
|
||||
|
||||
AceTimer.frame:SetScript("OnUpdate", OnUpdate)
|
||||
AceTimer.frame:SetScript("OnEvent", OnEvent)
|
||||
AceTimer.frame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||
|
||||
-- In theory, we should hide&show the frame based on there being timers or not.
|
||||
-- However, this job is fairly expensive, and the chance that there will
|
||||
-- actually be zero timers running is diminuitive to say the lest.
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="AceTimer-3.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,240 @@
|
||||
--[[ $Id: CallbackHandler-1.0.lua 14 2010-08-09 00:43:38Z mikk $ ]]
|
||||
local MAJOR, MINOR = "CallbackHandler-1.0", 6
|
||||
local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
|
||||
|
||||
if not CallbackHandler then return end -- No upgrade needed
|
||||
|
||||
local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
|
||||
|
||||
-- Lua APIs
|
||||
local tconcat = table.concat
|
||||
local assert, error, loadstring = assert, error, loadstring
|
||||
local setmetatable, rawset, rawget = setmetatable, rawset, rawget
|
||||
local next, select, pairs, type, tostring = next, select, pairs, type, tostring
|
||||
|
||||
-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
|
||||
-- List them here for Mikk's FindGlobals script
|
||||
-- GLOBALS: geterrorhandler
|
||||
|
||||
local xpcall = xpcall
|
||||
|
||||
local function errorhandler(err)
|
||||
return geterrorhandler()(err)
|
||||
end
|
||||
|
||||
local function CreateDispatcher(argCount)
|
||||
local code = [[
|
||||
local next, xpcall, eh = ...
|
||||
|
||||
local method, ARGS
|
||||
local function call() method(ARGS) end
|
||||
|
||||
local function dispatch(handlers, ...)
|
||||
local index
|
||||
index, method = next(handlers)
|
||||
if not method then return end
|
||||
local OLD_ARGS = ARGS
|
||||
ARGS = ...
|
||||
repeat
|
||||
xpcall(call, eh)
|
||||
index, method = next(handlers, index)
|
||||
until not method
|
||||
ARGS = OLD_ARGS
|
||||
end
|
||||
|
||||
return dispatch
|
||||
]]
|
||||
|
||||
local ARGS, OLD_ARGS = {}, {}
|
||||
for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
|
||||
code = code:gsub("OLD_ARGS", tconcat(OLD_ARGS, ", ")):gsub("ARGS", tconcat(ARGS, ", "))
|
||||
return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
|
||||
end
|
||||
|
||||
local Dispatchers = setmetatable({}, {__index=function(self, argCount)
|
||||
local dispatcher = CreateDispatcher(argCount)
|
||||
rawset(self, argCount, dispatcher)
|
||||
return dispatcher
|
||||
end})
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
-- CallbackHandler:New
|
||||
--
|
||||
-- target - target object to embed public APIs in
|
||||
-- RegisterName - name of the callback registration API, default "RegisterCallback"
|
||||
-- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
|
||||
-- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
|
||||
|
||||
function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
|
||||
-- TODO: Remove this after beta has gone out
|
||||
assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
|
||||
|
||||
RegisterName = RegisterName or "RegisterCallback"
|
||||
UnregisterName = UnregisterName or "UnregisterCallback"
|
||||
if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
|
||||
UnregisterAllName = "UnregisterAllCallbacks"
|
||||
end
|
||||
|
||||
-- we declare all objects and exported APIs inside this closure to quickly gain access
|
||||
-- to e.g. function names, the "target" parameter, etc
|
||||
|
||||
|
||||
-- Create the registry object
|
||||
local events = setmetatable({}, meta)
|
||||
local registry = { recurse=0, events=events }
|
||||
|
||||
-- registry:Fire() - fires the given event/message into the registry
|
||||
function registry:Fire(eventname, ...)
|
||||
if not rawget(events, eventname) or not next(events[eventname]) then return end
|
||||
local oldrecurse = registry.recurse
|
||||
registry.recurse = oldrecurse + 1
|
||||
|
||||
Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
|
||||
|
||||
registry.recurse = oldrecurse
|
||||
|
||||
if registry.insertQueue and oldrecurse==0 then
|
||||
-- Something in one of our callbacks wanted to register more callbacks; they got queued
|
||||
for eventname,callbacks in pairs(registry.insertQueue) do
|
||||
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
|
||||
for self,func in pairs(callbacks) do
|
||||
events[eventname][self] = func
|
||||
-- fire OnUsed callback?
|
||||
if first and registry.OnUsed then
|
||||
registry.OnUsed(registry, target, eventname)
|
||||
first = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
registry.insertQueue = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Registration of a callback, handles:
|
||||
-- self["method"], leads to self["method"](self, ...)
|
||||
-- self with function ref, leads to functionref(...)
|
||||
-- "addonId" (instead of self) with function ref, leads to functionref(...)
|
||||
-- all with an optional arg, which, if present, gets passed as first argument (after self if present)
|
||||
target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
|
||||
if type(eventname) ~= "string" then
|
||||
error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
|
||||
end
|
||||
|
||||
method = method or eventname
|
||||
|
||||
local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
|
||||
|
||||
if type(method) ~= "string" and type(method) ~= "function" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
|
||||
end
|
||||
|
||||
local regfunc
|
||||
|
||||
if type(method) == "string" then
|
||||
-- self["method"] calling style
|
||||
if type(self) ~= "table" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
|
||||
elseif self==target then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
|
||||
elseif type(self[method]) ~= "function" then
|
||||
error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
|
||||
end
|
||||
|
||||
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
|
||||
local arg=select(1,...)
|
||||
regfunc = function(...) self[method](self,arg,...) end
|
||||
else
|
||||
regfunc = function(...) self[method](self,...) end
|
||||
end
|
||||
else
|
||||
-- function ref with self=object or self="addonId" or self=thread
|
||||
if type(self)~="table" and type(self)~="string" and type(self)~="thread" then
|
||||
error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string or thread expected.", 2)
|
||||
end
|
||||
|
||||
if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
|
||||
local arg=select(1,...)
|
||||
regfunc = function(...) method(arg,...) end
|
||||
else
|
||||
regfunc = method
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if events[eventname][self] or registry.recurse<1 then
|
||||
-- if registry.recurse<1 then
|
||||
-- we're overwriting an existing entry, or not currently recursing. just set it.
|
||||
events[eventname][self] = regfunc
|
||||
-- fire OnUsed callback?
|
||||
if registry.OnUsed and first then
|
||||
registry.OnUsed(registry, target, eventname)
|
||||
end
|
||||
else
|
||||
-- we're currently processing a callback in this registry, so delay the registration of this new entry!
|
||||
-- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
|
||||
registry.insertQueue = registry.insertQueue or setmetatable({},meta)
|
||||
registry.insertQueue[eventname][self] = regfunc
|
||||
end
|
||||
end
|
||||
|
||||
-- Unregister a callback
|
||||
target[UnregisterName] = function(self, eventname)
|
||||
if not self or self==target then
|
||||
error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
|
||||
end
|
||||
if type(eventname) ~= "string" then
|
||||
error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
|
||||
end
|
||||
if rawget(events, eventname) and events[eventname][self] then
|
||||
events[eventname][self] = nil
|
||||
-- Fire OnUnused callback?
|
||||
if registry.OnUnused and not next(events[eventname]) then
|
||||
registry.OnUnused(registry, target, eventname)
|
||||
end
|
||||
end
|
||||
if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
|
||||
registry.insertQueue[eventname][self] = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- OPTIONAL: Unregister all callbacks for given selfs/addonIds
|
||||
if UnregisterAllName then
|
||||
target[UnregisterAllName] = function(...)
|
||||
if select("#",...)<1 then
|
||||
error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
|
||||
end
|
||||
if select("#",...)==1 and ...==target then
|
||||
error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
|
||||
end
|
||||
|
||||
|
||||
for i=1,select("#",...) do
|
||||
local self = select(i,...)
|
||||
if registry.insertQueue then
|
||||
for eventname, callbacks in pairs(registry.insertQueue) do
|
||||
if callbacks[self] then
|
||||
callbacks[self] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
for eventname, callbacks in pairs(events) do
|
||||
if callbacks[self] then
|
||||
callbacks[self] = nil
|
||||
-- Fire OnUnused callback?
|
||||
if registry.OnUnused and not next(callbacks) then
|
||||
registry.OnUnused(registry, target, eventname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return registry
|
||||
end
|
||||
|
||||
|
||||
-- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
|
||||
-- try to upgrade old implicit embeds since the system is selfcontained and
|
||||
-- relies on closures to work.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="CallbackHandler-1.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,264 @@
|
||||
--[[
|
||||
Name: DBIcon-1.0
|
||||
Revision: $Rev: 14 $
|
||||
Author(s): Rabbit (rabbit.magtheridon@gmail.com)
|
||||
Description: Allows addons to register to recieve a lightweight minimap icon as an alternative to more heavy LDB displays.
|
||||
Dependencies: LibStub
|
||||
License: GPL v2 or later.
|
||||
]]
|
||||
|
||||
--[[
|
||||
Copyright (C) 2008-2010 Rabbit
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
]]
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
-- DBIcon-1.0
|
||||
--
|
||||
-- Disclaimer: Most of this code was ripped from Barrel but fixed, streamlined
|
||||
-- and cleaned up a lot so that it no longer sucks.
|
||||
--
|
||||
|
||||
local DBICON10 = "LibDBIcon-1.0"
|
||||
local DBICON10_MINOR = tonumber(("$Rev: 14 $"):match("(%d+)"))
|
||||
if not LibStub then error(DBICON10 .. " requires LibStub.") end
|
||||
local ldb = LibStub("LibDataBroker-1.1", true)
|
||||
if not ldb then error(DBICON10 .. " requires LibDataBroker-1.1.") end
|
||||
local lib = LibStub:NewLibrary(DBICON10, DBICON10_MINOR)
|
||||
if not lib then return end
|
||||
|
||||
lib.disabled = lib.disabled or nil
|
||||
lib.objects = lib.objects or {}
|
||||
lib.callbackRegistered = lib.callbackRegistered or nil
|
||||
lib.notCreated = lib.notCreated or {}
|
||||
|
||||
function lib:IconCallback(event, name, key, value, dataobj)
|
||||
if lib.objects[name] then
|
||||
lib.objects[name].icon:SetTexture(dataobj.icon)
|
||||
end
|
||||
end
|
||||
if not lib.callbackRegistered then
|
||||
ldb.RegisterCallback(lib, "LibDataBroker_AttributeChanged__icon", "IconCallback")
|
||||
lib.callbackRegistered = true
|
||||
end
|
||||
|
||||
-- Tooltip code ripped from StatBlockCore by Funkydude
|
||||
local function getAnchors(frame)
|
||||
local x,y = frame:GetCenter()
|
||||
if not x or not y then return "TOPLEFT", "BOTTOMLEFT" end
|
||||
local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or ""
|
||||
local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM"
|
||||
return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf
|
||||
end
|
||||
|
||||
local function onEnter(self)
|
||||
if self.isMoving then return end
|
||||
local obj = self.dataObject
|
||||
if obj.OnTooltipShow then
|
||||
GameTooltip:SetOwner(self, "ANCHOR_NONE")
|
||||
GameTooltip:SetPoint(getAnchors(self))
|
||||
obj.OnTooltipShow(GameTooltip)
|
||||
GameTooltip:Show()
|
||||
elseif obj.OnEnter then
|
||||
obj.OnEnter(self)
|
||||
end
|
||||
end
|
||||
|
||||
local function onLeave(self)
|
||||
local obj = self.dataObject
|
||||
GameTooltip:Hide()
|
||||
if obj.OnLeave then obj.OnLeave(self) end
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local minimapShapes = {
|
||||
["ROUND"] = {true, true, true, true},
|
||||
["SQUARE"] = {false, false, false, false},
|
||||
["CORNER-TOPLEFT"] = {true, false, false, false},
|
||||
["CORNER-TOPRIGHT"] = {false, false, true, false},
|
||||
["CORNER-BOTTOMLEFT"] = {false, true, false, false},
|
||||
["CORNER-BOTTOMRIGHT"] = {false, false, false, true},
|
||||
["SIDE-LEFT"] = {true, true, false, false},
|
||||
["SIDE-RIGHT"] = {false, false, true, true},
|
||||
["SIDE-TOP"] = {true, false, true, false},
|
||||
["SIDE-BOTTOM"] = {false, true, false, true},
|
||||
["TRICORNER-TOPLEFT"] = {true, true, true, false},
|
||||
["TRICORNER-TOPRIGHT"] = {true, false, true, true},
|
||||
["TRICORNER-BOTTOMLEFT"] = {true, true, false, true},
|
||||
["TRICORNER-BOTTOMRIGHT"] = {false, true, true, true},
|
||||
}
|
||||
|
||||
local function updatePosition(button)
|
||||
local angle = math.rad(button.db.minimapPos or 225)
|
||||
local x, y, q = math.cos(angle), math.sin(angle), 1
|
||||
if x < 0 then q = q + 1 end
|
||||
if y > 0 then q = q + 2 end
|
||||
local minimapShape = GetMinimapShape and GetMinimapShape() or "ROUND"
|
||||
local quadTable = minimapShapes[minimapShape]
|
||||
if quadTable[q] then
|
||||
x, y = x*80, y*80
|
||||
else
|
||||
local diagRadius = 103.13708498985 --math.sqrt(2*(80)^2)-10
|
||||
x = math.max(-80, math.min(x*diagRadius, 80))
|
||||
y = math.max(-80, math.min(y*diagRadius, 80))
|
||||
end
|
||||
button:SetPoint("CENTER", Minimap, "CENTER", x, y)
|
||||
end
|
||||
|
||||
local function onClick(self, b) if self.dataObject.OnClick then self.dataObject.OnClick(self, b) end end
|
||||
local function onMouseDown(self) self.icon:SetTexCoord(0, 1, 0, 1) end
|
||||
local function onMouseUp(self) self.icon:SetTexCoord(0.05, 0.95, 0.05, 0.95) end
|
||||
|
||||
local function onUpdate(self)
|
||||
local mx, my = Minimap:GetCenter()
|
||||
local px, py = GetCursorPosition()
|
||||
local scale = Minimap:GetEffectiveScale()
|
||||
px, py = px / scale, py / scale
|
||||
self.db.minimapPos = math.deg(math.atan2(py - my, px - mx)) % 360
|
||||
updatePosition(self)
|
||||
end
|
||||
|
||||
local function onDragStart(self)
|
||||
self:LockHighlight()
|
||||
self.icon:SetTexCoord(0, 1, 0, 1)
|
||||
self:SetScript("OnUpdate", onUpdate)
|
||||
self.isMoving = true
|
||||
GameTooltip:Hide()
|
||||
end
|
||||
|
||||
local function onDragStop(self)
|
||||
self:SetScript("OnUpdate", nil)
|
||||
self.icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
|
||||
self:UnlockHighlight()
|
||||
self.isMoving = nil
|
||||
end
|
||||
|
||||
local function createButton(name, object, db)
|
||||
local button = CreateFrame("Button", "LibDBIcon10_"..name, Minimap)
|
||||
button.dataObject = object
|
||||
button.db = db
|
||||
button:SetFrameStrata("MEDIUM")
|
||||
button:SetWidth(31); button:SetHeight(31)
|
||||
button:SetFrameLevel(8)
|
||||
button:RegisterForClicks("anyUp")
|
||||
button:RegisterForDrag("LeftButton")
|
||||
button:SetHighlightTexture("Interface\\Minimap\\UI-Minimap-ZoomButton-Highlight")
|
||||
local overlay = button:CreateTexture(nil, "OVERLAY")
|
||||
overlay:SetWidth(53); overlay:SetHeight(53)
|
||||
overlay:SetTexture("Interface\\Minimap\\MiniMap-TrackingBorder")
|
||||
overlay:SetPoint("TOPLEFT")
|
||||
local icon = button:CreateTexture(nil, "BACKGROUND")
|
||||
icon:SetWidth(20); icon:SetHeight(20)
|
||||
icon:SetTexture(object.icon)
|
||||
icon:SetTexCoord(0.05, 0.95, 0.05, 0.95)
|
||||
icon:SetPoint("TOPLEFT", 7, -5)
|
||||
button.icon = icon
|
||||
|
||||
button:SetScript("OnEnter", onEnter)
|
||||
button:SetScript("OnLeave", onLeave)
|
||||
button:SetScript("OnClick", onClick)
|
||||
button:SetScript("OnDragStart", onDragStart)
|
||||
button:SetScript("OnDragStop", onDragStop)
|
||||
button:SetScript("OnMouseDown", onMouseDown)
|
||||
button:SetScript("OnMouseUp", onMouseUp)
|
||||
|
||||
lib.objects[name] = button
|
||||
|
||||
if lib.loggedIn then
|
||||
updatePosition(button)
|
||||
if not db.hide then button:Show()
|
||||
else button:Hide() end
|
||||
end
|
||||
end
|
||||
|
||||
-- We could use a metatable.__index on lib.objects, but then we'd create
|
||||
-- the icons when checking things like :IsRegistered, which is not necessary.
|
||||
local function check(name)
|
||||
if lib.notCreated[name] then
|
||||
createButton(name, lib.notCreated[name][1], lib.notCreated[name][2])
|
||||
lib.notCreated[name] = nil
|
||||
end
|
||||
end
|
||||
|
||||
lib.loggedIn = lib.loggedIn or false
|
||||
-- Wait a bit with the initial positioning to let any GetMinimapShape addons
|
||||
-- load up.
|
||||
if not lib.loggedIn then
|
||||
local f = CreateFrame("Frame")
|
||||
f:SetScript("OnEvent", function()
|
||||
for _, object in pairs(lib.objects) do
|
||||
updatePosition(object)
|
||||
if not lib.disabled and not object.db.hide then object:Show()
|
||||
else object:Hide() end
|
||||
end
|
||||
lib.loggedIn = true
|
||||
f:SetScript("OnEvent", nil)
|
||||
f = nil
|
||||
end)
|
||||
f:RegisterEvent("PLAYER_LOGIN")
|
||||
end
|
||||
|
||||
function lib:Register(name, object, db)
|
||||
if lib.disabled then return end
|
||||
if not object.icon then error("Can't register LDB objects without icons set!") end
|
||||
if lib.objects[name] or lib.notCreated[name] then error("Already registered, nubcake.") end
|
||||
if not db or not db.hide then
|
||||
createButton(name, object, db)
|
||||
else
|
||||
lib.notCreated[name] = {object, db}
|
||||
end
|
||||
end
|
||||
|
||||
function lib:Hide(name)
|
||||
if not lib.objects[name] then return end
|
||||
lib.objects[name]:Hide()
|
||||
end
|
||||
function lib:Show(name)
|
||||
if lib.disabled then return end
|
||||
check(name)
|
||||
lib.objects[name]:Show()
|
||||
updatePosition(lib.objects[name])
|
||||
end
|
||||
function lib:IsRegistered(name)
|
||||
return (lib.objects[name] or lib.notCreated[name]) and true or false
|
||||
end
|
||||
function lib:Refresh(name, db)
|
||||
if lib.disabled then return end
|
||||
check(name)
|
||||
local button = lib.objects[name]
|
||||
if db then button.db = db end
|
||||
updatePosition(button)
|
||||
if not db.hide then button:Show() else button:Hide() end
|
||||
end
|
||||
|
||||
function lib:EnableLibrary()
|
||||
lib.disabled = nil
|
||||
for name, object in pairs(lib.objects) do
|
||||
if not object.db or (object.db and not object.db.hide) then
|
||||
object:Show()
|
||||
updatePosition(object)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function lib:DisableLibrary()
|
||||
lib.disabled = true
|
||||
for name, object in pairs(lib.objects) do
|
||||
object:Hide()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
assert(LibStub, "LibDataBroker-1.1 requires LibStub")
|
||||
assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
|
||||
|
||||
local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
|
||||
if not lib then return end
|
||||
oldminor = oldminor or 0
|
||||
|
||||
|
||||
lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
|
||||
lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {}, lib.proxystorage or {}
|
||||
local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
|
||||
|
||||
if oldminor < 2 then
|
||||
lib.domt = {
|
||||
__metatable = "access denied",
|
||||
__index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
|
||||
}
|
||||
end
|
||||
|
||||
if oldminor < 3 then
|
||||
lib.domt.__newindex = function(self, key, value)
|
||||
if not attributestorage[self] then attributestorage[self] = {} end
|
||||
if attributestorage[self][key] == value then return end
|
||||
attributestorage[self][key] = value
|
||||
local name = namestorage[self]
|
||||
if not name then return end
|
||||
callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
|
||||
callbacks:Fire("LibDataBroker_AttributeChanged_"..name, name, key, value, self)
|
||||
callbacks:Fire("LibDataBroker_AttributeChanged_"..name.."_"..key, name, key, value, self)
|
||||
callbacks:Fire("LibDataBroker_AttributeChanged__"..key, name, key, value, self)
|
||||
end
|
||||
end
|
||||
|
||||
if oldminor < 2 then
|
||||
function lib:NewDataObject(name, dataobj)
|
||||
if self.proxystorage[name] then return end
|
||||
|
||||
if dataobj then
|
||||
assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
|
||||
self.attributestorage[dataobj] = {}
|
||||
for i,v in pairs(dataobj) do
|
||||
self.attributestorage[dataobj][i] = v
|
||||
dataobj[i] = nil
|
||||
end
|
||||
end
|
||||
dataobj = setmetatable(dataobj or {}, self.domt)
|
||||
self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
|
||||
self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
|
||||
return dataobj
|
||||
end
|
||||
end
|
||||
|
||||
if oldminor < 1 then
|
||||
function lib:DataObjectIterator()
|
||||
return pairs(self.proxystorage)
|
||||
end
|
||||
|
||||
function lib:GetDataObjectByName(dataobjectname)
|
||||
return self.proxystorage[dataobjectname]
|
||||
end
|
||||
|
||||
function lib:GetNameByDataObject(dataobject)
|
||||
return self.namestorage[dataobject]
|
||||
end
|
||||
end
|
||||
|
||||
if oldminor < 4 then
|
||||
local next = pairs(attributestorage)
|
||||
function lib:pairs(dataobject_or_name)
|
||||
local t = type(dataobject_or_name)
|
||||
assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
|
||||
|
||||
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
|
||||
assert(attributestorage[dataobj], "Data object not found")
|
||||
|
||||
return next, attributestorage[dataobj], nil
|
||||
end
|
||||
|
||||
local ipairs_iter = ipairs(attributestorage)
|
||||
function lib:ipairs(dataobject_or_name)
|
||||
local t = type(dataobject_or_name)
|
||||
assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
|
||||
|
||||
local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
|
||||
assert(attributestorage[dataobj], "Data object not found")
|
||||
|
||||
return ipairs_iter, attributestorage[dataobj], 0
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
LibDataBroker is a small WoW addon library designed to provide a "MVC":http://en.wikipedia.org/wiki/Model-view-controller interface for use in various addons.
|
||||
LDB's primary goal is to "detach" plugins for TitanPanel and FuBar from the display addon.
|
||||
Plugins can provide data into a simple table, and display addons can receive callbacks to refresh their display of this data.
|
||||
LDB also provides a place for addons to register "quicklaunch" functions, removing the need for authors to embed many large libraries to create minimap buttons.
|
||||
Users who do not wish to be "plagued" by these buttons simply do not install an addon to render them.
|
||||
|
||||
Due to it's simple generic design, LDB can be used for any design where you wish to have an addon notified of changes to a table.
|
||||
|
||||
h2. Links
|
||||
|
||||
* "API documentation":http://github.com/tekkub/libdatabroker-1-1/wikis/api
|
||||
* "Data specifications":http://github.com/tekkub/libdatabroker-1-1/wikis/data-specifications
|
||||
* "Addons using LDB":http://github.com/tekkub/libdatabroker-1-1/wikis/addons-using-ldb
|
||||
@@ -0,0 +1,29 @@
|
||||
Copyright (c) 2008, LibQTip 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.
|
||||
* Redistribution of a stand alone version is strictly prohibited without
|
||||
prior written authorization from the Lead of the LibQTip Development Team.
|
||||
* Neither the name of the LibQTip 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.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
## Interface: 30300
|
||||
## Title: Lib: QTip-1.0
|
||||
## Notes: Library providing multi-column tooltips.
|
||||
## Author: Torhal, Adirelle, Elkano, Tristanian
|
||||
## Version: r138
|
||||
## LoadOnDemand: 1
|
||||
## X-Date: 2010-08-03T20:56:32Z
|
||||
## X-Credits: Kaelten (input on initial design)
|
||||
## X-Category: Library, Tooltip
|
||||
## X-License: Ace3 BSD-like license
|
||||
## X-Curse-Packaged-Version: r138
|
||||
## X-Curse-Project-Name: LibQTip-1.0
|
||||
## X-Curse-Project-ID: libqtip-1-0
|
||||
## X-Curse-Repository-ID: wow/libqtip-1-0/mainline
|
||||
|
||||
LibStub\LibStub.lua
|
||||
lib.xml
|
||||
@@ -0,0 +1,4 @@
|
||||
<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">
|
||||
<Script file="LibQTip-1.0.lua"/>
|
||||
</Ui>
|
||||
@@ -0,0 +1,390 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- German localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "deDE");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["deDE.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
|
||||
L["ABOLISH_CHECK"] = "Zuvor überprüfen ob Reinigung nötig"
|
||||
L["ABOUT_AUTHOREMAIL"] = "E-MAIL DES ENTWICKLERS"
|
||||
L["ABOUT_CREDITS"] = "VERDIENST"
|
||||
L["ABOUT_LICENSE"] = "LIZENZ"
|
||||
L["ABOUT_NOTES"] = "Anzeige und Reinigung von Gebrechen für Solo, Gruppe und Schlachtzug mit erweitertem Filter- und Prioritäten-System."
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "OFFIZIELLE WEBSEITE"
|
||||
L["ABOUT_SHAREDLIBS"] = "GEMEINSAM GENUTZTE SAMMLUNGEN"
|
||||
L["ABSENT"] = "Fehlt (%s)"
|
||||
L["AFFLICTEDBY"] = "%s Befallen"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "Zeige Anzahl der Betroffenen: "
|
||||
L["ANCHOR"] = "Decursive Textfenster"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "Micro-Unit-Fenster anzeigen oder verstecken"
|
||||
L["BINDING_NAME_DCRPRADD"] = "Ziel zur Prioritätenliste hinzufügen"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "Prioritätenliste leeren"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "Prioritätenliste ausgeben"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "Zeige/Verstecke die Prioritätenliste UI"
|
||||
L["BINDING_NAME_DCRSHOW"] = "Zeige/Verstecke Decursive Main Bar"
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "Feststehendes Optionsfeld anzeigen"
|
||||
L["BINDING_NAME_DCRSKADD"] = "Ziel zur Ignorierliste hinzufügen"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "Ignorierliste leeren"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "Ignorierliste ausgeben"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "Zeige/Verstecke die Ignorierliste UI"
|
||||
L["BLACK_LENGTH"] = "Sekunden auf der Blacklist: "
|
||||
L["BLACKLISTED"] = "Black-listed"
|
||||
L["CHARM"] = "Verführung/Übernommen/Gedankenkontrolle"
|
||||
L["CLASS_HUNTER"] = "Jäger"
|
||||
L["CLEAR_PRIO"] = "C"
|
||||
L["CLEAR_SKIP"] = "C"
|
||||
L["COLORALERT"] = "Warnfarbe einstellen, wenn ein '%s' benötigt wird."
|
||||
L["COLORCHRONOS"] = "Chronometer"
|
||||
L["COLORCHRONOS_DESC"] = "Chronometer-Farbe einstellen"
|
||||
L["COLORSTATUS"] = "Farbe für '%s' MUF-Status einstellen."
|
||||
L["CTRL"] = "Strg"
|
||||
L["CURE_PETS"] = "Scanne und reinige Pets"
|
||||
L["CURSE"] = "Fluch"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33Bitte sende den Inhalt dieses Fensters an Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(Benutze Strg+A, um alles zu markieren, und dann Strg+C, um den Text in deine Zwischenablage zu kopieren)|r
|
||||
Bitte berichte ebenfalls, ob du merkwürdiges Verhalten von Decursive bemerkt hast.
|
||||
]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = " **** |cFFFF0000Decursive-Debug-Bericht|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[Ein Debug-Bericht ist vorhanden!
|
||||
Gib |cFFFF0000/dcr general report|r ein, um ihn zu sehen.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "Debug Report verfügbar !"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "Zeigt einen Debug Report an der für den Author wichtig ist...."
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DEV_VERSION_ALERT"] = [=[Du benutzt eine Entwickler-Version von Decursive.
|
||||
|
||||
Falls du nicht teilhaben willst am Testen neuer Features/Fehlerbehebungen, Erhalten von Fehlerbehebungsberichten im Spiel, Probleme oder Anfragen senden möchtest an den Entwickler, dann VERWENDE DIESE VERSION NICHT und lade die letzte stabile Version herunter bei curse.com oder wowace.com.
|
||||
|
||||
Diese Mitteilunge wird nur einmal pro Version in den Chat ausgegeben.]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[Diese Entwickler-Version von Decursive ist abgelaufen.
|
||||
Du solltest die neueste Entwickler-Version herunterladen oder zurückgehen zur aktuellen stabilen Release-Version, die du bei CURSE.COM oder WAWACE.COM findest.
|
||||
Diese Warnung wird alle zwei Tage angezeigt.]=]
|
||||
L["DEWDROPISGONE"] = "Es gibt kein Äquivalent zu DewDrop für Ace3. Alt-Rechts-Klicken, um das Optionsfeld zu öffnen."
|
||||
L["DISABLEWARNING"] = [=[Decursive wurde ausgeschaltet!
|
||||
|
||||
Um es erneut zu aktivieren, gib |cFFFFAA44/DCR ENABLE|r ein.]=]
|
||||
L["DISEASE"] = "Krankheit"
|
||||
L["DONOT_BL_PRIO"] = "Keine Namen der Prioritätenliste bannen"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r |cFFAA0000gescheitert bei|r %s
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "Focus Einheit"
|
||||
L["FUBARMENU"] = "FuBar Menu"
|
||||
L["FUBARMENU_DESC"] = "Setzt die Optionen relativ zum FuBar Icon"
|
||||
L["GLOR1"] = "In Gedenken an Glorfindal"
|
||||
L["GLOR2"] = [=[Decursive ist Bertrand gewidmet, der uns viel zu früh verlassen hat.
|
||||
Er wird immer in Erinnerung bleiben.]=]
|
||||
L["GLOR3"] = [=[In Gedenken an Bertrand Sense
|
||||
1969 - 2007]=]
|
||||
L["GLOR4"] = [=[Freundschaft und Zuneigung haben ihre Wurzeln überall, die, die Glorfindal in World of Warcraft getroffen haben kennen einen Menschen großen Einsatzes und einen charismatischen Leiter.
|
||||
|
||||
Er war im echten Leben wie im Spiel, Selbstlos, Grosszügig, immer für seine Freunde da und vor allem ein enthusiastischer Mensch.
|
||||
|
||||
Er verließ uns mit 38 und lies nicht nur Anonyme Spieler in einer Virtuellen Welt, sondern echte Freunde zurück, die ihn immer vermissen werden.]=]
|
||||
L["GLOR5"] = "Er wird immer in Erinnerung bleiben..."
|
||||
L["HANDLEHELP"] = "Alle Micro-Unit-Fenster (MUFs) verschieben"
|
||||
L["HIDE_LIVELIST"] = "Verstecke die Live-Liste"
|
||||
L["HIDE_MAIN"] = "Verstecke Decursive Fenster"
|
||||
L["HIDESHOW_BUTTONS"] = "Verbergen-/Anzeigen-Schaltflächen"
|
||||
L["HLP_LEFTCLICK"] = "Linksklick"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = [=[Das Klicken auf die aktuelle Liste ist nicht mehr möglich seit WoW 2.0. Lies bitte die Datei "Readme.txt" in deinem Decursive-Ordner...
|
||||
(Um diese Liste zu bewegen, bewege die Decursive-Leiste, /dcrshow und Links-Alt-Klick zum Bewegen)]=]
|
||||
L["HLP_MIDDLECLICK"] = "Mittlere Maustaste"
|
||||
L["HLP_NOTHINGTOCURE"] = "Es gibt nichts zu Heilen!"
|
||||
L["HLP_RIGHTCLICK"] = "Rechtsklick"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "Benutze \"%s\" um dieses Gebrechen zu Heilen!"
|
||||
L["HLP_WRONGMBUTTON"] = "Falscher Mausbutton!"
|
||||
L["IGNORE_STEALTH"] = "Ignoriere getarnte Einheiten"
|
||||
L["IS_HERE_MSG"] = "Decursive wurde geladen, kontrolliere bitte die Einstellungen"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r-Click: Entfernt den Spieler
|
||||
|cFF33AA33LEFT|r-Click: Diesen Spieler eins nach oben setzen
|
||||
|cFF33AA33RIGHT|r-Click: Diesen Spieler eins nach unten setzen
|
||||
|cFF33AA33[SHIFT] LEFT|r-Click: Setzt den Spieler ganz nach oben
|
||||
|cFF33AA33[SHIFT] RIGHT|r-Click: Setzt den Spieler ganz nach unten]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[Warnung: Die Taste zu dem Decursive macro [%s] ist an Aktion gebunden '%s'.
|
||||
Decursive wird es auf die vorherige Einstellung zurück setzen wenn du eine andere Taste für das Marko auswählst.]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "Die Taste [%s] kann nicht an das Decursive-Macro gebunden werden"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "Die Taste [%s] wurde erfolgreich an das Decursive-Macro gebunden"
|
||||
L["MACROKEYNOTMAPPED"] = "Decursive mouse-over Makro ist nicht an eine Taste gebunden, schau in der Option \"Makro\" (Interface) nach "
|
||||
L["MAGIC"] = "Magie"
|
||||
L["MAGICCHARMED"] = "Magie Zauber"
|
||||
L["MISSINGUNIT"] = "Fehlende Einheit"
|
||||
L["NORMAL"] = "Normal"
|
||||
L["NOSPELL"] = "Kein Zauber verfügbar"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "Wähle, ob Einheiten mit einem aktiven \"Aufheben\"-Zauber angezeigt und geheilt werden sollen."
|
||||
L["OPT_ABOUT"] = "Über"
|
||||
L["OPT_ADDDEBUFF"] = "Ein Gebrechen manuell hinzufügen"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "Ein neues Gebrechen der Liste hinzufügen"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "Erneuertes Gebrechen hinzufügen."
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "Ein Gebrechen anhand der Historie hinzufügen"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<Affliction name>"
|
||||
L["OPT_ADVDISP"] = "Erweiterte Anzeigeeinstellungen"
|
||||
L["OPT_ADVDISP_DESC"] = "Erlauben, die Transparenz des Rands und der Mitte getrennt einzustellen, den Abstand zwischen jedem MUF einzustellen."
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s betroffen von %s, wird jedoch übersprungen"
|
||||
L["OPT_ALWAYSIGNORE"] = "Auch ignorieren wenn nicht im Kampf"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "Falls Markiert, wird dieses Gebrechen auch dann ignoriert, wenn du dich nicht im Kampf befindest."
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "Definiert die maximale Anzahl der anzuzeigenden Verfluchten in der aktuellen Liste"
|
||||
L["OPT_ANCHOR_DESC"] = "Zeigt Anker des Rahmens der allgemeinen Mitteilungen an"
|
||||
L["OPT_AUTOHIDEMFS"] = "Automatisch verstecken"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "Wähle, wann das MUF-Fenster verborgen werden soll."
|
||||
L["OPT_BLACKLENTGH_DESC"] = "Definiert wie lange ein Spieler auf der Blacklist steht. "
|
||||
L["OPT_BORDERTRANSP"] = "Rahmen-Transparenz"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "Rahmen-Transparenz setzten"
|
||||
L["OPT_CENTERTRANSP"] = "Transparenz Mitte"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "Transparenz der Mitte einstellen"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "Wenn markiert, bist du in der Lage, bezauberte Einheiten zu sehen und zu behandeln."
|
||||
L["OPT_CHATFRAME_DESC"] = "Decursive Nachrichten werden im Standart Bildfeld ausgegeben."
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "Andere Spieler überprüfen"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "Zeigt Decursive-Version den Spielern in deiner aktuellen Gruppe oder Gilde an (kann nicht Versionen vor Decursive 2.4.6 anzeigen)."
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "Erzeuge eine virtuelle Test Krankheit/Gebrechen"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "Lässt dich sehen, wie es aussieht, wenn ein Gebrechen gefunden wurde."
|
||||
L["OPT_CUREPETS_DESC"] = "Begleiter werden bearbeitet und geheilt"
|
||||
L["OPT_CURINGOPTIONS"] = "Aktuelle Einstellungen"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "Verschiedene Aspekte des Heilungsprozesses einstellen"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
Wähle die Arten von Gebrechen, die du heilen möchtest. Nicht markierte Typen werden komplett von Decursive ignoriert.
|
||||
|
||||
Die grüne Zahl legt die Priorität des Gebrechens fest. Diese Priorität beeinflußt mehrere Aspekte:
|
||||
- Was Decursive als erstes anzeigt, wenn ein Spieler an verschiedenen Debuff-Typen leidet.
|
||||
- Welche Maus-Schaltfläche du klicken mußt, um den jeweiligen Debuff zu heilen (Erster Zauber ist Linksklick, zweiter ist Rechtsklick, etc...).
|
||||
|
||||
All dies wird in der Dokumentation genau erklärt (muß gelesen werden):
|
||||
http://www.wowace.com/addons/decursive/
|
||||
]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "Aktuelle Sortierungseinstellungen"
|
||||
L["OPT_CURSECHECK_DESC"] = "Falls markiert, bist du in der Lage, verfluchte Einheiten zu sehen und zu heilen."
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
|
||||
Standardmäßig markiert]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "Auswählen welche Klasse im Kampf ignoriert werden soll wenn sie von dieser Krankheit betroffen ist."
|
||||
L["OPT_DEBUFFFILTER"] = "Gebrechen gefilter"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "Wähle Gebrechen anhand des Namens und der Klasse welches innerhalb des Kampfes gefiltert werden soll."
|
||||
L["OPT_DISABLEMACROCREATION"] = "Deaktiviert Makro erstellung"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Decursive-Makro wird nicht mehr kreiert oder erhalten"
|
||||
L["OPT_DISEASECHECK_DESC"] = "Wenn Aktiv, die Möglichkeit erkrankte Einheiten zu sehen und zu heilen."
|
||||
L["OPT_DISPLAYOPTIONS"] = "Anzeigeoptionen"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "Einheiten auf der Prioritätenliste werden nicht in die Blacklist übernommen."
|
||||
L["OPT_ENABLEDEBUG"] = "Fehlersuche zulassen"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "Ausgabe der Fehlersuche zulassen"
|
||||
L["OPT_ENABLEDECURSIVE"] = "Decursive aktivieren"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "%q wird bei den spezifizierten Klassen ignoriert während du dich im Kampf befindest."
|
||||
L["OPT_GENERAL"] = "Allgemeine Optionen"
|
||||
L["OPT_GROWDIRECTION"] = "MUF-Anzeige umkehren"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "Das MUF von unten nach oben anzeigen"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "Wenn nicht versteckt, zeigt eine Informations Leiste von Spielern mit Flüchen"
|
||||
L["OPT_HIDEMFS_GROUP"] = "Solo/Gruppe"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "Das MUF verstecken wenn du nicht im Raid bist"
|
||||
L["OPT_HIDEMFS_NEVER"] = "Nie"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "Das MUF-Fenster nie automatisch verstecken."
|
||||
L["OPT_HIDEMFS_SOLO"] = "Solo"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "Das MUF-Fenster verstecken wenn du in keiner Gruppe oder Raidgruppe bist."
|
||||
L["OPT_HIDEMUFSHANDLE"] = "MUF-Handhabung verbergen"
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = [=[Verbirgt die Handhabung der Mikro-Einheiten-Rahmen und schaltet die Möglichkeit aus, diese zu bewegen.
|
||||
Benutze denselben Befehl, um diese wiederherzustellen.]=]
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "Verhüllte/Versteckte Einheiten werden ignoriert"
|
||||
L["OPTION_MENU"] = "Decursive Einstellungen"
|
||||
L["OPT_LIVELIST"] = "Live-Liste"
|
||||
L["OPT_LIVELIST_DESC"] = "Optionen für die Live-Liste"
|
||||
L["OPT_LLALPHA"] = "Transparenz Live-Liste"
|
||||
L["OPT_LLALPHA_DESC"] = "Andert die Decursive Haupt und Live Leiste Transparenz (Haupt Leiste muss sichtbar sein)"
|
||||
L["OPT_LLSCALE"] = "Skalierung der Live-Liste"
|
||||
L["OPT_LLSCALE_DESC"] = "Setzt die Größe der Decursive Hauptleiste und der Live-Liste (Hauptleiste muss angezeigt werden)"
|
||||
L["OPT_LVONLYINRANGE"] = "Nur Einheiten in Reichweite"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "Nur Einheiten in Dispelreichweite werden in der Live-Liste angezeigt"
|
||||
L["OPT_MACROBIND"] = "Tastkombination für das Macro setzen"
|
||||
L["OPT_MACROBIND_DESC"] = [=[Definiert die Taste mit der das 'Decursive' Makro aufgerufen wird
|
||||
|
||||
Wähle die gewünschte Taste und drück die Taste "Enter" um die Zuordnung abzuschliessen (Mit dem Mouse Over Curso über dem Edit Feld)
|
||||
]=]
|
||||
L["OPT_MACROOPTIONS"] = "Macro-Optionen"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "Das Verhalten des Decursive-Macros festlegen"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "Wenn Aktiv, ist es möglich mit Magie verzauberte Einheiten zu sehen und zu heilen."
|
||||
L["OPT_MAGICCHECK_DESC"] = "Wenn Aktiv, ist es möglich mit Magie befallene Einheiten zu sehen und zu heilen."
|
||||
L["OPT_MAXMFS"] = "Maximale Anzahl an Einheiten die angezeigt werden sollen"
|
||||
L["OPT_MAXMFS_DESC"] = "Definiert die maximale Anzahl an Mikro-Unitframes die angezeigt werden sollen"
|
||||
L["OPT_MESSAGES"] = "Nachrichten"
|
||||
L["OPT_MESSAGES_DESC"] = "Optionen über Nachrichten Anzeige"
|
||||
L["OPT_MFALPHA"] = "Transparenz"
|
||||
L["OPT_MFALPHA_DESC"] = "Abweichende Transparenz der MUF's wenn Einheiten nicht betroffen sind"
|
||||
L["OPT_MFPERFOPT"] = "Performance-Einstellungen"
|
||||
L["OPT_MFREFRESHRATE"] = "Aktualisierungsrate"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "Zeit zwischen jedem refresh Aufruf (1 oder mehrere micro-unit-frames können auf einmal aktuallisiert werden)"
|
||||
L["OPT_MFREFRESHSPEED"] = "Aktualisierungsgeschwindigkeit"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "Anzahl der Micro-Unit-Fenster die in einem Durchgang aktualisiert werden sollen"
|
||||
L["OPT_MFSCALE"] = "Scalieriung des Micro-Unit-Fensters"
|
||||
L["OPT_MFSCALE_DESC"] = "Große des Micro-Unit-Fensters setzten"
|
||||
L["OPT_MFSETTINGS"] = "Einstellungen des Micro-Unit-Fensters"
|
||||
L["OPT_MFSETTINGS_DESC"] = "Stellt die MUF Fenster Optionen nach deinen Bedürfnissen ein. "
|
||||
L["OPT_MUFFOCUSBUTTON"] = "Fokus-Schaltfläche:"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "Maus-Schaltflächen"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "Maus-Schaltflächen einstellen, die du für jede Warnfarbe des Mikro-Einheiten-Rahmens benutzen möchtest."
|
||||
L["OPT_MUFSCOLORS"] = "Farben"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "Farben des Micro-Unit-Fensters verändern"
|
||||
L["OPT_MUFTARGETBUTTON"] = "Tiel-Schaltfläche:"
|
||||
L["OPT_NOKEYWARN"] = "Warnen wenn keine Tastenbelegung angegeben"
|
||||
L["OPT_NOKEYWARN_DESC"] = "Warnen wenn keine Tastenbelegung angegeben"
|
||||
L["OPT_NOSTARTMESSAGES"] = "Begrüssungsmitteilungen ausschalten"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "Die drei Mitteilungen entfernen, die Decursive bei jedem Einloggen im Chat-Rahmen ausgibt."
|
||||
L["OPT_PLAYSOUND_DESC"] = "Einen Ton abspielen wenn jemand von einem Fluch betroffen ist"
|
||||
L["OPT_POISONCHECK_DESC"] = "Wenn Aktiv, ist es möglich vergiftete Einheiten zu sehen und zu heilen."
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "Decursive-Nachrichten werden in einem eigenen Chat-Fenster angezeigt"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "Fehler werden angezeigt"
|
||||
L["OPT_PROFILERESET"] = "Profil zurückgestetzt..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "Einheiten werden Angezeigt und in zufälliger Reihenfolge geheilt(Nicht empfohlen)"
|
||||
L["OPT_READDDEFAULTSD"] = "RE-ADD Standart Gebrechen "
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[Fügt fehlende Decursive standart Gebrechen zu dieser Liste.
|
||||
Deine Einstellungen werden nicht geändert. ]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "Alle Decursive standart Gebrechen sind in dieser Liste. "
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[ Bist du sicher du wills '%s' entfernen aus der Decursive Krankheiten Liste ?
|
||||
]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "Dieses Gebrechen entfernen"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "Entfernt '%s' von der skip list"
|
||||
L["OPT_RESETDEBUFF"] = "Resete diese Gebrechen"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = " Resets '%s' auf Decursive Standart"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "Zurücksetzen"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "Zuordnungen der Maus-Schaltflächen auf Standard zurücksetzen."
|
||||
L["OPT_RESETOPTIONS"] = "Optionen zurücksetzten"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "Aktuelles Profil zurücksetzten"
|
||||
L["OPT_RESTPROFILECONF"] = [=[Bist du sicher du willst das Profile
|
||||
'(%s) %s'
|
||||
auf die Standart Einstellungen zurück setzen ?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "Live-Liste von unten nach oben befüllen"
|
||||
L["OPT_SCANLENGTH_DESC"] = "Zeit zwischen jedem Scanvorgang festlegen"
|
||||
L["OPT_SHOWBORDER"] = "Zeige Klassenfarbige Umrandung"
|
||||
L["OPT_SHOWBORDER_DESC"] = "Eine farbliche Umrandung wird um die MUF's angezeigt welche die Unit Klasse darstellt "
|
||||
L["OPT_SHOWCHRONO"] = "Zeige Zeitmesser"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "Zeit in Sec. die verstrichen ist seit eine Einheit mit einem Gebrechen befallen ist, wird angezeigt. "
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "Zeit verbleibend"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "Zeige verbleibende Zeit an anstatt bereits verstrichener Zeit."
|
||||
L["OPT_SHOWHELP"] = "Hilfe anzeigen"
|
||||
L["OPT_SHOWHELP_DESC"] = "Zeigt einen Detaillierten Tooltip bei Mouse Over über das micro-unit-frame"
|
||||
L["OPT_SHOWMFS"] = "Micro-Unit-Fenster anzeigen"
|
||||
L["OPT_SHOWMFS_DESC"] = "Muss aktiv sein wenn du über Mausclick heilen möchtest."
|
||||
L["OPT_SHOWMINIMAPICON"] = "Minimap Icon"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "Minimap Icon anzeigen/verstecken"
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "Verborgenheitsstatus anzeigen"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "Wenn sich ein Spieler in Verborgenheit befindet, nimmt sein MUF eine spezielle Farbe an."
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "Zeigt einen Detailierten Tooltip über einen Fluch in der Life Liste auf den MUF's "
|
||||
L["OPT_STICKTORIGHT"] = "MUF rechts ausrichten"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "Das MUF-Fenster wächst von rechts nach links. Falls notwendig, wird der Halter bewegt."
|
||||
L["OPT_TESTLAYOUT"] = "Test-Layout"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[Erschaffe simulierte Einheiten, so dass du das Anzeige-Layout testen kannst.
|
||||
(Warte ein paar Sekunden nach dem Klicken!)]=]
|
||||
L["OPT_TESTLAYOUTUNUM"] = "Einheitsnummer"
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "Anzahl der zu erschaffenden simulierten Einheiten einstellen."
|
||||
L["OPT_TIECENTERANDBORDER"] = "Transparenz der Mitte und des Rands miteinander verbinden."
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "Falls markiert, ist die Transparenz des Rands die Hälfte der Transparenz der Mitte."
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "Die Anzeige der aktuellen Liste ist verbunden mit der Anzeige der Decursive-Leisten."
|
||||
L["OPT_TIEXYSPACING"] = "Horizontaler und vertikaler Abstand"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "Der horizontale und vertikale Abstand zwischen MUFs sind gleich."
|
||||
L["OPT_UNITPERLINES"] = "Anzahl Einheiten pro Zeile"
|
||||
L["OPT_UNITPERLINES_DESC"] = "Definiert die max. Anzahl an Micro-Unitframes die pro Zeile angezeigt werden sollen."
|
||||
L["OPT_USERDEBUFF"] = "Diese Krankheit ist nicht Teil von Decursive's standardmässigen Krankheiten."
|
||||
L["OPT_XSPACING"] = "Horizontaler Abstand"
|
||||
L["OPT_XSPACING_DESC"] = "Den horizontalen Abstand zwischen MUFs festlegen."
|
||||
L["OPT_YSPACING"] = "Vertikaler Abstand"
|
||||
L["OPT_YSPACING_DESC"] = "Den vertikalen Abstand zwischen MUFs festlegen."
|
||||
L["PLAY_SOUND"] = "Akustische Warnung falls Reinigung nötig"
|
||||
L["POISON"] = "Gift"
|
||||
L["POPULATE"] = "P"
|
||||
L["POPULATE_LIST"] = "Schnellbestücken der Decursive Liste"
|
||||
L["PRINT_CHATFRAME"] = "Nachrichten im Chat ausgeben"
|
||||
L["PRINT_CUSTOM"] = "Nachrichten in Bildschirmmitte ausgeben"
|
||||
L["PRINT_ERRORS"] = "Fehlernachrichten ausgeben"
|
||||
L["PRIORITY_LIST"] = "Decursive Prioritätenliste"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "Reinige in zufälliger Reihenfolge"
|
||||
L["REVERSE_LIVELIST"] = "Zeige die Live-Liste umgekehrt"
|
||||
L["SCAN_LENGTH"] = "Sekunden zwischen Live-Scans: "
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "Um das Decursive Fenster anzuzeigen, /dcrshow eingeben"
|
||||
L["SHOW_TOOLTIP"] = "Zeige Tooltips in der Betroffenenliste"
|
||||
L["SKIP_LIST_STR"] = "Decursive Ignorierliste"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "Zauber %s gefunden!"
|
||||
L["STEALTHED"] = "Getarnt"
|
||||
L["STR_CLOSE"] = "Schließen"
|
||||
L["STR_DCR_PRIO"] = "Decursive Prioritätenliste"
|
||||
L["STR_DCR_SKIP"] = "Decursive Ignorierliste"
|
||||
L["STR_GROUP"] = "Gruppe "
|
||||
L["STR_OPTIONS"] = "Einstellungen"
|
||||
L["STR_OTHER"] = "Sonstige"
|
||||
L["STR_POP"] = "Bestückungsliste"
|
||||
L["STR_QUICK_POP"] = "Schnellbestücken"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r |cFF00AA00Erfolgreich bei|r %s"
|
||||
L["TARGETUNIT"] = "Zieleinheit"
|
||||
L["TIE_LIVELIST"] = "Tie live-List Sichtbarkeit zu DCR Fenster"
|
||||
L["TOOFAR"] = "Zu weit weg"
|
||||
L["UNITSTATUS"] = "Einheitenstatus:"
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["deDE.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,395 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- English default localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["Dcr_DIAG.xml"] or not T._LoadedFiles["Dcr_DIAG.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (Dcr_DIAG.lua or Dcr_DIAG.xml not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "enUS", true);
|
||||
|
||||
if not L then return end;
|
||||
|
||||
L["ABOLISH_CHECK"] = "Check for \"Abolish\" before curing"
|
||||
L["ABOUT_AUTHOREMAIL"] = "AUTHOR E-MAIL"
|
||||
L["ABOUT_CREDITS"] = "CREDITS"
|
||||
L["ABOUT_LICENSE"] = "LICENSE"
|
||||
L["ABOUT_NOTES"] = "Afflictions display and cleaning for solo, group and raid with advanced filtering and priority system."
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "OFFICIAL WEBSITE"
|
||||
L["ABOUT_SHAREDLIBS"] = "SHARED LIBRARIES"
|
||||
L["ABSENT"] = "Missing (%s)"
|
||||
L["AFFLICTEDBY"] = "%s Afflicted"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "The amount of afflicted to show : "
|
||||
L["ANCHOR"] = "Decursive Text Anchor"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "Show or hide the micro-unit frames"
|
||||
L["BINDING_NAME_DCRPRADD"] = "Add target to priority list"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "Clear the priority list"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "Print the priority list"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "Show or hide the priority list"
|
||||
L["BINDING_NAME_DCRSHOW"] = [=[Show or hide Decursive Main Bar
|
||||
(live-list anchor)]=]
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "Display the option static panel"
|
||||
L["BINDING_NAME_DCRSKADD"] = "Add target to skip list"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "Clear the skip list"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "Print the skip list"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "Show or hide the skip list"
|
||||
L["BLACK_LENGTH"] = "Seconds on the blacklist : "
|
||||
L["BLACKLISTED"] = "Black-listed"
|
||||
L["CHARM"] = "Charm"
|
||||
L["CLASS_HUNTER"] = "Hunter"
|
||||
L["CLEAR_PRIO"] = "C"
|
||||
L["CLEAR_SKIP"] = "C"
|
||||
L["COLORALERT"] = "Set the color alert when a '%s' is required."
|
||||
L["COLORCHRONOS"] = "Chronometers"
|
||||
L["COLORCHRONOS_DESC"] = "Set the chronometers' color"
|
||||
L["COLORSTATUS"] = "Set the color for the '%s' MUF status."
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "Scan and cure pets"
|
||||
L["CURSE"] = "Curse"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33Please report the content of this window to Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(Use CTRL+A to select all and then CTRL+C to put the text in your clip-board)|r
|
||||
Also tell in your report if you noticed any strange behavior of Decursive.
|
||||
]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Decursive Debug Report|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[A debug report is available!
|
||||
Type |cFFFF0000/dcr general report|r to see it.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "Debug report available!"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "Show a debug report the author needs to see..."
|
||||
L["DEFAULT_MACROKEY"] = "`"
|
||||
L["DEV_VERSION_ALERT"] = [=[You are using a development version of Decursive.
|
||||
|
||||
If you do not want to participate in testing new features/fixes, receive in-game debug reports, send issues to the author then DO NOT USE THIS VERSION and download the latest STABLE version on curse.com or wowace.com.
|
||||
|
||||
This message will be displayed only once per version]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[This development version of Decursive has expired.
|
||||
You should, download the latest development version or go back to the current stable release available on CURSE.COM or WOWACE.COM.
|
||||
This warning will be displayed every two days.]=]
|
||||
L["DEWDROPISGONE"] = "There is no DewDrop equivalent for Ace3. Alt-Right-Click to open the option panel."
|
||||
L["DISABLEWARNING"] = [=[Decursive has been disabled!
|
||||
|
||||
To enable it again, type |cFFFFAA44/DCR ENABLE|r]=]
|
||||
L["DISEASE"] = "Disease"
|
||||
L["DONOT_BL_PRIO"] = "Don't blacklist priority list names"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r |cFFAA0000failed on|r %s
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "Focus Unit"
|
||||
L["FUBARMENU"] = "FuBar Menu"
|
||||
L["FUBARMENU_DESC"] = "Set options relative to FuBar icon"
|
||||
L["GLOR1"] = "In memory of Glorfindal"
|
||||
L["GLOR2"] = [=[Decursive is dedicated to the memory of Bertrand who left way too soon.
|
||||
He will always be remembered.]=]
|
||||
L["GLOR3"] = [=[In remembrance of Bertrand Sense
|
||||
1969 - 2007]=]
|
||||
L["GLOR4"] = [=[Friendship and affection can take their roots anywhere, those who met Glorfindal in World of Warcraft knew a man of great commitment and a charismatic leader.
|
||||
|
||||
He was in life as he was in game, selfless, generous, dedicated to his friends and most of all, a passionate man.
|
||||
|
||||
He left us at the age of 38 leaving behind him not just anonymous players in a virtual world but, a group of true friends who will miss him forever.]=]
|
||||
L["GLOR5"] = "He will always be remembered..."
|
||||
L["HANDLEHELP"] = "Drag all the Micro-UnitFrames (MUFs)"
|
||||
L["HIDE_LIVELIST"] = "Hide the live-list"
|
||||
L["HIDE_MAIN"] = "Hide Decursive Window"
|
||||
L["HIDESHOW_BUTTONS"] = "Hide/Show buttons"
|
||||
L["HLP_LEFTCLICK"] = "Left-Click"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = [=[Clicking on the live-list is useless since WoW 2.0. You should read the FAQ in the "Readme.txt" file located in Decursive folder...
|
||||
(To move this list move the Decursive bar, /dcrshow and left-alt-click to move)]=]
|
||||
L["HLP_MIDDLECLICK"] = "Middle-Click"
|
||||
L["HLP_NOTHINGTOCURE"] = "There is nothing to cure!"
|
||||
L["HLP_RIGHTCLICK"] = "Right-Click"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "Use \"%s\" to cure this affliction!"
|
||||
L["HLP_WRONGMBUTTON"] = "Wrong mouse button!"
|
||||
L["IGNORE_STEALTH"] = "Ignore cloaked Units"
|
||||
L["IS_HERE_MSG"] = "Decursive is now initialized, remember to check the options"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r-Click: Remove this player
|
||||
|cFF33AA33LEFT|r-Click: Rise this player
|
||||
|cFF33AA33RIGHT|r-Click: Come down this player
|
||||
|cFF33AA33[SHIFT] LEFT|r-Click: Put this player at the top
|
||||
|cFF33AA33[SHIFT] RIGHT|r-Click: Put this player at the bottom]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[WARNING: The key mapped to Decursive macro [%s] was mapped to action '%s'.
|
||||
Decursive will restore the previous mapping if you set another key for its macro.]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "The key [%s] could not be mapped to Decursive macro!"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "The key [%s] has been successfully mapped to Decursive macro."
|
||||
L["MACROKEYNOTMAPPED"] = "Decursive mouse-over macro is not mapped to a key, take a look at the 'Macro' options!"
|
||||
L["MAGIC"] = "Magic"
|
||||
L["MAGICCHARMED"] = "Magic Charm"
|
||||
L["MISSINGUNIT"] = "Missing unit"
|
||||
L["NORMAL"] = "Normal"
|
||||
L["NOSPELL"] = "No spell available"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "select whether units with an active 'Abolish' spell are shown and cured"
|
||||
L["OPT_ABOUT"] = "About"
|
||||
L["OPT_ADDDEBUFF"] = "Add a custom affliction"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "Adds a new affliction to this list"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "Add a recent affliction"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "Add an affliction using the history"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<Affliction name>"
|
||||
L["OPT_ADVDISP"] = "Advance display Options"
|
||||
L["OPT_ADVDISP_DESC"] = "Allow to set Transparency of the border and center separately, to set the space between each MUF"
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s afflicted by %s will be skipped"
|
||||
L["OPT_ALLOWMACROEDIT"] = "Allow macro edition"
|
||||
L["OPT_ALLOWMACROEDIT_DESC"] = "Enable this to prevent Decursive from updating its macro, letting you edit it as you want."
|
||||
L["OPT_ALWAYSIGNORE"] = "Also ignore when not in combat"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "If checked, this affliction will also be ignored when you are not in combat"
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "Defines the max number of cursed to display in the live-list"
|
||||
L["OPT_ANCHOR_DESC"] = "Shows the anchor of the custom message frame"
|
||||
L["OPT_AUTOHIDEMFS"] = "Auto-Hide"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "Choose when to hide the MUF window"
|
||||
L["OPT_BLACKLENTGH_DESC"] = "Defines how long someone stays on the blacklist"
|
||||
L["OPT_BORDERTRANSP"] = "Border transparency"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "Set the transparency of the border"
|
||||
L["OPT_CENTERTRANSP"] = "Center transparency"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "Set the transparency of the center"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "If checked you'll be able to see and deal with charmed units"
|
||||
L["OPT_CHATFRAME_DESC"] = "Decursive's messages will be printed to the default chat frame"
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "Check other players"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "Displays Decursive version among the players in your current group or guild (cannot display versions prior to Decursive 2.4.6)."
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "Create a virtual test affliction"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "Lets you see how it looks like when an affliction is found"
|
||||
L["OPT_CUREPETS_DESC"] = "Pets will be managed and cured"
|
||||
L["OPT_CURINGOPTIONS"] = "Curing options"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "Set different aspects of the curing process"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
Select the types of the afflictions you want to cure, unchecked types will be completely ignored by Decursive.
|
||||
|
||||
The green number determine the priority of the affliction. This priority will affect several aspects:
|
||||
- What Decursive shows you first if a player got several types of Debuff.
|
||||
- What mouse button you'll have to click to cure the debuff (First spell is Left-Click, second is Right-Click, etc...)
|
||||
|
||||
All of this is explained in the documentation (a must see):
|
||||
http://www.wowace.com/addons/decursive/
|
||||
]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "Curing Order Options"
|
||||
L["OPT_CURSECHECK_DESC"] = "If checked you'll be able to see and cure cursed units"
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
|
||||
Checked by default]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "Select what class should be ignored in combat when afflicted by this affliction"
|
||||
L["OPT_DEBUFFFILTER"] = "Affliction filtering"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "Select afflictions to filter out by name and class while you are in combat"
|
||||
L["OPT_DISABLEABOLISH"] = "Do not use 'Abolish' spells"
|
||||
L["OPT_DISABLEABOLISH_DESC"] = "If enabled, Decursive will prefer 'Cure Disease' and 'Cure Poison' over their 'Abolish' equivalent."
|
||||
L["OPT_DISABLEMACROCREATION"] = "Disable macro creation"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Decursive macro will no longer be created or maintained"
|
||||
L["OPT_DISEASECHECK_DESC"] = "If checked you'll be able to see and cure diseased units"
|
||||
L["OPT_DISPLAYOPTIONS"] = "Display options"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "Prioritized units won't be blacklisted"
|
||||
L["OPT_ENABLEDEBUG"] = "Enable Debugging"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "Enable Debugging output"
|
||||
L["OPT_ENABLEDECURSIVE"] = "Enable Decursive"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "%q will be ignored on the specified classes while you are in combat."
|
||||
L["OPT_GENERAL"] = "General options"
|
||||
L["OPT_GROWDIRECTION"] = "Reverse MUFs Display"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "The MUFs will be displayed from bottom to top"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "If not hidden, displays an informative list of cursed people"
|
||||
L["OPT_HIDEMFS_GROUP"] = "Solo/Party"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "Hide the MUF window when you are not in a raid"
|
||||
L["OPT_HIDEMFS_NEVER"] = "Never"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "Never auto-hide the MUF window"
|
||||
L["OPT_HIDEMFS_SOLO"] = "Solo"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "Hide the MUF window when you are not in a party or raid"
|
||||
L["OPT_HIDEMUFSHANDLE"] = "Hide the MUFs handle"
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = [=[Hides the Micro-Unit Frames handle and disables the possibility to move them.
|
||||
Use the same command to get it back.]=]
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "Cloaked units will be ignored"
|
||||
L["OPTION_MENU"] = "Decursive Options Menu"
|
||||
L["OPT_LIVELIST"] = "Live list"
|
||||
L["OPT_LIVELIST_DESC"] = "Options for the live list"
|
||||
L["OPT_LLALPHA"] = "Live-list transparency"
|
||||
L["OPT_LLALPHA_DESC"] = "Changes Decursive main bar and live-list transparency (Main bar must be displayed)"
|
||||
L["OPT_LLSCALE"] = "Scale of the Live-list"
|
||||
L["OPT_LLSCALE_DESC"] = "Set the size of the Decursive main bar and of the Live-list (Main bar must be displayed)"
|
||||
L["OPT_LVONLYINRANGE"] = "Units in range only"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "Only units in dispel range will be shown in the live-list"
|
||||
L["OPT_MACROBIND"] = "Set the macro binding key"
|
||||
L["OPT_MACROBIND_DESC"] = [=[Defines the key on which the 'Decursive' macro will be called.
|
||||
|
||||
Press the key and hit your 'Enter' keyboard key to save the new assignment (with your mouse cursor over the edit field)]=]
|
||||
L["OPT_MACROOPTIONS"] = "Macro options"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "Set the behaviour of the macro created by Decursive"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "If checked you'll be able to see and cure magic-charmed units"
|
||||
L["OPT_MAGICCHECK_DESC"] = "If checked you'll be able to see and cure magic afflicted units"
|
||||
L["OPT_MAXMFS"] = "Max units shown"
|
||||
L["OPT_MAXMFS_DESC"] = "Defines the max number of micro unit frame to display"
|
||||
L["OPT_MESSAGES"] = "Messages"
|
||||
L["OPT_MESSAGES_DESC"] = "Options about messages display"
|
||||
L["OPT_MFALPHA"] = "Transparency"
|
||||
L["OPT_MFALPHA_DESC"] = "Defines the transparency of the MUFs when units are not afflicted"
|
||||
L["OPT_MFPERFOPT"] = "Performance options"
|
||||
L["OPT_MFREFRESHRATE"] = "Refresh rate"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "Time between each refresh call (1 or several micro-unit-frames can be refreshed at once)"
|
||||
L["OPT_MFREFRESHSPEED"] = "Refresh speed"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "Number of micro-unit-frames to refresh on a single pass"
|
||||
L["OPT_MFSCALE"] = "Scale of the micro-unit-frames"
|
||||
L["OPT_MFSCALE_DESC"] = "Set the size of the micro-unit-frames"
|
||||
L["OPT_MFSETTINGS"] = "Micro Unit Frame Settings"
|
||||
L["OPT_MFSETTINGS_DESC"] = "Set the micro units frame window options to suit your needs"
|
||||
L["OPT_MUFFOCUSBUTTON"] = "Focusing button:"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "Mouse buttons"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "Set the mouse-buttons you want to use for each Micro-Unit-Frame alert color."
|
||||
L["OPT_MUFSCOLORS"] = "Colors"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "Change the colors of the Micro Unit Frames."
|
||||
L["OPT_MUFTARGETBUTTON"] = "Targeting button:"
|
||||
L["OPT_NOKEYWARN"] = "Warn if no key"
|
||||
L["OPT_NOKEYWARN_DESC"] = "Display a warning if no key is mapped."
|
||||
L["OPT_NOSTARTMESSAGES"] = "Disable welcome messages"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "Remove the three messages Decursive prints to the chat frame at every login."
|
||||
L["OPT_PLAYSOUND_DESC"] = "Play a sound if someone get cursed"
|
||||
L["OPT_POISONCHECK_DESC"] = "If checked you'll be able to see and cure poisoned units"
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "Decursive's messages will be printed in a custom chat frame"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "Errors will be displayed"
|
||||
L["OPT_PROFILERESET"] = "Profile reset..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "Units will be displayed and cured randomly (not recommended)"
|
||||
L["OPT_READDDEFAULTSD"] = "Re-add default afflictions"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[Add missing Decursive's default afflictions to this list
|
||||
Your settings won't be changed]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "All Decursive's default afflictions are in this list"
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[Are you sure you want to remove
|
||||
'%s'
|
||||
from Decursive's affliction skip list?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "Remove this affliction"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "Removes '%s' from the skip list"
|
||||
L["OPT_RESETDEBUFF"] = "Reset this affliction"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = "Resets '%s' to Decursive default"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "Reset"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "Reset mouse button assignments to defaults."
|
||||
L["OPT_RESETOPTIONS"] = "Reset options to defaults"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "Reset the current profile to the default values"
|
||||
L["OPT_RESTPROFILECONF"] = [=[Are you sure you want to reset the profile
|
||||
'(%s) %s'
|
||||
to default options?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "The live-list fills itself from bottom to top"
|
||||
L["OPT_SCANLENGTH_DESC"] = "Defines the time between each scan"
|
||||
L["OPT_SHOWBORDER"] = "Show the class-colored borders"
|
||||
L["OPT_SHOWBORDER_DESC"] = "A colored border will be displayed around the MUFs representing the unit's class"
|
||||
L["OPT_SHOWCHRONO"] = "Show chronometers"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "The number of seconds elapsed since a unit has been afflicted is displayed"
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "Time left"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "Display time left instead of time elapsed."
|
||||
L["OPT_SHOWHELP"] = "Show help"
|
||||
L["OPT_SHOWHELP_DESC"] = "Shows an detailed tooltip when you mouse-over a micro-unit-frame"
|
||||
L["OPT_SHOWMFS"] = "Show the Micro Units Frame"
|
||||
L["OPT_SHOWMFS_DESC"] = "This must be enabled if you want to cure by clicking"
|
||||
L["OPT_SHOWMINIMAPICON"] = "Minimap Icon"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "Toggle the minimap icon."
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "Show stealth status"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "When a player is stealthed, his MUF will take a special color"
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "Shows a detailed tooltips about curses in the live-list and on the MUFs"
|
||||
L["OPT_STICKTORIGHT"] = "Align MUF window to the right"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "The MUF window will grow from right to left, the handle will be moved as necessary."
|
||||
L["OPT_TESTLAYOUT"] = "Test Layout"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[Create fake units so you can test the display layout.
|
||||
(Wait a few seconds after clicking)]=]
|
||||
L["OPT_TESTLAYOUTUNUM"] = "Unit number"
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "Set the number of fake units to create."
|
||||
L["OPT_TIECENTERANDBORDER"] = "Tie center and border transparency"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "The transparency of the border is half the center transparency when checked"
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "The live-list display is tied to \"Decursive\" bar display"
|
||||
L["OPT_TIEXYSPACING"] = "Tie horizontal and vertical spacing"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "The horizontal and vertical space between MUFs are the same"
|
||||
L["OPT_UNITPERLINES"] = "Number of units per line"
|
||||
L["OPT_UNITPERLINES_DESC"] = "Defines the max number of micro-unit-frames to display per line"
|
||||
L["OPT_USERDEBUFF"] = "This affliction is not part of Decursive's default afflictions"
|
||||
L["OPT_XSPACING"] = "Horizontal spacing"
|
||||
L["OPT_XSPACING_DESC"] = "Set the Horizontal space between MUFs"
|
||||
L["OPT_YSPACING"] = "Vertical spacing"
|
||||
L["OPT_YSPACING_DESC"] = "Set the Vertical space between MUFs"
|
||||
L["PLAY_SOUND"] = "Play a sound when there is someone to cure"
|
||||
L["POISON"] = "Poison"
|
||||
L["POPULATE"] = "p"
|
||||
L["POPULATE_LIST"] = "Quickly populate the Decursive list"
|
||||
L["PRINT_CHATFRAME"] = "Print messages in default chat"
|
||||
L["PRINT_CUSTOM"] = "Print messages in the window"
|
||||
L["PRINT_ERRORS"] = "Print error messages"
|
||||
L["PRIORITY_LIST"] = "Decursive Priority List"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "Cure in a random order"
|
||||
L["REVERSE_LIVELIST"] = "Reverse live-list display"
|
||||
L["SCAN_LENGTH"] = "Seconds between live scans : "
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "To show Decursive's frame, type /dcrshow"
|
||||
L["SHOW_TOOLTIP"] = "Show Tooltips on afflicted units"
|
||||
L["SKIP_LIST_STR"] = "Decursive Skip List"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "%s spell found!"
|
||||
L["STEALTHED"] = "cloaked"
|
||||
L["STR_CLOSE"] = "Close"
|
||||
L["STR_DCR_PRIO"] = "Decursive Priority"
|
||||
L["STR_DCR_SKIP"] = "Decursive Skip"
|
||||
L["STR_GROUP"] = "Group "
|
||||
L["STR_OPTIONS"] = "Decursive's Options"
|
||||
L["STR_OTHER"] = "Other"
|
||||
L["STR_POP"] = "Populate List"
|
||||
L["STR_QUICK_POP"] = "Quickly Populate"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r |cFF00AA00succeeded on|r %s"
|
||||
L["TARGETUNIT"] = "Target Unit"
|
||||
L["TIE_LIVELIST"] = "Tie live-list visibility to DCR window"
|
||||
L["TOOFAR"] = "Too far"
|
||||
L["UNITSTATUS"] = "Unit Status: "
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["enUS.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Spanish localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "esES");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["esES.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
L["CLASS_HUNTER"] = "Cazador"
|
||||
L["CURSE"] = "Maldición"
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DISEASE"] = "Enfermedad"
|
||||
L["MAGIC"] = "Magia"
|
||||
L["OPT_UNITPERLINES_DESC"] = "Define el número máximo de micro-marcos de unidades a mostrar por línea"
|
||||
L["OPT_XSPACING"] = "Espaciado horizontal"
|
||||
L["OPT_YSPACING"] = "Espaciado vertical"
|
||||
L["PLAY_SOUND"] = "Reproducir un sonido cuando hay alguien a quien curar"
|
||||
L["POISON"] = "Veneno"
|
||||
L["POPULATE"] = "p"
|
||||
L["PRINT_CHATFRAME"] = "Mostrar mensajes en el chat predeterminado"
|
||||
L["RANDOM_ORDER"] = "Curar en orden aleatorio"
|
||||
L["SCAN_LENGTH"] = "Segundos entre escaneos en vivo :"
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "Para mostrar la ventana de Decursive, escribe /dcrshow"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "¡%s hechizo encontrado!"
|
||||
L["STR_CLOSE"] = "Cerrar"
|
||||
L["STR_DCR_PRIO"] = "Prioridad decursive"
|
||||
L["STR_DCR_SKIP"] = "No decursear"
|
||||
L["STR_GROUP"] = "Grupo"
|
||||
L["STR_OPTIONS"] = "Opciones"
|
||||
L["STR_OTHER"] = "Otro"
|
||||
L["TOOFAR"] = "Muy lejos"
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["esES.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,78 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Spanish localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "esMX");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["esMX.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["esMX.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,392 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- French localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "frFR");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["frFR.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end
|
||||
|
||||
L["ABOLISH_CHECK"] = "Voir si \"Abolir\" sur la cible avant de guérir"
|
||||
L["ABOUT_AUTHOREMAIL"] = "CONTACTER L'AUTEUR"
|
||||
L["ABOUT_CREDITS"] = "REMERCIEMENTS"
|
||||
L["ABOUT_LICENSE"] = "LICENCE"
|
||||
L["ABOUT_NOTES"] = "Affichage et guérison des affections avec un système évolué de filtrage et de priorité."
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "SITE OFFICIEL"
|
||||
L["ABOUT_SHAREDLIBS"] = "LIBRAIRIES PARTAGÉES"
|
||||
L["ABSENT"] = "Absente (%s)"
|
||||
L["AFFLICTEDBY"] = "Affecté par %s"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "Nombre d'affectés à afficher : "
|
||||
L["ANCHOR"] = "Ancre du texte"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "Afficher ou masquer les micro-portraits"
|
||||
L["BINDING_NAME_DCRPRADD"] = "Ajouter la cible à la liste de priorités"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "Effacer la liste de priorités"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "Afficher la liste de priorités"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "Afficher ou Cacher la liste de priorités"
|
||||
L["BINDING_NAME_DCRSHOW"] = [=[Afficher ou Cacher la barre Decursive
|
||||
(Ancre de la liste des affectés)]=]
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "Affiche le panneau des options"
|
||||
L["BINDING_NAME_DCRSKADD"] = "Ajouter la cible à la liste des exceptions"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "Effacer la liste des exceptions"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "Afficher la liste des exceptions"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "Afficher ou Cacher la liste des exceptions"
|
||||
L["BLACK_LENGTH"] = "Délais (Secs) sur la *blacklist* : "
|
||||
L["BLACKLISTED"] = "Sur liste noire"
|
||||
L["CHARM"] = "Possession"
|
||||
L["CLASS_HUNTER"] = "Chasseur"
|
||||
L["CLEAR_PRIO"] = "E"
|
||||
L["CLEAR_SKIP"] = "E"
|
||||
L["COLORALERT"] = "Règle la couleur d'alerte quand un '%s' est requis."
|
||||
L["COLORCHRONOS"] = "Chronomètres"
|
||||
L["COLORCHRONOS_DESC"] = "Règle la couleur des chrnomètres"
|
||||
L["COLORSTATUS"] = "Règle la couleur du statut '%s'."
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "Contrôler et guérir les familiers"
|
||||
L["CURSE"] = "Malédiction"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33Merci d'envoyer le contenu de cette fenêtre à Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(Faire CTRL+A pour tout sélectionner et CTRL+C pour le copier dans votre "presse papier")|r
|
||||
Dîtes également dans votre rapport si vous avez remarqué un comportement étrange de Decursive.
|
||||
]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Rapport de debuggage de Decursive|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[Un rapport de debuggage est disponible !
|
||||
Taper |cFFFF0000/dcr general report|r pour le voir.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "Rapport de debuggage disponible !"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "Affiche un rapport de debuggage que l'auteur doit voir..."
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DEV_VERSION_ALERT"] = [=[Vous utilisez une version de développement de Decursive.
|
||||
|
||||
Si vous ne voulez pas participer au test des nouvelles fonctionnalités/corrections, recevoir des rapports de débuggage pendant le jeu, rapporter les problèmes à l'auteur alors N'UTILISEZ PAS CETTE VERSION et télécharger la dernière version STABLE sur curse.com ou wowace.com.
|
||||
|
||||
Ce message ne sera affiché qu'une seule fois par version.
|
||||
|
||||
]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[Cette version de développement de Decursive a expiré.
|
||||
Vous devriez télécharger la dernière version de développement ou retourner à la version stable courante disponible sur CURSE.COM ou WOWACE.COM]=]
|
||||
L["DEWDROPISGONE"] = "Il n'y a pas d'équivalent à DewDrop pour Ace3. Faire Alt-clique-droit pour ouvrir le panneau des options."
|
||||
L["DISABLEWARNING"] = [=[Decursive a été désactivé !
|
||||
Pour le réactiver, tapper |cFFFFAA44/DCR ENABLE|r]=]
|
||||
L["DISEASE"] = "Maladie"
|
||||
L["DONOT_BL_PRIO"] = "Ne pas *blacklister* les gens prioritaires"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r sur %s |cFFAA0000échoué !|r
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "Focalise l'unité"
|
||||
L["FUBARMENU"] = "Menu de Fubar"
|
||||
L["FUBARMENU_DESC"] = "Règles les options relatives à l'icône de FuBar"
|
||||
L["GLOR1"] = "À la mémoire de Glorfindal"
|
||||
L["GLOR2"] = "Decursive est dédié à la mémoire de Bertrand qui nous a quitté bien trop tôt. On se souviendra toujours de lui."
|
||||
L["GLOR3"] = [=[En souvenir de Bertrand Sense
|
||||
1969 - 2007]=]
|
||||
L["GLOR4"] = [=[L'amitié et l'affection peuvent prendre naissance n'importe où, ceux qui ont rencontré Glorfindal dans World Of Warcraft ont connu un homme engagé et un leader charismatique.
|
||||
|
||||
Il était dans la vie comme dans le jeux, désintéressé, généreux, dévoué envers les siens et surtout un homme passionné.
|
||||
|
||||
Il nous a quitté à l'âge de 38 ans laissant derrière lui pas seulement des joueurs anonymes dans un monde virtuel, mais un groupe de véritables amis à qui il manquera éternellement.]=]
|
||||
L["GLOR5"] = "On ne l'oubliera jamais..."
|
||||
L["HANDLEHELP"] = "Déplacer tous les micro-portraits"
|
||||
L["HIDE_LIVELIST"] = "Cacher la liste"
|
||||
L["HIDE_MAIN"] = "Cacher la fenêtre \"Decursive\""
|
||||
L["HIDESHOW_BUTTONS"] = "Cacher/Afficher les boutons"
|
||||
L["HLP_LEFTCLICK"] = "Clic Gauche"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = [=[Cliquer sur la liste est inutile depuis WoW 2.0. Vous devriez lire la FAQ se trouvant dans le fichier "lisez-moi.txt" qui se trouve dans le répertoire de Decursive.
|
||||
(Pour bouger cette liste, bougez la barre de Decursive, /dcrshow et alt-clique-gauche)]=]
|
||||
L["HLP_MIDDLECLICK"] = "Clic Milieu"
|
||||
L["HLP_NOTHINGTOCURE"] = "Il n'y a rien à guérir !"
|
||||
L["HLP_RIGHTCLICK"] = "Clic Droit"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "Utilisez \"%s\" pour guérir cette affection !"
|
||||
L["HLP_WRONGMBUTTON"] = "Mauvais clique !"
|
||||
L["IGNORE_STEALTH"] = "Ignorer les unités camouflées"
|
||||
L["IS_HERE_MSG"] = "Decursive est initialisé, n'oubliez pas de contrôler les options disponibles"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r Click : Efface ce joueur
|
||||
Click |cFF33AA33GAUCHE|r : Monte ce joueur
|
||||
Click |cFF33AA33DROIT|r: Descend ce joueur
|
||||
|cFF33AA33[MAJ]|r Click |cFF33AA33GAUCHE|r : Met ce joueur en haut
|
||||
|cFF33AA33[MAJ]|r Click |cFF33AA33DROIT|r : Met ce joueur en bas]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[ATTENTION: La touche affectée à la macro de Decursive [%s] était affectée à l'action '%s'.
|
||||
Decursive restaurera l'action originale si vous affectez une autre touche à la macro.]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "La touche [%s] n'a pas pu être affectée à la macro de Decursive"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "La touche [%s] a été correctement affectée à la macro de Decursive."
|
||||
L["MACROKEYNOTMAPPED"] = "Aucune touche n'est affectée à la macro de Decursive, reportez-vous aux options concernant la macro !"
|
||||
L["MAGIC"] = "Magie"
|
||||
L["MAGICCHARMED"] = "Contrôle magique"
|
||||
L["MISSINGUNIT"] = "Unité absente"
|
||||
L["NORMAL"] = "Normal"
|
||||
L["NOSPELL"] = "Aucun sort disponible"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "Définit si les unités avec un sort 'Abolir' actif sont affichées et soignées"
|
||||
L["OPT_ABOUT"] = "À propos"
|
||||
L["OPT_ADDDEBUFF"] = "Ajouter une affection"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "Ajoute une nouvelle affection à cette liste"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "Ajouter une affection récente"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "Ajouter une affection depuis l'historique"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<Nom de l'affection>"
|
||||
L["OPT_ADVDISP"] = "Options avancées"
|
||||
L["OPT_ADVDISP_DESC"] = "Permet de régler la transparence de la bordure et du centre séparément, permet de régler l'espace entre les micro-portraits"
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s affecté(e) par %s sera ignoré"
|
||||
L["OPT_ALLOWMACROEDIT"] = "Autoriser l'édition de la macro"
|
||||
L["OPT_ALLOWMACROEDIT_DESC"] = "Activer cette option empêche Decursive de mettre à jour sa macro, vous permettant de la modifier."
|
||||
L["OPT_ALWAYSIGNORE"] = "Ignorer aussi hors combat"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "Si cochée, cette affection sera aussi ignorée en dehors des combats"
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "Définit le nombre max d'affectés affichés dans la liste des affectés."
|
||||
L["OPT_ANCHOR_DESC"] = "Montre l'ancre de la fenêtre de discussion spéciale"
|
||||
L["OPT_AUTOHIDEMFS"] = "Masquer automatiquement"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "Choisissez quand la fenêtre des micro-portraits doit être masquée automatiquement."
|
||||
L["OPT_BLACKLENTGH_DESC"] = "Définit combien de temps quelqu'un reste sur liste noire"
|
||||
L["OPT_BORDERTRANSP"] = "Transparence de la bordure"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "Règle la transparence de la bordure"
|
||||
L["OPT_CENTERTRANSP"] = "Transparence du centre"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "Règle la transparence du centre"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités possédées"
|
||||
L["OPT_CHATFRAME_DESC"] = "Les messages de Decursive seront affichés dans la fenêtre de discussion par défaut"
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "Vérifier les autres joueurs"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "Affiche la version de Decursive utilisée par les joueurs de votre groupe ou de votre guilde (Ne fonctionne qu'à partir de la version 2.4.6 de Decursive)."
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "Créer une affection virtuelle de test"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "Permet de voir ce qu'il se passe lorsqu'une affection est détectée"
|
||||
L["OPT_CUREPETS_DESC"] = "Les familiers seront affichés et guéris"
|
||||
L["OPT_CURINGOPTIONS"] = "Options de guérison"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "Définit les différents aspects du processus de guérison"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[Sélectionnez le type d'affections que vous souhaitez guérir. Cette priorité affecte plusieurs aspects de Decursive :
|
||||
- Ce que Decursive vous montre en premier lorsque un joueur à plusieurs types de debuff en même temps.
|
||||
- Sur quel bouton de la souris vous devrez cliquer pour guérir le debuff (clique gauche pour le premier sort, clique droit pour le second, etc...).
|
||||
|
||||
Tout cela est expliquer dans la documentation (À lire absolument - en anglais) :
|
||||
http://www.wowace.com/addons/decursive/]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "Options sur l'ordre de guérison"
|
||||
L["OPT_CURSECHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités maudites"
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
|
||||
Cochée par défaut]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "Sélectionnez quelle classe doit être ignorée pour cette affection"
|
||||
L["OPT_DEBUFFFILTER"] = "Filtrage des affections"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "Sélectionner les affections à filtrer par nom et par classe pendant les combat"
|
||||
L["OPT_DISABLEABOLISH"] = "Ne pas utiliser les sorts 'Abolir'"
|
||||
L["OPT_DISABLEABOLISH_DESC"] = "Si activée, Decursive préfèrera 'Guérison des maladies' et 'Guérison du poison' à la place de leur équivalent en 'Abolir'"
|
||||
L["OPT_DISABLEMACROCREATION"] = "Ne pas créer de macro"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "La macro de Decursive ne sera plus créée ni mis à jour."
|
||||
L["OPT_DISEASECHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités malade"
|
||||
L["OPT_DISPLAYOPTIONS"] = "Options d'affichage"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "Les unités prioritaires ne seront pas blacklistées"
|
||||
L["OPT_ENABLEDEBUG"] = "Debug"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "Activer les informations de debuggage"
|
||||
L["OPT_ENABLEDECURSIVE"] = "Activer Decursive"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "%q sera ignoré sur les classes spécifiées pendant que vous êtes en combat."
|
||||
L["OPT_GENERAL"] = "Options générales"
|
||||
L["OPT_GROWDIRECTION"] = "Inverser l'affichage des micro-portraits"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "Les micro-portraits seront affichés de bas en haut"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "Si non cochée, affiche une liste des personnes affligés"
|
||||
L["OPT_HIDEMFS_GROUP"] = "Solo / Groupe"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "Masque la fenêtre lorsque vous n'êtes pas dans un raid."
|
||||
L["OPT_HIDEMFS_NEVER"] = "Jamais"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "Ne jamais masquer la fenêtre automatiquement."
|
||||
L["OPT_HIDEMFS_SOLO"] = "Solo"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "Masque la fenêtre lorsque vous n'êtes pas dans un groupe ou dans un raid."
|
||||
L["OPT_HIDEMUFSHANDLE"] = "Chacher la poignée des Micro-Portraits"
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = [=[Cache la poignée des Micro-Portraits et désactive la possibilité de les bouger.
|
||||
Utilisez la même commande pour la retrouver.]=]
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "Les unités camouflées seront ignorées"
|
||||
L["OPTION_MENU"] = "Menu options"
|
||||
L["OPT_LIVELIST"] = "Liste des affligés"
|
||||
L["OPT_LIVELIST_DESC"] = "Options pour la liste des affligés"
|
||||
L["OPT_LLALPHA"] = "Transparence"
|
||||
L["OPT_LLALPHA_DESC"] = [=[Définit la transparence de la barre principale de Decursive et de la liste des affligés
|
||||
(la barre principale doit être affichée)]=]
|
||||
L["OPT_LLSCALE"] = "Échelle de la liste des affectés"
|
||||
L["OPT_LLSCALE_DESC"] = [=[Définit la taille de la barre principale de Decursive et de la liste des affectés
|
||||
(la barre principale doit être affichée)]=]
|
||||
L["OPT_LVONLYINRANGE"] = "Unités à portée seulement"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "Si cette option est activée, uniquement les unités à portée de sorts seront affichées dans la liste"
|
||||
L["OPT_MACROBIND"] = "Définit la touche liée à la macro"
|
||||
L["OPT_MACROBIND_DESC"] = [=[Définit la touche à partir de laquelle la macro 'Decursive' sera appelée.
|
||||
|
||||
Appuyer sur la touche puis sur 'Entrée' pour sauvegarder la nouvelle affectation.]=]
|
||||
L["OPT_MACROOPTIONS"] = "Options de la macro"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "Définit le comportement de la macro créée par Decursive"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités contrôlées par magie"
|
||||
L["OPT_MAGICCHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités affectées par la magie"
|
||||
L["OPT_MAXMFS"] = "Nombre maximum d'unités affichées"
|
||||
L["OPT_MAXMFS_DESC"] = "Définit le nombre maximum de micro-portraits à afficher"
|
||||
L["OPT_MESSAGES"] = "Messages"
|
||||
L["OPT_MESSAGES_DESC"] = "Options sur les messages affichés"
|
||||
L["OPT_MFALPHA"] = "Transparence"
|
||||
L["OPT_MFALPHA_DESC"] = "Définit la transparence des micro-portraits, lorsque l'unité n'est pas affectée."
|
||||
L["OPT_MFPERFOPT"] = "Options de performance"
|
||||
L["OPT_MFREFRESHRATE"] = "Taux de rafraîchissement"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "Période de rafraîchissement (1 ou plusieurs micro-portraits peuvent être rafraîchis en même temps)"
|
||||
L["OPT_MFREFRESHSPEED"] = "Rapidité de rafraîchissement"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "Nombre de micro-portraits à rafraîchir à chaque passage"
|
||||
L["OPT_MFSCALE"] = "Échelle des micro-portraits"
|
||||
L["OPT_MFSCALE_DESC"] = "Définit la taille des micro-portraits"
|
||||
L["OPT_MFSETTINGS"] = "Configuration des micro-portraits"
|
||||
L["OPT_MFSETTINGS_DESC"] = "Réglez les options de la fenêtre des micro-portraits selon vos besoins"
|
||||
L["OPT_MUFFOCUSBUTTON"] = "Bouton de ciblage"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "Boutons de la souris"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "Régler les boutons de la souris que vous souhaitez utiliser pour chaque couleur d'alerte des micro-portraits."
|
||||
L["OPT_MUFSCOLORS"] = "Couleurs"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "Change les couleurs des micro-portraits."
|
||||
L["OPT_MUFTARGETBUTTON"] = "Bouton de focalisation"
|
||||
L["OPT_NOKEYWARN"] = "Avertir si aucune touche"
|
||||
L["OPT_NOKEYWARN_DESC"] = "Affiche un avertissement si aucune touche n'est affectée à la macro."
|
||||
L["OPT_NOSTARTMESSAGES"] = "Désactiver les messages de bienvenue"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "Enlève les trois messages que Decursive écrit dans le chat à chaque connexion."
|
||||
L["OPT_PLAYSOUND_DESC"] = "Joue un son si quelqu'un est affecté."
|
||||
L["OPT_POISONCHECK_DESC"] = "Si cochée, vous pourrez voir et guérir les unités empoisonnées"
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "Les messages de Decursive seront affichés dans une fenêtre de discussion spéciale"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "Les erreurs seront affichées"
|
||||
L["OPT_PROFILERESET"] = "Remise à zéro du profil..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "Les unités seront affichées et guéries au hasard (non recommandé)"
|
||||
L["OPT_READDDEFAULTSD"] = "Ré-ajouter les affections par défaut"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[Ajoute les affections de Decursive manquant à cette liste
|
||||
Votre configuration ne sera pas changée]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "Toutes les affections par défaut de Decursive sont dans cette liste"
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[Êtes-vous sûr de vouloir enlever
|
||||
'%s'
|
||||
de la liste des exceptions ?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "Enlever cette affection"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "Supprime '%s' de la liste d'exception"
|
||||
L["OPT_RESETDEBUFF"] = "Remettre à zéro cette affection"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = "Met '%s' aux valeurs par défaut de Decursive"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "Réinitialiser"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "Réinitialise les affectations des boutons de la souris aux valeurs par défaut."
|
||||
L["OPT_RESETOPTIONS"] = "Remet les options par défaut"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "Met les options du profil courant aux valeurs par défaut"
|
||||
L["OPT_RESTPROFILECONF"] = [=[Êtes-vous sûr de vouloir remettre votre profil
|
||||
'(%s) %s'
|
||||
aux valeurs par défaut ?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "La liste des affectés se remplit de bas en haut"
|
||||
L["OPT_SCANLENGTH_DESC"] = "Définit le temps entre chaque scan"
|
||||
L["OPT_SHOWBORDER"] = "Afficher la bordure colorée des classes"
|
||||
L["OPT_SHOWBORDER_DESC"] = "Une bordure colorée représentant la classe de l'unité est affichée autour des micro-portraits"
|
||||
L["OPT_SHOWCHRONO"] = "Afficher les chronomètres"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "Le nombre de secondes écoulées depuis qu'une unité a été affecté est affiché."
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "Temps restant"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "Affiche le temps restant au lieu du temps écoulé."
|
||||
L["OPT_SHOWHELP"] = "Affiche l'aide"
|
||||
L["OPT_SHOWHELP_DESC"] = "Affiche une bulle d'aide lorsque la souris passe au-dessus d'un micro-portrait"
|
||||
L["OPT_SHOWMFS"] = "Affiche la fenêtre de micro-portraits"
|
||||
L["OPT_SHOWMFS_DESC"] = "Cette option doit être activée, si vous voulez guérir en cliquant avec la souris"
|
||||
L["OPT_SHOWMINIMAPICON"] = "Icône Minicarte"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "Active/Désactive l'icône de la minicarte"
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "Montrer le camouflage"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "Lorsqu'un joueur est camouflé, son micro-portrait prendra une couleur spéciale."
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "Affiche une bulle d'informations détaillées à propos des affections sur les micro-portraits et dans la liste des affectés."
|
||||
L["OPT_STICKTORIGHT"] = "Aligner la fenêtre à droite"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "La fenêtre des micro-portrait se développera de la droite vers la gauche, la poignée sera déplacée automatiquement."
|
||||
L["OPT_TESTLAYOUT"] = "Tester la disposition"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[Créé des unités virtuelles permettant de tester leur disposition.
|
||||
(Attendre quelques secondes après avoir cliqué)]=]
|
||||
L["OPT_TESTLAYOUTUNUM"] = "Nombre d'unité"
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "Règle le nombre d'unité virtuelles à créer."
|
||||
L["OPT_TIECENTERANDBORDER"] = "Lier le centre et la bordure"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "Quand activée, la transparence de la bordure vaut la moitié de celle du centre"
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "L'affichage de la liste des affectés est lié à celui de la barre \"Decursive\""
|
||||
L["OPT_TIEXYSPACING"] = "Lier l'espacement horizontale et verticale"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "L'espacement horizontale et verticale entre les micro-portraits sont identiques"
|
||||
L["OPT_UNITPERLINES"] = "Nombre d'unités par ligne"
|
||||
L["OPT_UNITPERLINES_DESC"] = "Définit le nombre maximum de micro-portraits à afficher par ligne"
|
||||
L["OPT_USERDEBUFF"] = "Cette affection ne fait pas partie de la liste des affections par défaut de Decursive"
|
||||
L["OPT_XSPACING"] = "Espacement horizontal"
|
||||
L["OPT_XSPACING_DESC"] = "Règle l'espacement horizontal entre les micro-portraits"
|
||||
L["OPT_YSPACING"] = "Espacement vertical"
|
||||
L["OPT_YSPACING_DESC"] = "Règle l'espacement vertical entre les micro-portraits"
|
||||
L["PLAY_SOUND"] = "Jouer un son quand il y a quelqu'un à guérir"
|
||||
L["POISON"] = "Poison"
|
||||
L["POPULATE"] = "R"
|
||||
L["POPULATE_LIST"] = "Remplir rapidement la liste"
|
||||
L["PRINT_CHATFRAME"] = "Afficher les messages dans le canal par défaut"
|
||||
L["PRINT_CUSTOM"] = "Afficher les messages dans la fenêtre"
|
||||
L["PRINT_ERRORS"] = "Afficher les messages d'erreurs"
|
||||
L["PRIORITY_LIST"] = "Liste des priorités"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "Guérir aléatoirement"
|
||||
L["REVERSE_LIVELIST"] = "Inverser l'affichage de la liste"
|
||||
L["SCAN_LENGTH"] = "Délai (secs) entre les scans : "
|
||||
L["SHIFT"] = "Maj"
|
||||
L["SHOW_MSG"] = "Pour afficher la fenêtre \"Decursive\", tapez /dcrshow."
|
||||
L["SHOW_TOOLTIP"] = "Afficher les infos-bulles sur les unités affectées"
|
||||
L["SKIP_LIST_STR"] = "Liste des exceptions"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "%s trouvé !"
|
||||
L["STEALTHED"] = "Camouflée"
|
||||
L["STR_CLOSE"] = "Fermer"
|
||||
L["STR_DCR_PRIO"] = "Liste de priorités"
|
||||
L["STR_DCR_SKIP"] = "Liste des exceptions"
|
||||
L["STR_GROUP"] = "Groupe "
|
||||
L["STR_OPTIONS"] = "Options de Decursive"
|
||||
L["STR_OTHER"] = "Autre"
|
||||
L["STR_POP"] = "Remplir la liste"
|
||||
L["STR_QUICK_POP"] = "Remplir rapidement"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r sur %s |cFF00AA00réussi !|r"
|
||||
L["TARGETUNIT"] = "Cible l'unité"
|
||||
L["TIE_LIVELIST"] = "Lier la visibilité de la liste à \"Decursive\""
|
||||
L["TOOFAR"] = "Hors de portée"
|
||||
L["UNITSTATUS"] = "Statut de l'unité : "
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["frFR.lua"] = "2.5.1-6-gd3885c5";
|
||||
|
||||
@@ -0,0 +1,385 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Korean localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Korean localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "koKR");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["koKR.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
L["ABOLISH_CHECK"] = "해제 전 \"해제 주문\" 검사"
|
||||
L["ABOUT_AUTHOREMAIL"] = "제작자 이메일"
|
||||
L["ABOUT_CREDITS"] = "공로자"
|
||||
L["ABOUT_LICENSE"] = "라이센스"
|
||||
L["ABOUT_NOTES"] = "쏠로, 파티, 공격대를 위한 고급화된 필터링과 시스템 우선권으로 고통들의 표시와 제거를 합니다."
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "공식 웹사이트"
|
||||
L["ABOUT_SHAREDLIBS"] = "공유된 라이브러리들"
|
||||
L["ABSENT"] = "(%s) 자리비움"
|
||||
L["AFFLICTEDBY"] = "%s에 걸림"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "표시할 대상의 수 : "
|
||||
L["ANCHOR"] = "Decursive 글자 위치"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "작은 유닛 프레임 표시/숨김"
|
||||
L["BINDING_NAME_DCRPRADD"] = "대상을 우선순위 목록에 추가"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "우선순위 목록 초기화"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "우선순위 목록 출력"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "우선순위 목록 표시/숨김"
|
||||
L["BINDING_NAME_DCRSHOW"] = [=[Decursive 메인바 표시/숨김
|
||||
(실시간 목록 고정위치)]=]
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "고정 창 설정 표시"
|
||||
L["BINDING_NAME_DCRSKADD"] = "대상을 제외 목록에 추가"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "제외 목록 초기화"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "제외 목록 출력"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "제외 목록 표시/숨김"
|
||||
L["BLACK_LENGTH"] = "블랙리스트 추가 시간(초) : "
|
||||
L["BLACKLISTED"] = "블랙리스트됨"
|
||||
L["CHARM"] = "변이"
|
||||
L["CLASS_HUNTER"] = "사냥꾼"
|
||||
L["CLEAR_PRIO"] = "C"
|
||||
L["CLEAR_SKIP"] = "C"
|
||||
L["COLORALERT"] = "'%s'|1이;가; 필요할때의 알림 색상을 설정합니다."
|
||||
L["COLORCHRONOS"] = "크로노미터"
|
||||
L["COLORCHRONOS_DESC"] = "크로노미터의 색상을 설정합니다."
|
||||
L["COLORSTATUS"] = "MUF 상태가 '%s'일때 색상을 설정합니다."
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "소환수 탐색과 해제"
|
||||
L["CURSE"] = "저주"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33Archarodim+DcrReport@teaser.fr로 이 창의 내용을 보고해 주십시오|r
|
||||
|cFF009999(CTRL+A키로 모두 선택하고 CTRL+C키로 당신의 클립보드 내 문자를 넣어 사용하십시오)|r
|
||||
또한 당신이 눈치챈 Decursive의 어떠한 이상 증상도 보고서에 알리십시오.
|
||||
]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Decursive 디버그 보고서|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[디버그 보고서가 유효합니다!
|
||||
|cFFFF0000/dcr general report|r를 입력해 그것을 확인합니다.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "디버그 보고서 유효함!"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "개발자의 확인이 필요한 디버그 보고서 보기..."
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DEV_VERSION_ALERT"] = [=[당신은 Decursive의 개발자 버전을 사용중입니다.
|
||||
|
||||
만약 당신이 새로운 지원들/수정들, 게임중 디버그 보고서 보내기, 개발자에게 문제점 보내기 위해 테스트에 참여하고 싶지않다면 '이 버전을 사용하지 마십시오.' 그리고 curse.com의 최종 '안정화' 버전을 다운로드 하십시오.
|
||||
|
||||
이 메세지는 버전마다 한번씩만 표시됩니다.
|
||||
|
||||
Decursive의 개발자 버전은 플레이어가 게임을 시작 할 때 경고가 표시됩니다.]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[본 Decursive의 개발자 버전은 만료되었습니다.
|
||||
마지막 개발자 버전을 다운로드하거나 CURSE.COM 또는 WOWACE.COM에서 현재 안정화 배포판을 사용해 주십시오.
|
||||
이 경고는 2일간 항상 표시됩니다.
|
||||
|
||||
알림: Decursive의 만료된 개발 버전으로 접속 시 사용자에게 매번 표시됩니다.]=]
|
||||
L["DEWDROPISGONE"] = "거기엔 Ace3에 대해 상응하는 DewDrop이 없습니다. Alt+우-클릭으로 설정판을 여십시오."
|
||||
L["DISABLEWARNING"] = [=[Decursive 사용이 중지되었습니다!
|
||||
|
||||
다시 사용하려면, |cFFFFAA44/DCR ENABLE|r를 입력하세요.]=]
|
||||
L["DISEASE"] = "질병"
|
||||
L["DONOT_BL_PRIO"] = "우선순위 블랙리스트 제외"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r|1으로;로; %s |cFFAA0000치료 실패|r
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "주시대상"
|
||||
L["FUBARMENU"] = "FuBar 메뉴"
|
||||
L["FUBARMENU_DESC"] = "FuBar 아이콘에 관련된 옵션을 설정합니다."
|
||||
L["GLOR1"] = "Glorfindal의 추억속에"
|
||||
L["GLOR2"] = [=[Decursive는 돌아올 수 없는 길을 떠난 Bertrand의 추억에 바칩니다.
|
||||
그는 언제나 기억될 것입니다.]=]
|
||||
L["GLOR3"] = [=[Bertrand Sense를 기억하며
|
||||
1969 - 2007]=]
|
||||
L["GLOR4"] = [=[사랑과 우정은 그들은 언제 어디에서나 얻을 수 있습니다, World of Warcraft에서 Glorfindal을 만났던 사람들은 훌륭히 책임감있고 카리스마 넘치는 지도자로 알고 있었습니다.
|
||||
|
||||
그는 게임 속 삶에 있어서, 모든 이들과 그의 친구들에게 헌신적이고, 사심없고, 관대하였고, 열정적인 사람이었습니다.
|
||||
|
||||
그는 가상 세계 속의 단지 익명 플레이어로써 훗날 38의 나이에 떠나갔지만, 진정한 친구들이라면 그를 영원히 그리워 할 것입니다.]=]
|
||||
L["GLOR5"] = "그는 언제나 기억될 것입니다..."
|
||||
L["HANDLEHELP"] = "작은 유닛 프레임(MUFs) 모두 이동"
|
||||
L["HIDE_LIVELIST"] = "실시간 목록 숨김"
|
||||
L["HIDE_MAIN"] = "Decursive 창 숨김"
|
||||
L["HIDESHOW_BUTTONS"] = "버튼 표시/숨김"
|
||||
L["HLP_LEFTCLICK"] = "좌-클릭"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = [=[실시간 목록을 클릭하는 것은 WoW 2.0 이후 사용할 수 없습니다. Decursive 폴더에 위치한 "Readme.txt" 읽어 보세요...
|
||||
(해당 목록을 이동하려면 /dcrshow 혹은 ALT-좌-클릭하세요.)]=]
|
||||
L["HLP_MIDDLECLICK"] = "가운데-클릭"
|
||||
L["HLP_NOTHINGTOCURE"] = "치료할 것이 없습니다!"
|
||||
L["HLP_RIGHTCLICK"] = "우-클릭"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "해당 디버프를 치료하려면 \"%s\" 버튼을 사용하세요"
|
||||
L["HLP_WRONGMBUTTON"] = "잘못된 마우스 버튼입니다!"
|
||||
L["IGNORE_STEALTH"] = "은신 대상 무시"
|
||||
L["IS_HERE_MSG"] = "Decursive가 초기화 되었습니다. 옵션을 설정하세요."
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r 클릭: 해당 플레이어 제거
|
||||
|cFF33AA33좌|r-클릭: 해당 플레이어를 위로
|
||||
|cFF33AA33우|r-클릭: 해당 플레이어를 아래로
|
||||
|cFF33AA33[SHIFT] 좌|r-클릭: 해당 플레이어를 최상위로
|
||||
|cFF33AA33[SHIFT] 우|r-클릭: 해당 플레이어를 최하위로]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[경고: Decursive 매크로에 지정한 [%s]키는 '%s'|1을;를; 위해 지정되어 있습니다.
|
||||
당신이 매크로에 다른 키를 지정하면 Decursive는 이전 설정을 복원할 것입니다.]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "[%s] 키는 Decursive 매크로로 지정할 수 없습니다!"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "[%s] 키가 Decursive 매크로로 성공적으로 지정되었습니다."
|
||||
L["MACROKEYNOTMAPPED"] = "Decursive 마우스오버 매크로는 지정된 키가 없습니다, '매크로' 설정을 보시면 키를 지정할 수 있습니다!"
|
||||
L["MAGIC"] = "마법"
|
||||
L["MAGICCHARMED"] = "마법 정화"
|
||||
L["MISSINGUNIT"] = "잘못된 대상"
|
||||
L["NORMAL"] = "정상"
|
||||
L["NOSPELL"] = "이용가능한 주문이 없습니다."
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "'해제' 주문을 가진 대상을 표시하고 치유 할 지를 선택합니다."
|
||||
L["OPT_ABOUT"] = "관하여"
|
||||
L["OPT_ADDDEBUFF"] = "목록에 디버프 추가"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "이 목록에 새로운 디버프 추가"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "최근의 디버프 추가"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "예전에 사용된 디버프를 추가합니다."
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<디버프명>"
|
||||
L["OPT_ADVDISP"] = "고급 표시 설정"
|
||||
L["OPT_ADVDISP_DESC"] = "각 MUF 사이 간격 설정을 위해 테두리와 가운데 구분의 투명도를 설정할 수 있습니다."
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s - %s에 걸리면 무시합니다."
|
||||
L["OPT_ALWAYSIGNORE"] = "비전투시에도 항상 무시"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "선택 시 해당 디버프는 전투 중이 아닐때도 무시됩니다."
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "실시간 목록에 표시할 유닛의 최대 수를 지정합니다."
|
||||
L["OPT_ANCHOR_DESC"] = "사용자 정의 메세지창의 고정위치를 표시합니다."
|
||||
L["OPT_AUTOHIDEMFS"] = "자동숨김"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "선택하면 언제 MUF창을 숨겨둘지 설정합니다."
|
||||
L["OPT_BLACKLENTGH_DESC"] = "블랙리스트에 등록할 시간을 지정합니다."
|
||||
L["OPT_BORDERTRANSP"] = "테두리 투명도"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "테두리의 투명도를 설정합니다."
|
||||
L["OPT_CENTERTRANSP"] = "가운데 투명도"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "가운데의 투명도를 설정합니다."
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "선택 시 지배에 걸린 대상을 표시하고 변이합니다."
|
||||
L["OPT_CHATFRAME_DESC"] = "Decursive의 메세지가 기본 대화창에 표시됩니다."
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "다른 플레이어 확인"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "당신이 현재 속한 길드 또는 그룹 플레이어의 Decursive 버전을 표시합니다. (Decursive 2.4.6 이전 버전은 표시할 수 없습니다.)"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "가상 테스트 디버프 생성"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "디버프 발생 시 어떻게 보여지는 지를 표시하도록 합니다."
|
||||
L["OPT_CUREPETS_DESC"] = "소환수를 관리하고 해제합니다."
|
||||
L["OPT_CURINGOPTIONS"] = "해제 옵션"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "해제의 다양한 형태를 설정합니다."
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
당신이 치료를 원하는 재난의 유형을 선택, 선택하지 않은 유형은 Decursive에서 완전히 무시될 것입니다.
|
||||
|
||||
재난의 우선 순위는 녹색 숫자로 정의됩니다. 이것은 몇 가지 영향을 미칠 것입니다:
|
||||
- 플레이어에 여러 종류의 디버프가 걸려있으면 Decursive가 먼저 표시 할 지.
|
||||
- 당신이 디버프를 치료하려 어떤 마우스 버튼을 클릭 할 지.(첫째 주문은 좌-클릭, 둘째는 우-클릭, 등...)
|
||||
|
||||
여기에 모든 설명이 기술되어 있습니다(참조 요망):
|
||||
http://www.wowace.com/addons/decursive/]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "해제 순서 설정"
|
||||
L["OPT_CURSECHECK_DESC"] = "체크 시 저주에 걸린 대상을 표시하고 치료합니다."
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
기본값으로 설정됨]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "해당 디버프에 걸렸을 때 전투 중 무시할 직업을 선택하세요."
|
||||
L["OPT_DEBUFFFILTER"] = "디버프 필터링"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "이름과 직업에 의해 필터링 할 디버프를 선택합니다."
|
||||
L["OPT_DISABLEMACROCREATION"] = "매크로 생성 사용안함"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Decursive 매크로를 더 이상 생성 또는 유지할 수 없습니다."
|
||||
L["OPT_DISEASECHECK_DESC"] = "선택 시 질병에 걸린 대상을 표시하고 치료합니다."
|
||||
L["OPT_DISPLAYOPTIONS"] = "디스플레이 옵션"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "우선순위에 등록된 유닛은 블랙리스트에 추가하지 않습니다."
|
||||
L["OPT_ENABLEDEBUG"] = "디버깅 사용"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "디버깅 출력 사용"
|
||||
L["OPT_ENABLEDECURSIVE"] = "Decursive 사용"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "당신이 전투중인 동안 %q로 지정된 클래스는 무시됩니다."
|
||||
L["OPT_GENERAL"] = "기본 설정"
|
||||
L["OPT_GROWDIRECTION"] = "MUF 표시 반전"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "MUF를 하단에서 상단으로 표시합니다."
|
||||
L["OPT_HIDELIVELIST_DESC"] = "숨긴다면 해제된 대상의 정보를 표시합니다."
|
||||
L["OPT_HIDEMFS_GROUP"] = "솔로/파티"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "MUF창을 공격대에 속해있지 않을 때 숨겨둡니다."
|
||||
L["OPT_HIDEMFS_NEVER"] = "사용안함"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "MUF창의 자동숨김을 사용하지 않습니다."
|
||||
L["OPT_HIDEMFS_SOLO"] = "솔로"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "MUF창을 파티나 공격대에 속해있지 않을 때 숨겨둡니다."
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "은신한 대상을 무시합니다."
|
||||
L["OPTION_MENU"] = "Decursive 설정 메뉴"
|
||||
L["OPT_LIVELIST"] = "실시간 목록"
|
||||
L["OPT_LIVELIST_DESC"] = "실시간 목록에 대한 설정입니다."
|
||||
L["OPT_LLALPHA"] = "실시간 목록 투명도"
|
||||
L["OPT_LLALPHA_DESC"] = "Decursive 메인바와 실시간 목록의 투명도를 변경합니다. (메인바가 표시되어 있어야 함)"
|
||||
L["OPT_LLSCALE"] = "실시간 목록 크기"
|
||||
L["OPT_LLSCALE_DESC"] = "Decursive 메인바와 실시간 목록의 크기를 설정합니다. (메인바가 표시되어 있어야 함)"
|
||||
L["OPT_LVONLYINRANGE"] = "범위 내 대상"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "해제 범위 내 대상만 실시간 목록에 표시합니다."
|
||||
L["OPT_MACROBIND"] = "매크로 단축키 설정"
|
||||
L["OPT_MACROBIND_DESC"] = [=['Decursive' 매크로를 호출 할 키를 지정합니다.
|
||||
|
||||
키를 누르고 키보드의 'Enter'키를 누르면 새롭게 지정된 키가 저장됩니다.(당신의 마우스 커서가 편집 구역내에 있어야 합니다)]=]
|
||||
L["OPT_MACROOPTIONS"] = "매크로 설정"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "Decursive에 의해 생성된 매크로의 동작을 설정합니다."
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "체크 시 지배에 걸린 대상을 표시하고 치료합니다."
|
||||
L["OPT_MAGICCHECK_DESC"] = "체크 시 마법에 걸린 대상을 표시하고 치료합니다."
|
||||
L["OPT_MAXMFS"] = "표시할 최대 유닛"
|
||||
L["OPT_MAXMFS_DESC"] = "표시할 작은 유닛 프레임의 최대 갯수를 지정합니다."
|
||||
L["OPT_MESSAGES"] = "메세지"
|
||||
L["OPT_MESSAGES_DESC"] = "메세지 표시에 대한 설정입니다."
|
||||
L["OPT_MFALPHA"] = "투명도"
|
||||
L["OPT_MFALPHA_DESC"] = "디버프의 걸린 대상이 없을 때 MUF의 투명도를 지정합니다."
|
||||
L["OPT_MFPERFOPT"] = "성능 설정"
|
||||
L["OPT_MFREFRESHRATE"] = "갱신 주기"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "갱신할 시간 간격(한번에 1 혹은 그 이상 작은 유닛 프레임을 갱신할 수 있습니다.)"
|
||||
L["OPT_MFREFRESHSPEED"] = "갱신 속도"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "한번에 갱신할 작은 유닛 프레임의 갯수"
|
||||
L["OPT_MFSCALE"] = "작은 유닛 프레임의 크기"
|
||||
L["OPT_MFSCALE_DESC"] = "작은 유닛 프레임의 크기를 설정합니다."
|
||||
L["OPT_MFSETTINGS"] = "작은 유닛 프레임 설정"
|
||||
L["OPT_MFSETTINGS_DESC"] = "작은 유닛 프레임에 대한 설정입니다."
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "마우스 버튼"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "각 MUF의 경고색을 위해 당신이 사용하고자하는 마우스 버튼을 설정합니다."
|
||||
L["OPT_MUFSCOLORS"] = "색상"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "작은 유닛 프레임의 색상을 변경합니다."
|
||||
L["OPT_NOKEYWARN"] = "키 없음 경고"
|
||||
L["OPT_NOKEYWARN_DESC"] = "지정된 키가 없다면 경고 문구를 표시합니다."
|
||||
L["OPT_NOSTARTMESSAGES"] = "환영 메세지 사용안함"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "매일 로그인 시 대화창에 Decursive가 출력하는 3개의 메세지를 제거합니다."
|
||||
L["OPT_PLAYSOUND_DESC"] = "해제 가능한 디버프 발견시 효과음을 재생합니다."
|
||||
L["OPT_POISONCHECK_DESC"] = "체크 시 독에 걸린 대상을 표시하고 치료합니다."
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "Decursive의 메세지가 사용자 정의 대화창에 표시됩니다."
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "오류를 표시합니다."
|
||||
L["OPT_PROFILERESET"] = "프로필 초기화..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "대상을 무작위로 표시하고 치료합니다.(비추천)"
|
||||
L["OPT_READDDEFAULTSD"] = "기본 디버프 재추가"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[해당 목록에 누락된 Decursive의 기본 디버프를 추가합니다.
|
||||
설정은 변하지 않습니다.]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "Decursive의 모든 기본 디버프는 해당 목록에 있습니다."
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[정말로 Decursive의 디버프 제외 목록에서
|
||||
'%s'|1을;를; 제거 하시겠습니까?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "해당 디버프 제거"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "제외 목록에서 '%s' 제거"
|
||||
L["OPT_RESETDEBUFF"] = "해당 디버프 초기화"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = "'%s' Decursive 기본으로 초기화"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "초기화"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "기본값으로 할당된 마우스 버튼을 초기화합니다."
|
||||
L["OPT_RESETOPTIONS"] = "기본값으로 설정 초기화"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "현재 프로필을 기본값으로 초기화합니다."
|
||||
L["OPT_RESTPROFILECONF"] = [=[정말로 '(%s) %s'
|
||||
프로필을 기본 설정으로
|
||||
초기화 하시겠습니까?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "실시간 목록을 아래에서 위로 생성합니다."
|
||||
L["OPT_SCANLENGTH_DESC"] = "각 탐색의 시간 간격을 지정합니다."
|
||||
L["OPT_SHOWBORDER"] = "직업 색상 테두리 표시"
|
||||
L["OPT_SHOWBORDER_DESC"] = "MUF에 유닛의 직업에 따른 색상을 테두리로 표시합니다."
|
||||
L["OPT_SHOWCHRONO"] = "크로노미터 표시"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "유닛이 주문에 걸린 이후 경과된 초의 숫자를 표시합니다."
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "남은 시간"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "경과한 시간 대신 남은 시간을 표시합니다."
|
||||
L["OPT_SHOWHELP"] = "도움말 표시"
|
||||
L["OPT_SHOWHELP_DESC"] = "작은 유닛 프레임에 마우스를 올리면 정보 툴팁을 표시합니다."
|
||||
L["OPT_SHOWMFS"] = "작은 유닛 프레임(MUF) 표시"
|
||||
L["OPT_SHOWMFS_DESC"] = "클릭으로 해제하려면 반드시 활성화 되어야 합니다."
|
||||
L["OPT_SHOWMINIMAPICON"] = "미니맵 아이콘"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "미니맵 아이콘을 표시합니다."
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "은신 상태 보기"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "플레이어가 은신중이면, 그 MUF는 특정한 색상을 갖게 될 것임"
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "실시간 목록과 작은 유닛 프레임에 디버프에 대한 자세한 툴팁을 표시합니다."
|
||||
L["OPT_STICKTORIGHT"] = "MUF창 오른쪽으로 정렬"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "MUF창은 오른쪽에서 왼쪽으로 증가되며 동작은 자동적으로 이루어질 것입니다."
|
||||
L["OPT_TIECENTERANDBORDER"] = "가운데와 테두리의 투명도"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "체크 시 테두리의 투명도가 가운데 투명도의 절반이 됩니다."
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "실시간 목록을 아래에서 위로 생성합니다."
|
||||
L["OPT_TIEXYSPACING"] = "수평/수직 간격"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "MUF의 수평과 수직 간격이 같아 집니다."
|
||||
L["OPT_UNITPERLINES"] = "한줄에 표시할 유닛의 갯수"
|
||||
L["OPT_UNITPERLINES_DESC"] = "한줄에 표시할 작은 유닛 프레임의 최대 갯수를 지정합니다."
|
||||
L["OPT_USERDEBUFF"] = "해당 디버프는 Decursive의 기본 디버프가 아닙니다."
|
||||
L["OPT_XSPACING"] = "수평 간격"
|
||||
L["OPT_XSPACING_DESC"] = "MUF 사이의 수평 간격을 설정합니다."
|
||||
L["OPT_YSPACING"] = "수직 간격"
|
||||
L["OPT_YSPACING_DESC"] = "MUF 사이의 수직 간격을 설정합니다."
|
||||
L["PLAY_SOUND"] = "효과음 재생"
|
||||
L["POISON"] = "독"
|
||||
L["POPULATE"] = "p"
|
||||
L["POPULATE_LIST"] = "Decursive 목록에 빠른 추가"
|
||||
L["PRINT_CHATFRAME"] = "기본 대화창에 메세지 표시"
|
||||
L["PRINT_CUSTOM"] = "Decursive 창에 메세지 표시"
|
||||
L["PRINT_ERRORS"] = "오류 메세지 출력"
|
||||
L["PRIORITY_LIST"] = "Decursive 우선순위 목록"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "무작위 해제"
|
||||
L["REVERSE_LIVELIST"] = "실시간 목록 표시 반전"
|
||||
L["SCAN_LENGTH"] = "실시간 탐색 시간(초) : "
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "Decursive 창 표시, /dcrshow 명령어를 입력하세요."
|
||||
L["SHOW_TOOLTIP"] = "디버프 걸린 대상의 툴팁 표시"
|
||||
L["SKIP_LIST_STR"] = "Decursive 제외 목록"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "%s 주문 발견!"
|
||||
L["STEALTHED"] = "은신상태"
|
||||
L["STR_CLOSE"] = "닫기"
|
||||
L["STR_DCR_PRIO"] = "Decursive 우선순위"
|
||||
L["STR_DCR_SKIP"] = "Decursive 제외"
|
||||
L["STR_GROUP"] = "파티 "
|
||||
L["STR_OPTIONS"] = "Decursive 설정"
|
||||
L["STR_OTHER"] = "기타"
|
||||
L["STR_POP"] = "추가 목록"
|
||||
L["STR_QUICK_POP"] = "빠른 추가"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r|1으로;로; %s |cFF00AA00치료 성공!|r"
|
||||
L["TARGETUNIT"] = "대상"
|
||||
L["TIE_LIVELIST"] = "실시간 목록 표시를 DCR 창과 함께 표시"
|
||||
L["TOOFAR"] = "거리 벗어남"
|
||||
L["UNITSTATUS"] = "상태: "
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["koKR.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,14 @@
|
||||
<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">
|
||||
|
||||
<Script file="enUS.lua"/>
|
||||
<Script file="deDE.lua"/>
|
||||
<Script file="esES.lua"/>
|
||||
<Script file="esMX.lua"/>
|
||||
<Script file="frFR.lua"/>
|
||||
<Script file="koKR.lua"/>
|
||||
<Script file="ruRU.lua"/>
|
||||
<Script file="zhCN.lua"/>
|
||||
<Script file="zhTW.lua"/>
|
||||
|
||||
</Ui>
|
||||
@@ -0,0 +1,388 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Russian localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "ruRU");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["ruRU.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
L["ABOLISH_CHECK"] = "Проверять на наличие Устранения яда/болезни перед лечением"
|
||||
L["ABOUT_AUTHOREMAIL"] = "E-mail автора"
|
||||
L["ABOUT_CREDITS"] = "РАЗРАБОТЧИКИ"
|
||||
L["ABOUT_LICENSE"] = "ПРАВА"
|
||||
L["ABOUT_NOTES"] = "Отображение и инструменты для развеивания дебаффов для одиночной игры, игры в группе и рейде, с развитой системой фильтрации и приоритетов."
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "ОФИЦИАЛЬНЫЙ САЙТ"
|
||||
L["ABOUT_SHAREDLIBS"] = "ОБЩИЕ БИБЛИОТЕКИ"
|
||||
L["ABSENT"] = "Отсутствует (%s)"
|
||||
L["AFFLICTEDBY"] = "%s заражен"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "Количество отображаемых заражений : "
|
||||
L["ANCHOR"] = "Якорь окна сообщений Decursive"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "Показать или скрыть микро-фреймы игроков"
|
||||
L["BINDING_NAME_DCRPRADD"] = "Добавить цель в список приоритетов"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "Очистить список приоритетов"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "Вывести список приоритетов"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "Показать или скрыть список приоритета"
|
||||
L["BINDING_NAME_DCRSHOW"] = [=[Показать/скрыть главную панель Decursive
|
||||
(якорь активного списка)]=]
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "Отображать опции панели"
|
||||
L["BINDING_NAME_DCRSKADD"] = "Добавить цель в список пропусков"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "Очистить список пропусков"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "Распечатка списка пропусков"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "Показать или скрыть список пропусков"
|
||||
L["BLACK_LENGTH"] = "Секунд в чёрном списке : "
|
||||
L["BLACKLISTED"] = "В чёрном списке"
|
||||
L["CHARM"] = "Подчинение"
|
||||
L["CLASS_HUNTER"] = "Охотник"
|
||||
L["CLEAR_PRIO"] = "О"
|
||||
L["CLEAR_SKIP"] = "О"
|
||||
L["COLORALERT"] = "Установить предупреждающий цвет, когда требуется '%s'."
|
||||
L["COLORCHRONOS"] = "Хронометры"
|
||||
L["COLORCHRONOS_DESC"] = "Установить цвет хронометров"
|
||||
L["COLORSTATUS"] = "Установить цвет для статуса МФИ: '%s'."
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "Скан и лечение питомцев"
|
||||
L["CURSE"] = "Проклятие"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33Пожайлуйста, отправьте содержимое этого окна по адресу Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(Нажмите CTRL+A, чтобы выделить всё содержимое, а затем CTRL+C, чтобы переместить его в буфер обмена)|r
|
||||
В своём отчёте также сообщите о неполадках в работе Decursive, если таковые имеются.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Отчёт об отладке Decursive|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[Отчёт об отладке доступен!
|
||||
Введите |cFFFF0000/dcr general report|r, чтобы увидеть его.]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "Отчёт об отладке доступен!"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "Показать отчет о поиске ошибок, который необходимо представить автору..."
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DEV_VERSION_ALERT"] = [=[Вы используете тестовую версию Decursive.
|
||||
|
||||
Если вы не желаете участвовать в тестировании новых функций и исправлении ошибок, получать внутриигровые отчеты об ошибках, посылать отчеты автору, тогда НЕ ИСПОЛЬЗУЙТЕ ЭТУ ВЕРСИЮ и скачайте последнюю СТАБИЛЬНУЮ версию с curse.com или wowace.com.
|
||||
|
||||
Это сообщение будет отображаться каждый раз при установке каждой новой тестовой версии.]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[Эта тестовая версия Decursive устарела.
|
||||
Пожалуйста, скачайте последнюю тестовую версию или используйте текущую стабильную версию с CURSE.COM или WOWACE.COM.
|
||||
|
||||
Спасибо :-)]=]
|
||||
L["DEWDROPISGONE"] = "Для Ace3 не существует эквивалента DewDrop. Alt+Правый щелчок, чтобы открыть настройки."
|
||||
L["DISABLEWARNING"] = [=[Decursive отключен!
|
||||
|
||||
Чтобы включить его снова, введите |cFFFFAA44/DCR ENABLE|r]=]
|
||||
L["DISEASE"] = "Болезни"
|
||||
L["DONOT_BL_PRIO"] = "Не вносить в чёрный список имена из списка приоритетов"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r |cFFAA0000неудачно на|r %s
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "Фокус"
|
||||
L["FUBARMENU"] = "Меню FuBarа"
|
||||
L["FUBARMENU_DESC"] = "Настройка иконки FuBarа"
|
||||
L["GLOR1"] = "В память о Glorfindal'е"
|
||||
L["GLOR2"] = [=[Decursive посвящён памяти о Бертране, который оставил нас слишком рано.
|
||||
Его всегда будут помнить.]=]
|
||||
L["GLOR3"] = [=[В память о Bertrand Sense
|
||||
1969 - 2007]=]
|
||||
L["GLOR4"] = [=[Дружба и привязанность могут пустить свои корни где угодно. Те, кто встретился с Glorfindal в World of Warcraft, знали его как человека с великими обязательствами, и харизматического лидера.
|
||||
|
||||
В жизни он был таким же, как и в игре: самоотверженным, щедрым, преданным своим друзьям и, прежде всего всего, страстным человеком.
|
||||
|
||||
Он оставил нас в возрасте 38 лет, оставив не только игроков в виртуальном мире, но и группу истинных друзей, которые будут тосковать без него всегда.]=]
|
||||
L["GLOR5"] = "Его всегда будут помнить..."
|
||||
L["HANDLEHELP"] = "Тащить все микро-фреймы игроков (МФИ)"
|
||||
L["HIDE_LIVELIST"] = "Скрыть активный список"
|
||||
L["HIDE_MAIN"] = "Скрыть окно Decursive"
|
||||
L["HIDESHOW_BUTTONS"] = "Скрыть/Показать кнопки"
|
||||
L["HLP_LEFTCLICK"] = "Левый клик"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = [=[Щелканье по активному списку является бесполезным после WoW 2.0. Вы должны прочитать файл "Readme.txt", находящийся в папке Decursive...
|
||||
(Для перемещения этого списка переместите панель Decursive, /dcrshow и alt+клик левой кнопкой для изменения положения)]=]
|
||||
L["HLP_MIDDLECLICK"] = "Центральный клик"
|
||||
L["HLP_NOTHINGTOCURE"] = "Нечего лечить!"
|
||||
L["HLP_RIGHTCLICK"] = "Правый клик"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "Используйте \"%s\" для излечения данного заражения!"
|
||||
L["HLP_WRONGMBUTTON"] = "Неверная кнопка мыши!"
|
||||
L["IGNORE_STEALTH"] = "Игнорировать невидимых игроков"
|
||||
L["IS_HERE_MSG"] = "Decursive инициализирован, не забудьте проверить настройки"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r клик: Удалить данного игрока
|
||||
|cFF33AA33ЛЕВЫЙ|r клик: Повысить данного игрока
|
||||
|cFF33AA33ПРАВЫЙ|r клик:Понизить данного игрока
|
||||
|cFF33AA33[SHIFT]ЛЕВЫЙ|r клик: Поместить данного игрока вверх
|
||||
|cFF33AA33[SHIFT]ПРАВЫЙ|r клик: Поместить данного игрока вниз]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[ПРЕДУПРЕЖДЕНИЕ: Клавиша, назначенная для макроса Decursive [%s], уже назначена на '%s'.
|
||||
Decursive восстановит предыдущее назначение, если вы назначите другую клавишу для этого макроса.]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "Клавиша [%s] не может быть назначена для макроса Decursive!"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "Клавиша [%s] успешно назначена для макроса Decursive."
|
||||
L["MACROKEYNOTMAPPED"] = "Макросу Decursive не назначена клавиша, проверьте настройки макросов!"
|
||||
L["MAGIC"] = "Магия"
|
||||
L["MAGICCHARMED"] = "Магическое очарования"
|
||||
L["MISSINGUNIT"] = "Потеря игрока"
|
||||
L["NORMAL"] = "Нормальное"
|
||||
L["NOSPELL"] = "Нет доступных заклинаний"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "выберите, отображать ли игроков с активным на них заклинанием 'Устранение', делая их доступными для лечения"
|
||||
L["OPT_ABOUT"] = "О проекте"
|
||||
L["OPT_ADDDEBUFF"] = "Добавить недуг"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "Добавить новый недуг в данный список"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "Добавить недавнее заражение"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "Добавить заражение, используя историю"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<Название недуга>"
|
||||
L["OPT_ADVDISP"] = "Доп. настройки отображения"
|
||||
L["OPT_ADVDISP_DESC"] = "Позволяет установить прозрачность краёв и центра раздельно, а также установить расстояние между МФИ"
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s пораженный %s будет пропущен"
|
||||
L["OPT_ALWAYSIGNORE"] = "Также игнорировать вне боя"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "Если отмечено, данный недуг будет также игнорироваться, когда вы находитесь вне боя"
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "Установить максимальное количество отображаемых в активном списке заражений"
|
||||
L["OPT_ANCHOR_DESC"] = "Отображать указатель пользовательского фрейма ошибок"
|
||||
L["OPT_AUTOHIDEMFS"] = "Автоскрытие"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "Выберите, когда скрывать МФИ"
|
||||
L["OPT_BLACKLENTGH_DESC"] = "Установить продолжительность нахождения кого-либо в чёрном списке"
|
||||
L["OPT_BORDERTRANSP"] = "Прозрачность краёв"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "Установка прозрачности краёв"
|
||||
L["OPT_CENTERTRANSP"] = "Прозрачность центра"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "Установка прозрачности центра"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать очарованных игроков"
|
||||
L["OPT_CHATFRAME_DESC"] = "Сообщения Decursive будут выводиться в стандартное окно чата"
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "Проверить других игроков"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "Отображать версию Decursive других игроков вашей группы или гильдии (отображает только версии Decursive свыше 2.4.6)."
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "Создать виртуальный тест заражения"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "Позволяет вам увидеть, как будет всё это выглядеть, когда будет обнаружено заражение"
|
||||
L["OPT_CUREPETS_DESC"] = "Питомцы будут отображаться и излечиваться"
|
||||
L["OPT_CURINGOPTIONS"] = "Настройки лечения"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "Настроить различные аспекты процесса лечения"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
Выберите типы колдовства, которые вы желаете развеивать, невыбранные типы будут игнорироваться Decursive.
|
||||
|
||||
Зеленый номер определяет приоритет колдовства. Этот приоритет будет влиять на несколько аспектов:
|
||||
- Что Decursive показывает Вам в первую очередь, если на игрока наложено несколько типов дебаффов.
|
||||
- Какую кнопку мыши Вы должны будете нажать, чтобы развеять дебафф (Первое заклинание развеивается Левым щелчком, второе Правым, и т.д...)
|
||||
|
||||
Все это описано в документации (необходимо прочесть):
|
||||
http://www.wowace.com/addons/decursive/]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "Настройки порядка лечения"
|
||||
L["OPT_CURSECHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать проклятых игроков"
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
Назначен на стандарт]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "Выберите класс, который будет игнорироваться в бою при поражении данным недугом"
|
||||
L["OPT_DEBUFFFILTER"] = "Фильтрование недугов"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "Выберите недуги для фильтрации по имени и классу, когда вы находитесь в бою"
|
||||
L["OPT_DISABLEMACROCREATION"] = "Отключить создание макроса"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Макрос Decursive больше не будет создаваться или поддерживаться"
|
||||
L["OPT_DISEASECHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать заболевших игроков"
|
||||
L["OPT_DISPLAYOPTIONS"] = "Настройки отображения"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "Приоритетный игрок не может быть в чёрном списке"
|
||||
L["OPT_ENABLEDEBUG"] = "Включить поиск ошибок"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "Включить вывод информации при поиске ошибок"
|
||||
L["OPT_ENABLEDECURSIVE"] = "Включить Decursive"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "%q будет игнорироваться для указаных классов, пока вы находитесь в режиме боя."
|
||||
L["OPT_GENERAL"] = "Основные настройки"
|
||||
L["OPT_GROWDIRECTION"] = "Перевернуть отображение МФИ"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "МФИ будет отображаться снизу вверх"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "Если не скрыт, отображает информацию о зараженных игроках"
|
||||
L["OPT_HIDEMFS_GROUP"] = "Один/в группе"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "Скрывать МФИ, когда вы не находитесь в рейде"
|
||||
L["OPT_HIDEMFS_NEVER"] = "Никогда"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "Никогда не скрывать МФИ автоматически"
|
||||
L["OPT_HIDEMFS_SOLO"] = "Один"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "Скрывать МФИ, когда вы не находитесь в группе или в рейде"
|
||||
L["OPT_HIDEMUFSHANDLE"] = "Скрыть поддержку микро-фреймов игроков." -- Needs review
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = [=[Скрыть микро-фреймы игроков и отключить возможность их перемещения.
|
||||
Используйте такую же команду, чтобы вернуть её назад.]=] -- Needs review
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "Скрывающиеся игроки будут игнорироваться"
|
||||
L["OPTION_MENU"] = "Меню настроек Decursive"
|
||||
L["OPT_LIVELIST"] = "Активный список"
|
||||
L["OPT_LIVELIST_DESC"] = "Настройки активного списка"
|
||||
L["OPT_LLALPHA"] = "Прозрачность активного списка"
|
||||
L["OPT_LLALPHA_DESC"] = "Изменение прозрачности главной панели Decursive и активного списка (Главная панель должна быть включена)"
|
||||
L["OPT_LLSCALE"] = "Масштаб активного списка"
|
||||
L["OPT_LLSCALE_DESC"] = "Установка размера главной панели Decursive и активного списка (Главная панель должна быть включена)"
|
||||
L["OPT_LVONLYINRANGE"] = "Только игроки в пределах досягаемости"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "В активном списке будут отображаться только те игроки, которые находятся в радиусе рассеивания"
|
||||
L["OPT_MACROBIND"] = "Назначить клавишу для макроса"
|
||||
L["OPT_MACROBIND_DESC"] = [=[Установка клавиши, с помощью которой будет вызываться макрос 'Decursive'.
|
||||
|
||||
Выберите клавишу и нажмите 'Enter' для сохранения нового назначения (установив курсор мыши над областью редактирования)]=]
|
||||
L["OPT_MACROOPTIONS"] = "Настройки макросов"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "Установка поведения макросов, созданных Decursive"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать магически очарованных игроков"
|
||||
L["OPT_MAGICCHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать пораженных магией игроков"
|
||||
L["OPT_MAXMFS"] = "Всего игроков"
|
||||
L["OPT_MAXMFS_DESC"] = "Установить максимальное количество игроков, отображаемых на микро-фреймах"
|
||||
L["OPT_MESSAGES"] = "Сообщения"
|
||||
L["OPT_MESSAGES_DESC"] = "Настройки отображения сообщений"
|
||||
L["OPT_MFALPHA"] = "Прозрачность"
|
||||
L["OPT_MFALPHA_DESC"] = "Установка прозрачности МФИ, когда игроки не поражены"
|
||||
L["OPT_MFPERFOPT"] = "Настройки быстродействия"
|
||||
L["OPT_MFREFRESHRATE"] = "Частота обновления"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "Время между запросами (один или несколько МФИ могут быть обновлены одновременно)"
|
||||
L["OPT_MFREFRESHSPEED"] = "Скорость обновления"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "Количество микро-фреймов игроков, обновляемых в однократном прохождении"
|
||||
L["OPT_MFSCALE"] = "Масштаб микро-фреймов игроков"
|
||||
L["OPT_MFSCALE_DESC"] = "Установка размера микро-фреймов игроков"
|
||||
L["OPT_MFSETTINGS"] = "Настройки микро-фреймов игроков"
|
||||
L["OPT_MFSETTINGS_DESC"] = "Настройка микро-фреймов игроков"
|
||||
L["OPT_MUFFOCUSBUTTON"] = "Кнопка фокуса:"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "Кнопки мыши"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "Задать кнопки мыши для использования с каждым цветом оповещения микро-фреймов игроков." -- Needs review
|
||||
L["OPT_MUFSCOLORS"] = "Цвета"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "Изменить цвета микро-фреймов игроков."
|
||||
L["OPT_MUFTARGETBUTTON"] = "Кнопка цели:"
|
||||
L["OPT_NOKEYWARN"] = "Известить, если нет клавиши"
|
||||
L["OPT_NOKEYWARN_DESC"] = "Показать предупреждение, если нет назначенной клавиши."
|
||||
L["OPT_NOSTARTMESSAGES"] = "Отключить приветствие"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "Отключает выводимые сообщения Decursivа в окно чата при каждом подключении."
|
||||
L["OPT_PLAYSOUND_DESC"] = "Проигрывать звук при заражении кого-либо"
|
||||
L["OPT_POISONCHECK_DESC"] = "Если отмечено, то вы сможете видеть и излечивать отравленных игроков"
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "Сообщения Decursive будут выводиться в пользовательское окно чата"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "Выводить сообщения об ошибках"
|
||||
L["OPT_PROFILERESET"] = "Сброс профиля..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "Игроки будут отображаться и излечиваться в случайном порядке (не рекомендуется)"
|
||||
L["OPT_READDDEFAULTSD"] = "Повторно добавить стандартный недуг"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[Добавить утерянные стандартные недуги Decursive в данный список
|
||||
Ваши настройки не будут изменены]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "Все стандартные недуги Decursive уже существуют в данном списке"
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[Вы уверены, что хотите удалить
|
||||
'%s'
|
||||
из списка пропусков?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "Удалить данный недуг"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "Удалить '%s' из списка пропусков"
|
||||
L["OPT_RESETDEBUFF"] = "Сброс данного недуга"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = "Сброс '%s' на стандарт Decursive"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "Сброс"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "Сброс назначений кнопок мыши на значения по умолчанию."
|
||||
L["OPT_RESETOPTIONS"] = "Сброс настроек на стандартные"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "Сброс текущих настроек профиля на стандартные значения"
|
||||
L["OPT_RESTPROFILECONF"] = [=[Вы уверены, что хотите сбросить настройки профиля
|
||||
'(%s) %s'
|
||||
на стандартные?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "Активный список будет заполняться снизу вверх"
|
||||
L["OPT_SCANLENGTH_DESC"] = "Установите промежуток времени между сканированием"
|
||||
L["OPT_SHOWBORDER"] = "Показать края по цвету класса"
|
||||
L["OPT_SHOWBORDER_DESC"] = "Края МФИ будут отображаться в соответствии с предназначенным для класса цветом"
|
||||
L["OPT_SHOWCHRONO"] = "Показать хронометры"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "Отображение в секундах количества времени, прошедшего с момента заражения игрока"
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "Осталось"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "Отображать оставшееся время вместо прошедшего времени."
|
||||
L["OPT_SHOWHELP"] = "Вызов справки"
|
||||
L["OPT_SHOWHELP_DESC"] = "Отображать детализированные подсказки при наведении курсора мыши на микро-фреймы игроков"
|
||||
L["OPT_SHOWMFS"] = "Показать микро-фреймы игроков"
|
||||
L["OPT_SHOWMFS_DESC"] = "Эта опция должна быть отмечена, если вы хотите лечить с помощью кликов"
|
||||
L["OPT_SHOWMINIMAPICON"] = "Иконка у миникарты"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "Показать/скрыть иконку и миникарты."
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "Показать статус скрытности"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "Когда игрок использует скрытность, его МЮФ будет окрашен в особый цвет"
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "Показывать детализированные подсказки о заражениях в активном списке и МФИ"
|
||||
L["OPT_STICKTORIGHT"] = "Выравнять МФИ вправо"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "МФИ будет расти справа налево, якорь будет перемещён по мере необходимости."
|
||||
L["OPT_TESTLAYOUT"] = "Тест отображения"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[Создать вымышленные единицы для тестирования отображения.
|
||||
(Необходимо подождать пару секунд после нажатия)]=] -- Needs review
|
||||
L["OPT_TESTLAYOUTUNUM"] = "Количество игроков" -- Needs review
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "Укажите количество создаваемых вымышленных игроков" -- Needs review
|
||||
L["OPT_TIECENTERANDBORDER"] = "Объединить прозрачность центра и краёв"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "Если отмечено, то прозрачность краёв будет соответствовать прозрачности центра"
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "Отображение активного списка связано с отображением панели \"Decursive\" "
|
||||
L["OPT_TIEXYSPACING"] = "Объединить гориз. и вертик. расстояние"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "Если отмечено, то горизонтальное и вертикальное расстояния между МФИ будут равны"
|
||||
L["OPT_UNITPERLINES"] = "Игроков в линии"
|
||||
L["OPT_UNITPERLINES_DESC"] = "Установить максимальное число игроков, отображаемых на одной строке микрофреймов"
|
||||
L["OPT_USERDEBUFF"] = "Данный недуг не является стандартным недугом Decursive"
|
||||
L["OPT_XSPACING"] = "Расстояние по горизонтали"
|
||||
L["OPT_XSPACING_DESC"] = "Установка расстояния по горизонтали между МФИ"
|
||||
L["OPT_YSPACING"] = "Расстояние по вертикали"
|
||||
L["OPT_YSPACING_DESC"] = "Установка расстояния по вертикали между МФИ"
|
||||
L["PLAY_SOUND"] = "Проиграть звук, если есть кого лечить"
|
||||
L["POISON"] = "Яды"
|
||||
L["POPULATE"] = "зп"
|
||||
L["POPULATE_LIST"] = "Быстро заполнить список Decursive"
|
||||
L["PRINT_CHATFRAME"] = "Выводить сообщения в стандартный чат"
|
||||
L["PRINT_CUSTOM"] = "Выводить сообщения в окно"
|
||||
L["PRINT_ERRORS"] = "Выводить сообщения об ошибках"
|
||||
L["PRIORITY_LIST"] = "Список приоритетов"
|
||||
L["PRIORITY_SHOW"] = "ПР"
|
||||
L["RANDOM_ORDER"] = "Лечить в случайном порядке"
|
||||
L["REVERSE_LIVELIST"] = "Перевернуть отображение активного списка"
|
||||
L["SCAN_LENGTH"] = "Секунд между активными скан.: "
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "Для отображения фрейма Decursive введите /dcrshow"
|
||||
L["SHOW_TOOLTIP"] = "Отображать всплывающие подсказки к зараженным игрокам"
|
||||
L["SKIP_LIST_STR"] = "Список пропусков"
|
||||
L["SKIP_SHOW"] = "П"
|
||||
L["SPELL_FOUND"] = "Заклинание %s найдено!"
|
||||
L["STEALTHED"] = "Скрывается"
|
||||
L["STR_CLOSE"] = "Закрыть"
|
||||
L["STR_DCR_PRIO"] = "Приоритеты Decursive"
|
||||
L["STR_DCR_SKIP"] = "Пропуски Decursive"
|
||||
L["STR_GROUP"] = "Группа "
|
||||
L["STR_OPTIONS"] = "Настройки Decursive"
|
||||
L["STR_OTHER"] = "Другое"
|
||||
L["STR_POP"] = "Список заполнений"
|
||||
L["STR_QUICK_POP"] = "Быстрое заполнение"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r |cFF00AA00успешно на|r %s"
|
||||
L["TARGETUNIT"] = "Цель"
|
||||
L["TIE_LIVELIST"] = "Привязка обзора активного списка к окну DCR"
|
||||
L["TOOFAR"] = "Слишком далеко"
|
||||
L["UNITSTATUS"] = "Состояние: "
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["ruRU.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,384 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Simplified Chinese localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "zhCN");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["zhCN.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
L["ABOLISH_CHECK"] = "在施法前检测是否需要净化"
|
||||
L["ABOUT_AUTHOREMAIL"] = "作者 E-Mail"
|
||||
L["ABOUT_CREDITS"] = "贡献者"
|
||||
L["ABOUT_LICENSE"] = "许可"
|
||||
L["ABOUT_NOTES"] = "当单独、小队和团队时清除有害状态,并可使用高级过滤和优先等级系统。"
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "官方网站"
|
||||
L["ABOUT_SHAREDLIBS"] = "共享库"
|
||||
L["ABSENT"] = "不存在 (%s)"
|
||||
L["AFFLICTEDBY"] = "受%s影响"
|
||||
L["ALT"] = "Alt"
|
||||
L["AMOUNT_AFFLIC"] = "实时列表显示人数:"
|
||||
L["ANCHOR"] = "Decursive 文字定位点"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "显示或隐藏微单元面板(MUF)"
|
||||
L["BINDING_NAME_DCRPRADD"] = "将目标加入优先列表"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "清空优先列表"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "显示优先列表明细条目"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "显示/隐藏 优先列表"
|
||||
L["BINDING_NAME_DCRSHOW"] = "显示或隐藏一键驱散状态条"
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "显示选项设置窗口"
|
||||
L["BINDING_NAME_DCRSKADD"] = "将目标加入忽略列表"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "清空忽略列表"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "显示忽略列表明细条目"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "显示/隐藏 忽略列表"
|
||||
L["BLACK_LENGTH"] = "黑名单持续时间: "
|
||||
L["BLACKLISTED"] = "黑名单"
|
||||
L["CHARM"] = "魅惑"
|
||||
L["CLASS_HUNTER"] = "猎人"
|
||||
L["CLEAR_PRIO"] = "C"
|
||||
L["CLEAR_SKIP"] = "C"
|
||||
L["COLORALERT"] = "预警颜色"
|
||||
L["COLORCHRONOS"] = "秒表"
|
||||
L["COLORCHRONOS_DESC"] = "设置秒表颜色"
|
||||
L["COLORSTATUS"] = "设定当玩家状态是'%s'时微单元面板(MUF)的颜色"
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "检测并净化宠物"
|
||||
L["CURSE"] = "诅咒"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33请报告此窗口的内容给 Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(使用 CTRL+A 选择所有 CTRL+C 复制文本到剪切板)|r
|
||||
如果发现 Decursive 任何奇怪的行为也一并报告。]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Decursive 除错报告|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[一个除错报告可用!输入
|
||||
|cFFFF0000/dcr general report|r 查看]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "除错报告可用!"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "显示作者需要看到的除错报告…"
|
||||
L["DEFAULT_MACROKEY"] = "`"
|
||||
L["DEV_VERSION_ALERT"] = [=[您正在使用的是开发版本的 Decursive 。
|
||||
|
||||
如果不想参加测试新功能与修复,得到游戏中的除错报告后发送问题给作者,请“不要使用此版本”并从 curse.com 和 wowace.com 下载最新的“稳定”版本。
|
||||
|
||||
这条消息只将在版本更新中显示一次
|
||||
|
||||
使用开发版本 Decursive 的玩家开始游戏显示此提示。]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[此开发版 Decursive 已过期。
|
||||
请从 CURSE.COM 或 WOWACE.COM 下载最新的开发版或使用当前稳定版。谢谢! ^_^
|
||||
此提示每两天显示一次。
|
||||
|
||||
说明:当用户使用过期的开发版 Decursive 登录时每次显示。]=]
|
||||
L["DEWDROPISGONE"] = "没有等同于 Ace3 的 DewDrop。Alt+右键点击打开选项面板。"
|
||||
L["DISABLEWARNING"] = [=[Decursive 已被禁用!
|
||||
|
||||
要重新启用,输入 |cFFFFAA44/DCR ENABLE|r]=]
|
||||
L["DISEASE"] = "疾病"
|
||||
L["DONOT_BL_PRIO"] = "不将优先列表中的玩家加入黑名单"
|
||||
L["FAILEDCAST"] = [=[|cFF22FFFF%s %s|r |cFFAA0000未能施放于|r %s
|
||||
|cFF00AAAA%s|r]=]
|
||||
L["FOCUSUNIT"] = "焦点单位"
|
||||
L["FUBARMENU"] = "FuBar 选项"
|
||||
L["FUBARMENU_DESC"] = "FuBar 的相关设定"
|
||||
L["GLOR1"] = "纪念 Glorfindal"
|
||||
L["GLOR2"] = "献给匆匆离我们而去的 Bertrand;他将永远被我们所铭记。"
|
||||
L["GLOR3"] = "纪念 Bertrand(1969-2007)"
|
||||
L["GLOR4"] = "对于那些在魔兽世界里遇见过 Glorfindal 的人来说,他是一个重承诺的男人,也是一个有超凡魅力的领袖。友谊和慈爱将永植于他们的心中。他在游戏中就如同在他生活中一样的无私,彬彬有礼,乐于奉献,最重要的是他对生活充满热情。他离开我们的时候才仅仅38岁,随他离去的绝不会是虚拟世界匿名的角色;在这里还有一群忠实的朋友在永远想念他。"
|
||||
L["GLOR5"] = "他将永远被我们所铭记。"
|
||||
L["HANDLEHELP"] = "拖拽移动 MUF"
|
||||
L["HIDE_LIVELIST"] = "隐藏实时列表"
|
||||
L["HIDE_MAIN"] = "隐藏状态条"
|
||||
L["HIDESHOW_BUTTONS"] = "显示/隐藏按钮"
|
||||
L["HLP_LEFTCLICK"] = "鼠标左键"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = "由于暴雪禁用函数的缘故,点击实时列表已经不能驱散负面效果了"
|
||||
L["HLP_MIDDLECLICK"] = "鼠标中键"
|
||||
L["HLP_NOTHINGTOCURE"] = "没有可处理的负面效果!"
|
||||
L["HLP_RIGHTCLICK"] = "鼠标右键"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "用 \"%s\" 來净化这个负面效果!"
|
||||
L["HLP_WRONGMBUTTON"] = "错误的鼠标按键!"
|
||||
L["IGNORE_STEALTH"] = "忽略潜行的玩家"
|
||||
L["IS_HERE_MSG"] = "一键驱散已经启动,请核对相关设置。"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r+单击:删除
|
||||
|cFF33AA33左键|r单击:上移
|
||||
|cFF33AA33右键|r单击:下移
|
||||
|cFF33AA33[SHIFT]+左键|r单击:移到顶端
|
||||
|cFF33AA33[SHIFT]+右键|r单击:移到底端]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[警告: 一键驱散的宏绑定按键 [%s] 先前绑定到 '%s' 。
|
||||
当你设置別的宏按键后一键驱散会恢复此按键原有的动作。]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "按键 [%s] 不能绑定到一键驱散的宏!"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "按键 [%s] 已成功绑定到一键驱散的宏。"
|
||||
L["MACROKEYNOTMAPPED"] = "未绑定一键驱散的宏按键,你可以通过设置选项来设置该功能。"
|
||||
L["MAGIC"] = "魔法"
|
||||
L["MAGICCHARMED"] = "魔法魅惑"
|
||||
L["MISSINGUNIT"] = "丢失单位"
|
||||
L["NORMAL"] = "一般"
|
||||
L["NOSPELL"] = "没有相关技能"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "设置是否显示和净化带有“驱毒术”增益效果的玩家。"
|
||||
L["OPT_ABOUT"] = "关于"
|
||||
L["OPT_ADDDEBUFF"] = "新增"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "向列表中新增一个负面效果。"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "新增一个最近受到的负面效果"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "从历史记录中新增一个负面效果"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<负面效果名称>"
|
||||
L["OPT_ADVDISP"] = "高级显示选项"
|
||||
L["OPT_ADVDISP_DESC"] = "允许分别设置面板和边框的透明度,以及 MUF 的间距。"
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s受到%s的影响,但将被忽略。"
|
||||
L["OPT_ALWAYSIGNORE"] = "不在战斗状态时也忽略"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "选中后不在状态时此负面效果也会被忽略。"
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "设置实时列表显示的最大玩家数目。"
|
||||
L["OPT_ANCHOR_DESC"] = "设置自定义信息面板的定位点。"
|
||||
L["OPT_AUTOHIDEMFS"] = "自动隐藏"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "选择何时自动隐藏微单元面板(MUF)"
|
||||
L["OPT_BLACKLENTGH_DESC"] = "设置被暂时加入黑名单的玩家在名单中停留的时间。"
|
||||
L["OPT_BORDERTRANSP"] = "边框透明度"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "设置边框的透明度。"
|
||||
L["OPT_CENTERTRANSP"] = "面板透明度"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "设置面板的透明度"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "选中后你将可以查看和处理被诱惑的玩家。"
|
||||
L["OPT_CHATFRAME_DESC"] = "提示信息将显示在默认聊天窗口中。"
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "检查其他玩家"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "显示当前小队或团队玩家 Decursive 版本(不能显示 Decursive 2.4.6之前的版本)。"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "创建一个虚拟的测试用负面效果"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "让你看看出现负面效果时的界面是什么样子"
|
||||
L["OPT_CUREPETS_DESC"] = "宠物也会被检查和净化。"
|
||||
L["OPT_CURINGOPTIONS"] = "净化选项"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "关于净化过程的选项设置。"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
选择你想要治疗的伤害类型,未经检查的类型将被 Decursive 完全忽略。
|
||||
|
||||
绿色数字确定优先的伤害。这一优先事项将影响几方面:
|
||||
- 如果一个玩家获得许多类型的减益效果,Decursive 将优先显示。
|
||||
- 鼠标按钮点击将治疗减益(第一法术是左键点击,第二法术是右键点击,等等…)
|
||||
|
||||
所有这一切的说明文档(请见):
|
||||
http://www.wowace.com/addons/decursive/]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "净化顺序设置"
|
||||
L["OPT_CURSECHECK_DESC"] = "选中后你将可以查看和净化受到诅咒效果影响的玩家。"
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
|
||||
默认被选中
|
||||
|
||||
]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "选择在战斗中哪些受到此负面效果影响的职业将被忽略。"
|
||||
L["OPT_DEBUFFFILTER"] = "负面效果过滤"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "根据名称和职业选择在战斗中要过滤掉的负面效果"
|
||||
L["OPT_DISABLEMACROCREATION"] = "禁止创建宏"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Decursive 宏将不再创建和保留"
|
||||
L["OPT_DISEASECHECK_DESC"] = "选中后你将可以查看和净化受到疾病效果影响的玩家。"
|
||||
L["OPT_DISPLAYOPTIONS"] = "显示选项"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "优先列表中的玩家不会被加入黑名单。"
|
||||
L["OPT_ENABLEDEBUG"] = "启用除错"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "启用除错输出"
|
||||
L["OPT_ENABLEDECURSIVE"] = "启用 Decursive"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "在战斗中指定的职业%q将被忽略。"
|
||||
L["OPT_GENERAL"] = "一般选项"
|
||||
L["OPT_GROWDIRECTION"] = "反向显示 MUF"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "MUF 将从下向上显示。"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "显示所有受到负面效果影响的玩家列表。"
|
||||
L["OPT_HIDEMFS_GROUP"] = "单人/小队"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "不在团队中时隐藏微单元面板(MUF)"
|
||||
L["OPT_HIDEMFS_NEVER"] = "从不"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "从不隐藏"
|
||||
L["OPT_HIDEMFS_SOLO"] = "单人"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "在没有组队或者团队时隐藏微单元面板(MUF)"
|
||||
L["OPT_HIDEMUFSHANDLE"] = "隐藏 MUF 表头"
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = "隐藏微单元面板(MUF)表头并禁止移动。"
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "处于潜行状态的玩家会被忽略。"
|
||||
L["OPTION_MENU"] = "选项设置"
|
||||
L["OPT_LIVELIST"] = "实时列表"
|
||||
L["OPT_LIVELIST_DESC"] = "关于实时列表的选项设置。"
|
||||
L["OPT_LLALPHA"] = "实时列表透明度"
|
||||
L["OPT_LLALPHA_DESC"] = "改变一键驱散状态条面和实时列表的透明度(状态条必须可见)"
|
||||
L["OPT_LLSCALE"] = "设置实时列表缩放比例"
|
||||
L["OPT_LLSCALE_DESC"] = "设置状态条以及其实时列表的大小(状态条必须显示)"
|
||||
L["OPT_LVONLYINRANGE"] = "只显示法术有效范围内的目标"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "实时列表将只显示法术有效范围内的目标,超出范围的目标将被忽略。"
|
||||
L["OPT_MACROBIND"] = "设置宏按键"
|
||||
L["OPT_MACROBIND_DESC"] = [=[绑定一键驱散宏的按键。
|
||||
|
||||
按你想設定的按键后按 'Enter' 键保存设置(鼠标需要移动到编辑区域之外)]=]
|
||||
L["OPT_MACROOPTIONS"] = "宏选项"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "有关 Decursive 创建的宏的选项设置"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "选中后你将可以查看和净化受到魔法诱惑效果影响的玩家。"
|
||||
L["OPT_MAGICCHECK_DESC"] = "选中后你将可以查看和净化受到不良魔法效果影响的玩家。"
|
||||
L["OPT_MAXMFS"] = "最大单位数"
|
||||
L["OPT_MAXMFS_DESC"] = "设置在屏幕上显示的MUF的个数。"
|
||||
L["OPT_MESSAGES"] = "信息设置"
|
||||
L["OPT_MESSAGES_DESC"] = "关于提示信息的选项设置。"
|
||||
L["OPT_MFALPHA"] = "透明度"
|
||||
L["OPT_MFALPHA_DESC"] = "定义玩家没有受到负面效果影响时MUF的透明度。"
|
||||
L["OPT_MFPERFOPT"] = "性能选项"
|
||||
L["OPT_MFREFRESHRATE"] = "刷新率"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "每两次刷新之间的时间间隔"
|
||||
L["OPT_MFREFRESHSPEED"] = "刷新速度"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "设置每次刷新多少个MUF。"
|
||||
L["OPT_MFSCALE"] = "MUF 缩放比例"
|
||||
L["OPT_MFSCALE_DESC"] = "设置微单元面板(MUF)的大小。"
|
||||
L["OPT_MFSETTINGS"] = "微单元面板(MUF)选项"
|
||||
L["OPT_MFSETTINGS_DESC"] = "关于微单元面板(MUF)的选项设置。"
|
||||
L["OPT_MUFFOCUSBUTTON"] = "焦点按钮:"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "鼠标按钮"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "设置每个 MUF 鼠标按钮的警报颜色。"
|
||||
L["OPT_MUFSCOLORS"] = "颜色"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "更改关于微单元面板(MUF)的颜色"
|
||||
L["OPT_MUFTARGETBUTTON"] = "目标按钮:"
|
||||
L["OPT_NOKEYWARN"] = "没有映射按键"
|
||||
L["OPT_NOKEYWARN_DESC"] = "没有映射按键"
|
||||
L["OPT_NOSTARTMESSAGES"] = "禁用欢迎信息"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "移除每次登陆时在聊天框体显示的三个 Decursive 信息。"
|
||||
L["OPT_PLAYSOUND_DESC"] = "有玩家受到负面效果影响时播放声音提示。"
|
||||
L["OPT_POISONCHECK_DESC"] = "选中后你将可以查看和净化受到中毒效果影响的玩家。"
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "提示信息将显示在自定义聊天窗口中。"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "错误信息将被显示。"
|
||||
L["OPT_PROFILERESET"] = "正在重置选项设置方案……"
|
||||
L["OPT_RANDOMORDER_DESC"] = "随机净化玩家(不推荐使用)。"
|
||||
L["OPT_READDDEFAULTSD"] = "重新加入缺省负面效果"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[向列表中加入所有缺失的默认负面效果。
|
||||
你的自定义项目不会丢失]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "所有缺省负面效果都已加入列表。"
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[你确定要将“%s”
|
||||
从不良状态忽略列表中删除吗?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "删除"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "从忽略列表中删除“%s”。"
|
||||
L["OPT_RESETDEBUFF"] = "重置"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = [=[将
|
||||
%s
|
||||
恢复默认值。]=]
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "重置"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "重置鼠标按钮指派为默认。"
|
||||
L["OPT_RESETOPTIONS"] = "恢复默认设置"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "将当前选项设置方案恢复到默认值"
|
||||
L["OPT_RESTPROFILECONF"] = "你确定要将选项设置方案“(%s) %s”恢复默认值吗?"
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "实时列表将从下往上显示。"
|
||||
L["OPT_SCANLENGTH_DESC"] = "设置实时检测的时间间隔。"
|
||||
L["OPT_SHOWBORDER"] = "显示职业彩色边框"
|
||||
L["OPT_SHOWBORDER_DESC"] = "MUF 边框将会显示出代表该玩家职业的颜色。"
|
||||
L["OPT_SHOWCHRONO"] = "显示计时"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "显示单位受到不良效果的时间"
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "剩余时间"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "显示剩余时间而不是消耗时间。"
|
||||
L["OPT_SHOWHELP"] = "显示帮助信息"
|
||||
L["OPT_SHOWHELP_DESC"] = "当鼠标移动到 MUF 上时显示信息提示窗口。"
|
||||
L["OPT_SHOWMFS"] = "在屏幕上显示 MUF"
|
||||
L["OPT_SHOWMFS_DESC"] = "如果你要打地鼠就必須选择这项。"
|
||||
L["OPT_SHOWMINIMAPICON"] = "迷你地图图标"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "开启或关闭迷你地图图标。"
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "显示潜行状态"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = "当玩家前行时,他的 MUF 将有一个特殊的颜色"
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "在实时列表以及微单元面板(MUF)上显示信息提示。"
|
||||
L["OPT_STICKTORIGHT"] = "将微单元面板(MUF)向右对齐"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "这个选项将会使微单元面板(MUF)向右对齐"
|
||||
L["OPT_TESTLAYOUT"] = "测试布局"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[新建测试单位以测试显示布局。
|
||||
(点击后稍等片刻)]=]
|
||||
L["OPT_TESTLAYOUTUNUM"] = "单位数字"
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "设置新建测试单位数字。"
|
||||
L["OPT_TIECENTERANDBORDER"] = "绑定面板和边框的透明度"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "选中时边框的透明度为面板的一半。"
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "实时列表将和状态条一起 显示/隐藏。"
|
||||
L["OPT_TIEXYSPACING"] = "绑定水平和垂直间距。"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "MUF 之间的水平和垂直间距相同。"
|
||||
L["OPT_UNITPERLINES"] = "每行单位数"
|
||||
L["OPT_UNITPERLINES_DESC"] = "设置每行最多可显示单元面板(MUF)的个数。"
|
||||
L["OPT_USERDEBUFF"] = "该负面效果不是<一键驱散>预设的效果之一"
|
||||
L["OPT_XSPACING"] = "水平距离"
|
||||
L["OPT_XSPACING_DESC"] = "设置 MUF 间的水平距离。"
|
||||
L["OPT_YSPACING"] = "垂直距离"
|
||||
L["OPT_YSPACING_DESC"] = "设置 MUF 间的垂直距离。"
|
||||
L["PLAY_SOUND"] = "有玩家需要净化时播放声音提示"
|
||||
L["POISON"] = "中毒"
|
||||
L["POPULATE"] = "p"
|
||||
L["POPULATE_LIST"] = "列表快速添加器"
|
||||
L["PRINT_CHATFRAME"] = "在聊天窗口显示信息"
|
||||
L["PRINT_CUSTOM"] = "在游戏画面显示信息"
|
||||
L["PRINT_ERRORS"] = "显示错误信息"
|
||||
L["PRIORITY_LIST"] = "设置 优先列表"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "随机净化玩家"
|
||||
L["REVERSE_LIVELIST"] = "反向显示实时列表"
|
||||
L["SCAN_LENGTH"] = "实时检测时间间隔(秒):"
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "如果需要显示状态条,请输入 /dcrshow。"
|
||||
L["SHOW_TOOLTIP"] = "在实时列表中显示信息提示"
|
||||
L["SKIP_LIST_STR"] = "Decursive 忽略列表"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "找到%s法术!"
|
||||
L["STEALTHED"] = "已潜行"
|
||||
L["STR_CLOSE"] = "关闭"
|
||||
L["STR_DCR_PRIO"] = "Decursive 优先"
|
||||
L["STR_DCR_SKIP"] = "Decursive 忽略"
|
||||
L["STR_GROUP"] = "小队"
|
||||
L["STR_OPTIONS"] = "Decursive 选项"
|
||||
L["STR_OTHER"] = "其他"
|
||||
L["STR_POP"] = "快速添加列表"
|
||||
L["STR_QUICK_POP"] = "快速添加器"
|
||||
L["SUCCESSCAST"] = "%s %s|cFF00AA00成功施放于|r|cFF22FFFF %s|r。"
|
||||
L["TARGETUNIT"] = "设为目标"
|
||||
L["TIE_LIVELIST"] = "根据状态条是否可见 显示/隐藏 实时列表"
|
||||
L["TOOFAR"] = "太远"
|
||||
L["UNITSTATUS"] = "玩家状态:"
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["zhCN.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,382 @@
|
||||
--[[
|
||||
This file is part of Decursive.
|
||||
|
||||
Decursive (v 2.5.1-6-gd3885c5) add-on for World of Warcraft UI
|
||||
Copyright (C) 2006-2007-2008-2009 John Wellesz (archarodim AT teaser.fr) ( http://www.2072productions.com/?to=decursive.php )
|
||||
|
||||
This is the continued work of the original Decursive (v1.9.4) by Quu
|
||||
"Decursive 1.9.4" is in public domain ( www.quutar.com )
|
||||
|
||||
Decursive is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Decursive is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Decursive. If not, see <http://www.gnu.org/licenses/>.
|
||||
--]]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Traditional Chinese localization
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
--[=[
|
||||
-- YOUR ATTENTION PLEASE
|
||||
--
|
||||
-- !!!!!!! TRANSLATORS TRANSLATORS TRANSLATORS !!!!!!!
|
||||
--
|
||||
-- Thank you very much for your interest in translating Decursive.
|
||||
-- Do not edit those files. Use the localization interface available at the following address:
|
||||
--
|
||||
-- ################################################################
|
||||
-- # http://wow.curseforge.com/projects/decursive/localization/ #
|
||||
-- ################################################################
|
||||
--
|
||||
-- Your translations made using this interface will be automatically included in the next release.
|
||||
--
|
||||
--]=]
|
||||
|
||||
local addonName, T = ...;
|
||||
-- big ugly scary fatal error message display function {{{
|
||||
if not T._FatalError then
|
||||
-- the beautiful error popup : {{{ -
|
||||
StaticPopupDialogs["DECURSIVE_ERROR_FRAME"] = {
|
||||
text = "|cFFFF0000Decursive Error:|r\n%s",
|
||||
button1 = "OK",
|
||||
OnAccept = function()
|
||||
return false;
|
||||
end,
|
||||
timeout = 0,
|
||||
whileDead = 1,
|
||||
hideOnEscape = 1,
|
||||
showAlert = 1,
|
||||
}; -- }}}
|
||||
T._FatalError = function (TheError) StaticPopup_Show ("DECURSIVE_ERROR_FRAME", TheError); end
|
||||
end
|
||||
-- }}}
|
||||
if not T._LoadedFiles or not T._LoadedFiles["enUS.lua"] then
|
||||
if not DecursiveInstallCorrupted then T._FatalError("Decursive installation is corrupted! (enUS.lua not loaded)"); end;
|
||||
DecursiveInstallCorrupted = true;
|
||||
return;
|
||||
end
|
||||
|
||||
local L = LibStub("AceLocale-3.0"):NewLocale("Decursive", "zhTW");
|
||||
|
||||
if not L then
|
||||
T._LoadedFiles["zhTW.lua"] = "2.5.1-6-gd3885c5";
|
||||
return;
|
||||
end;
|
||||
|
||||
L["ABOLISH_CHECK"] = "施法前檢查是否需要淨化"
|
||||
L["ABOUT_AUTHOREMAIL"] = "作者 E-Mail"
|
||||
L["ABOUT_CREDITS"] = "貢獻者"
|
||||
L["ABOUT_LICENSE"] = "許可"
|
||||
L["ABOUT_NOTES"] = "當單獨、小隊和團隊時清除有害狀態,並可使用高級過濾和優先等級系統。"
|
||||
L["ABOUT_OFFICIALWEBSITE"] = "官方網站"
|
||||
L["ABOUT_SHAREDLIBS"] = "共享庫"
|
||||
L["ABSENT"] = "不存在 (%s)"
|
||||
L["AFFLICTEDBY"] = "受 %s 影響"
|
||||
L["ALT"] = "ALt"
|
||||
L["AMOUNT_AFFLIC"] = "即時清單顯示人數: "
|
||||
L["ANCHOR"] = "Decursive 文字定位點"
|
||||
L["BINDING_NAME_DCRMUFSHOWHIDE"] = "顯示或隱藏 MUF"
|
||||
L["BINDING_NAME_DCRPRADD"] = "添加目標至優先名單"
|
||||
L["BINDING_NAME_DCRPRCLEAR"] = "清空優先名單"
|
||||
L["BINDING_NAME_DCRPRLIST"] = "顯示優先名單至聊天視窗"
|
||||
L["BINDING_NAME_DCRPRSHOW"] = "開/關優先名單"
|
||||
L["BINDING_NAME_DCRSHOW"] = "顯示或隱藏 Decursive 工作條"
|
||||
L["BINDING_NAME_DCRSHOWOPTION"] = "顯示靜態設定選單"
|
||||
L["BINDING_NAME_DCRSKADD"] = "添加目標至忽略名單"
|
||||
L["BINDING_NAME_DCRSKCLEAR"] = "清空忽略名單"
|
||||
L["BINDING_NAME_DCRSKLIST"] = "顯示忽略名單至聊天視窗"
|
||||
L["BINDING_NAME_DCRSKSHOW"] = "開/關忽略名單"
|
||||
L["BLACK_LENGTH"] = "停留在排除名單的時間: "
|
||||
L["BLACKLISTED"] = "在排除名單"
|
||||
L["CHARM"] = "魅惑"
|
||||
L["CLASS_HUNTER"] = "獵人"
|
||||
L["CLEAR_PRIO"] = "C"
|
||||
L["CLEAR_SKIP"] = "C"
|
||||
L["COLORALERT"] = "設定按鍵警示'%s'的顏色"
|
||||
L["COLORCHRONOS"] = "秒錶"
|
||||
L["COLORCHRONOS_DESC"] = "設定秒錶顏色"
|
||||
L["COLORSTATUS"] = "設定當玩家狀態是 '%s' 時的 MUF 顏色."
|
||||
L["CTRL"] = "Ctrl"
|
||||
L["CURE_PETS"] = "檢測並淨化寵物"
|
||||
L["CURSE"] = "詛咒"
|
||||
L["DEBUG_REPORT_HEADER"] = [=[|cFF11FF33請報告此視窗的內容給 Archarodim+DcrReport@teaser.fr|r
|
||||
|cFF009999(使用 CTRL+A 選擇所有 CTRL+C 復制文本到剪切板)|r
|
||||
如果發現 Decursive 任何奇怪的行為也一并報告。]=]
|
||||
L["DECURSIVE_DEBUG_REPORT"] = "**** |cFFFF0000Decursive 除錯報告|r ****"
|
||||
L["DECURSIVE_DEBUG_REPORT_NOTIFY"] = [=[一個出錯報告可用!
|
||||
輸入 |cFFFF0000/dcr general report|r 查看]=]
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW"] = "除錯報告可用!"
|
||||
L["DECURSIVE_DEBUG_REPORT_SHOW_DESC"] = "顯示作者需要看到的除錯報告…"
|
||||
L["DEFAULT_MACROKEY"] = "NONE"
|
||||
L["DEV_VERSION_ALERT"] = [=[您正在使用的是開發版本的 Decursive 。
|
||||
|
||||
如果不想參加測試新功能與修復,得到遊戲中的除錯報告后發送問題給作者,請“不要使用此版本”並從 curse.com 和 wowace.com 下載最新的“穩定”版本。
|
||||
|
||||
這條消息只將在版本更新中顯示一次
|
||||
|
||||
使用開發版本 Decursive 的玩家開始遊戲顯示此提示。]=]
|
||||
L["DEV_VERSION_EXPIRED"] = [=[此開發版 Decursive 已過期。
|
||||
請從 CURSE.COM 和 WOWACE.COM 下載最新的開發版或使用當前穩定版。謝謝! ^_^
|
||||
此提示每兩天顯示一次。
|
||||
|
||||
說明:當用戶使用過期的開發版 Decursive 登錄時每次顯示。]=]
|
||||
L["DEWDROPISGONE"] = "沒有等同于 Ace3 的 DewDrop。Alt+點擊右鍵打開選項面板。"
|
||||
L["DISABLEWARNING"] = [=[Decursive 已停用!
|
||||
|
||||
如欲啟用, 輸入 |cFFFFAA44/DCR ENABLE|r]=]
|
||||
L["DISEASE"] = "疾病"
|
||||
L["DONOT_BL_PRIO"] = "不添加優先名單的玩家到排除名單"
|
||||
L["FAILEDCAST"] = "|cFF22FFFF%s %s|r |cFFAA0000對|r %s釋放失敗\\n|cFF00AAAA%s|r"
|
||||
L["FOCUSUNIT"] = "監控單位"
|
||||
L["FUBARMENU"] = "Fubar 選單"
|
||||
L["FUBARMENU_DESC"] = "Fubar 圖示相關設定"
|
||||
L["GLOR1"] = "紀念 Glorfindal"
|
||||
L["GLOR2"] = "獻給匆匆離我們而去的Bertrand;他將永遠被我們所銘記。"
|
||||
L["GLOR3"] = "紀念 Bertrand (1969~2007)"
|
||||
L["GLOR4"] = "對於那些在魔獸世界裡遇見過Glorfindal的人來說,他是一個重承諾的男人,也是一個有超凡魅力的領袖。友誼和慈愛將永植於他們的心中。他在遊戲中就如同在他生活中一樣的無私,彬彬有禮,樂於奉獻,最重要的是他對生活充滿熱情。他離開我們的時候才僅僅38歲,隨他離去的絕不會是虛擬世界匿名的角色;在這裡還有一群忠實的朋友在永遠想念他。"
|
||||
L["GLOR5"] = "他將永遠被我們所銘記。"
|
||||
L["HANDLEHELP"] = "拖曳移動所有的 Micro-UnitFrames (MUFs)"
|
||||
L["HIDE_LIVELIST"] = "隱藏即時清單"
|
||||
L["HIDE_MAIN"] = "隱藏 Decursive 視窗"
|
||||
L["HIDESHOW_BUTTONS"] = "顯示/隱藏按鈕"
|
||||
L["HLP_LEFTCLICK"] = "左-鍵"
|
||||
L["HLP_LL_ONCLICK_TEXT"] = "你不可以用點擊即時選單的方式解魔(因為相關的程式介面已經被封鎖),請用微縮圖像以打地鼠的方式解魔,如果你沒看見微縮圖像的話,請先檢察 Decursive 的設定。"
|
||||
L["HLP_MIDDLECLICK"] = "中-鍵"
|
||||
L["HLP_NOTHINGTOCURE"] = "沒有可處理的負面效果!"
|
||||
L["HLP_RIGHTCLICK"] = "右-鍵"
|
||||
L["HLP_USEXBUTTONTOCURE"] = "用 \"%s\" 來淨化這個負面效果!"
|
||||
L["HLP_WRONGMBUTTON"] = "錯誤的滑鼠按鍵!"
|
||||
L["IGNORE_STEALTH"] = "忽略潛行的玩家"
|
||||
L["IS_HERE_MSG"] = "Decursive 已經啟動,請核對設定選項。"
|
||||
L["LIST_ENTRY_ACTIONS"] = [=[|cFF33AA33[CTRL]|r-左鍵: 移除該玩家
|
||||
|cFF33AA33左|r-鍵: 提升該玩家順序
|
||||
|cFF33AA33右|r-鍵: 降低該玩家順序
|
||||
|cFF33AA33[SHIFT] 左|r-鍵: 將該玩家置頂
|
||||
|cFF33AA33[SHIFT] 右|r-鍵: 將該玩家置底]=]
|
||||
L["MACROKEYALREADYMAPPED"] = [=[警告: Decursive 巨集對應按鍵 [%s] 先前對應到 '%s' 動作。
|
||||
當你設定別的巨集按鍵後 Decursive 會回復此按鍵原有的對應動作。]=]
|
||||
L["MACROKEYMAPPINGFAILED"] = "按鍵 [%s] 不能被對應到 Decursive 巨集!"
|
||||
L["MACROKEYMAPPINGSUCCESS"] = "按鍵 [%s] 已成功對應到 Decursive 巨集。"
|
||||
L["MACROKEYNOTMAPPED"] = "Decursive 巨集未對應到一個按鍵,你可以透過設定選單來設定此一按鍵。(別錯過這個神奇的功能)"
|
||||
L["MAGIC"] = "魔法"
|
||||
L["MAGICCHARMED"] = "魔法誘惑"
|
||||
L["MISSINGUNIT"] = "找不到的單位"
|
||||
L["NORMAL"] = "一般"
|
||||
L["NOSPELL"] = "沒有可用法術"
|
||||
L["OPT_ABOLISHCHECK_DESC"] = "檢查玩家身上是否有淨化法術在運作。"
|
||||
L["OPT_ABOUT"] = "關於"
|
||||
L["OPT_ADDDEBUFF"] = "添加一負面效果到清單中"
|
||||
L["OPT_ADDDEBUFF_DESC"] = "將一個新的負面效果新增到清單中。"
|
||||
L["OPT_ADDDEBUFFFHIST"] = "新增一個最近受到的負面效果"
|
||||
L["OPT_ADDDEBUFFFHIST_DESC"] = "從歷史紀錄中新增一個負面效果"
|
||||
L["OPT_ADDDEBUFF_USAGE"] = "<Debuff name>"
|
||||
L["OPT_ADVDISP"] = "進階顯示選項"
|
||||
L["OPT_ADVDISP_DESC"] = "可設定邊框與中央色塊各自的透明度,以及 MUFs 之間的距離。"
|
||||
L["OPT_AFFLICTEDBYSKIPPED"] = "%s 受到 %s 的影響,但將被忽略。"
|
||||
L["OPT_ALWAYSIGNORE"] = "即使不在戰鬥中也忽略之"
|
||||
L["OPT_ALWAYSIGNORE_DESC"] = "如果選取該選項,即使脫離戰鬥也忽略該負面效果而不解除"
|
||||
L["OPT_AMOUNT_AFFLIC_DESC"] = "設定即時清單最多顯示幾人。"
|
||||
L["OPT_ANCHOR_DESC"] = "顯示自訂視窗的文字定位點。"
|
||||
L["OPT_AUTOHIDEMFS"] = "自動隱藏"
|
||||
L["OPT_AUTOHIDEMFS_DESC"] = "選擇什麼時候隱藏 MUF 視窗"
|
||||
L["OPT_BLACKLENTGH_DESC"] = "設定一個人停留在排除名單中的時間。"
|
||||
L["OPT_BORDERTRANSP"] = "邊框透明度"
|
||||
L["OPT_BORDERTRANSP_DESC"] = "設定邊框的透明度。"
|
||||
L["OPT_CENTERTRANSP"] = "中央透明度"
|
||||
L["OPT_CENTERTRANSP_DESC"] = "設定中間色塊的透明度"
|
||||
L["OPT_CHARMEDCHECK_DESC"] = "選取後你可以看見並處理被媚惑的玩家。"
|
||||
L["OPT_CHATFRAME_DESC"] = "顯示到預設的聊天視窗。"
|
||||
L["OPT_CHECKOTHERPLAYERS"] = "檢查其他玩家"
|
||||
L["OPT_CHECKOTHERPLAYERS_DESC"] = "顯示當前小隊或團隊玩家 Decursive 版本(不能顯示 Decursive 2.4.6之前的版本)。"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF"] = "建立虛擬負面效果測試"
|
||||
L["OPT_CREATE_VIRTUAL_DEBUFF_DESC"] = "讓你看到當負面效果發生時的情形"
|
||||
L["OPT_CUREPETS_DESC"] = "寵物會被顯示出來也可淨化。"
|
||||
L["OPT_CURINGOPTIONS"] = "淨化選項"
|
||||
L["OPT_CURINGOPTIONS_DESC"] = "設定淨化選項。"
|
||||
L["OPT_CURINGOPTIONS_EXPLANATION"] = [=[
|
||||
選擇你想要治療的傷害類型,未經檢查的類型將被 Decursive 完全忽略。
|
||||
|
||||
綠色數字確定優先的傷害。這一優先事項將影響幾方面:
|
||||
- 如果一個玩家獲得許多類型的減益效果,Decursive 將優先顯示。
|
||||
- 滑鼠按鈕點擊將治療減益(第一法術是左鍵點擊,第二法術是右鍵點擊,等等…)
|
||||
|
||||
所有這一切的說明文檔(請見):
|
||||
http://www.wowace.com/addons/decursive/]=]
|
||||
L["OPT_CURINGORDEROPTIONS"] = "淨化順序設定"
|
||||
L["OPT_CURSECHECK_DESC"] = "選取後你可以看見並解除被詛咒的玩家。"
|
||||
L["OPT_DEBCHECKEDBYDEF"] = [=[
|
||||
|
||||
Checked by default]=]
|
||||
L["OPT_DEBUFFENTRY_DESC"] = "選擇戰鬥中要忽略受到此負面效果影響的職業。"
|
||||
L["OPT_DEBUFFFILTER"] = "負面效果過濾設定"
|
||||
L["OPT_DEBUFFFILTER_DESC"] = "設定戰鬥中要忽略的職業與負面效果"
|
||||
L["OPT_DISABLEMACROCREATION"] = "禁止創建巨集"
|
||||
L["OPT_DISABLEMACROCREATION_DESC"] = "Decursive 巨集將不再創建和保留"
|
||||
L["OPT_DISEASECHECK_DESC"] = "選取後你可以看見並治療生病的玩家。"
|
||||
L["OPT_DISPLAYOPTIONS"] = "顯示設定"
|
||||
L["OPT_DONOTBLPRIO_DESC"] = "設定到優先清單的玩家不會被移入排除清單中。"
|
||||
L["OPT_ENABLEDEBUG"] = "啟用除錯"
|
||||
L["OPT_ENABLEDEBUG_DESC"] = "啟用除錯輸出"
|
||||
L["OPT_ENABLEDECURSIVE"] = "啟用 Decursive"
|
||||
L["OPT_FILTEROUTCLASSES_FOR_X"] = "在戰鬥中指定的職業%q將被忽略。"
|
||||
L["OPT_GENERAL"] = "一般選項"
|
||||
L["OPT_GROWDIRECTION"] = "反向顯示 MUFs"
|
||||
L["OPT_GROWDIRECTION_DESC"] = "MUFs 會從尾巴開始顯示。"
|
||||
L["OPT_HIDELIVELIST_DESC"] = "如果未被隱藏則顯示清單,列出中了負面效果的人。"
|
||||
L["OPT_HIDEMFS_GROUP"] = "單獨 / 小隊"
|
||||
L["OPT_HIDEMFS_GROUP_DESC"] = "當不在團隊中的時候隱藏 MUF 視窗"
|
||||
L["OPT_HIDEMFS_NEVER"] = "從不"
|
||||
L["OPT_HIDEMFS_NEVER_DESC"] = "從不自動隱藏 MUF 視窗"
|
||||
L["OPT_HIDEMFS_SOLO"] = "單獨"
|
||||
L["OPT_HIDEMFS_SOLO_DESC"] = "當不在團隊中或隊伍中的時候隱藏 MUF 視窗"
|
||||
L["OPT_HIDEMUFSHANDLE"] = "隱藏 MUF 表頭"
|
||||
L["OPT_HIDEMUFSHANDLE_DESC"] = "隱藏微單元面板(MUF)表頭並禁止移動。"
|
||||
L["OPT_IGNORESTEALTHED_DESC"] = "忽略潛行的玩家。"
|
||||
L["OPTION_MENU"] = "Decursive 選項"
|
||||
L["OPT_LIVELIST"] = "即時清單"
|
||||
L["OPT_LIVELIST_DESC"] = "即時清單設定選項。"
|
||||
L["OPT_LLALPHA"] = "實況清單的透明度"
|
||||
L["OPT_LLALPHA_DESC"] = "變更 Decursive 工作條及實況清單的透明度(工作條必須設定為顯示)"
|
||||
L["OPT_LLSCALE"] = "縮放即時列表"
|
||||
L["OPT_LLSCALE_DESC"] = "設定 Decursive 狀態條以及其即時列表的大小(狀態條必須顯示)"
|
||||
L["OPT_LVONLYINRANGE"] = "只顯示法術有效範圍內的目標"
|
||||
L["OPT_LVONLYINRANGE_DESC"] = "即時清單只顯示淨化法術有效範圍內的目標。"
|
||||
L["OPT_MACROBIND"] = "設定巨集按鍵"
|
||||
L["OPT_MACROBIND_DESC"] = [=[定義呼叫 Decursive 巨集的按鍵。
|
||||
|
||||
按你想設定的按鍵然後按 'Enter' 鍵儲存設定(滑鼠要移動到編輯區域)]=]
|
||||
L["OPT_MACROOPTIONS"] = "巨集設定選項"
|
||||
L["OPT_MACROOPTIONS_DESC"] = "設定 Decursive 產生的巨集如何動作"
|
||||
L["OPT_MAGICCHARMEDCHECK_DESC"] = "選取後你可以看見並處理被魔法媚惑的玩家。"
|
||||
L["OPT_MAGICCHECK_DESC"] = "選取後你可以看見並處理受魔法影響的玩家。"
|
||||
L["OPT_MAXMFS"] = "最多顯示幾個"
|
||||
L["OPT_MAXMFS_DESC"] = "設定在螢幕上最多顯示幾個 micro unit frames。"
|
||||
L["OPT_MESSAGES"] = "訊息設定"
|
||||
L["OPT_MESSAGES_DESC"] = "設定訊息顯示。"
|
||||
L["OPT_MFALPHA"] = "透明度"
|
||||
L["OPT_MFALPHA_DESC"] = "設定無 debuff 時 MUFs 的透明度。"
|
||||
L["OPT_MFPERFOPT"] = "效能設定選項"
|
||||
L["OPT_MFREFRESHRATE"] = "刷新頻率"
|
||||
L["OPT_MFREFRESHRATE_DESC"] = "設定多久刷新一次(一次可刷新一個或數個 micro-unit-frames)。"
|
||||
L["OPT_MFREFRESHSPEED"] = "刷新速度"
|
||||
L["OPT_MFREFRESHSPEED_DESC"] = "設定每次刷新多少個 micro-unit-frames。"
|
||||
L["OPT_MFSCALE"] = "micro-unit-frames 大小"
|
||||
L["OPT_MFSCALE_DESC"] = "設定螢幕上 micro-unit-frames 的大小。"
|
||||
L["OPT_MFSETTINGS"] = "Micro Unit Frame 設定選項"
|
||||
L["OPT_MFSETTINGS_DESC"] = "設定 MUF 視窗以符合你的需求。"
|
||||
L["OPT_MUFFOCUSBUTTON"] = "監控按鈕:"
|
||||
L["OPT_MUFMOUSEBUTTONS"] = "滑鼠按鈕"
|
||||
L["OPT_MUFMOUSEBUTTONS_DESC"] = "設定每個 MUF 滑鼠按鈕的警報顏色。"
|
||||
L["OPT_MUFSCOLORS"] = "顏色"
|
||||
L["OPT_MUFSCOLORS_DESC"] = "變更 MUFs 的顏色"
|
||||
L["OPT_MUFTARGETBUTTON"] = "目標按鈕:"
|
||||
L["OPT_NOKEYWARN"] = "當沒有設定按鍵時警告"
|
||||
L["OPT_NOKEYWARN_DESC"] = "當巨集按鍵沒有設定時顯示警告"
|
||||
L["OPT_NOSTARTMESSAGES"] = "禁用歡迎訊息"
|
||||
L["OPT_NOSTARTMESSAGES_DESC"] = "移除每次登陸時在聊天框體顯示的三個 Decursive 訊息。"
|
||||
L["OPT_PLAYSOUND_DESC"] = "有玩家中了負面效果時發出音效。"
|
||||
L["OPT_POISONCHECK_DESC"] = "選取後你可以看見並清除中毒的玩家。"
|
||||
L["OPT_PRINT_CUSTOM_DESC"] = "顯示到自訂的聊天視窗。"
|
||||
L["OPT_PRINT_ERRORS_DESC"] = "顯示錯誤訊息。"
|
||||
L["OPT_PROFILERESET"] = "重置設定檔..."
|
||||
L["OPT_RANDOMORDER_DESC"] = "隨機顯示與淨化玩家(不推薦使用)。"
|
||||
L["OPT_READDDEFAULTSD"] = "回復預設負面效果"
|
||||
L["OPT_READDDEFAULTSD_DESC1"] = [=[添加被移除的預設負面效果
|
||||
你的設定不會被改變。]=]
|
||||
L["OPT_READDDEFAULTSD_DESC2"] = "所有的預設負面效果都在此清單中。"
|
||||
L["OPT_REMOVESKDEBCONF"] = [=[你確定要把
|
||||
'%s'
|
||||
從負面效果忽略清單中移除?]=]
|
||||
L["OPT_REMOVETHISDEBUFF"] = "移除此負面效果"
|
||||
L["OPT_REMOVETHISDEBUFF_DESC"] = "將 '%s' 從忽略清單移除。"
|
||||
L["OPT_RESETDEBUFF"] = "重置此負面效果"
|
||||
L["OPT_RESETDTDCRDEFAULT"] = "重置 '%s' 為 Decursive 預設值。"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS"] = "重置"
|
||||
L["OPT_RESETMUFMOUSEBUTTONS_DESC"] = "重置滑鼠按鈕指派為默認。"
|
||||
L["OPT_RESETOPTIONS"] = "重置為原始設定"
|
||||
L["OPT_RESETOPTIONS_DESC"] = "回復目前的設定檔為原始設定"
|
||||
L["OPT_RESTPROFILECONF"] = [=[你確定要重置
|
||||
'(%s) %s'
|
||||
為原始設定?]=]
|
||||
L["OPT_REVERSE_LIVELIST_DESC"] = "由下到上填滿即時清單。"
|
||||
L["OPT_SCANLENGTH_DESC"] = "設定掃描時間間隔。"
|
||||
L["OPT_SHOWBORDER"] = "顯示職業顏色邊框"
|
||||
L["OPT_SHOWBORDER_DESC"] = "MUFs 邊框會顯示出該玩家的職業代表顏色。"
|
||||
L["OPT_SHOWCHRONO"] = "顯示負面效果持續時間"
|
||||
L["OPT_SHOWCHRONO_DESC"] = "在 MUFs 上顯示負面效果持續的秒數"
|
||||
L["OPT_SHOWCHRONOTIMElEFT"] = "剩餘時間"
|
||||
L["OPT_SHOWCHRONOTIMElEFT_DESC"] = "顯示剩餘時間而不是消耗時間。"
|
||||
L["OPT_SHOWHELP"] = "顯示小提示"
|
||||
L["OPT_SHOWHELP_DESC"] = "當滑鼠移到一個 micro-unit-frame 上時顯示小提示。"
|
||||
L["OPT_SHOWMFS"] = "在螢幕上顯示 micro units Frame (MUF)"
|
||||
L["OPT_SHOWMFS_DESC"] = "如果你要在螢幕上按按鍵清除就必須點選這個設定。"
|
||||
L["OPT_SHOWMINIMAPICON"] = "迷你地圖圖標"
|
||||
L["OPT_SHOWMINIMAPICON_DESC"] = "啟用迷你地圖小圖示。"
|
||||
L["OPT_SHOW_STEALTH_STATUS"] = "顯示潛行狀態"
|
||||
L["OPT_SHOW_STEALTH_STATUS_DESC"] = [=[當玩家前行時,他的 MUF 將有一個特殊的顏色
|
||||
描述 SHOW_STEALTH_STATUS 選項]=]
|
||||
L["OPT_SHOWTOOLTIP_DESC"] = "在即時清單跟 MUFs 上顯示負面效果的小提示。"
|
||||
L["OPT_STICKTORIGHT"] = "將 MUF 視窗向右對齊"
|
||||
L["OPT_STICKTORIGHT_DESC"] = "設定這個選項將會使 MUF 視窗由右邊向左邊成長"
|
||||
L["OPT_TESTLAYOUT"] = "測試布局"
|
||||
L["OPT_TESTLAYOUT_DESC"] = [=[新建測試單位以測試顯示布局。
|
||||
(點擊後稍等片刻)]=]
|
||||
L["OPT_TESTLAYOUTUNUM"] = "單位數字"
|
||||
L["OPT_TESTLAYOUTUNUM_DESC"] = "設定新建測試單位數字。"
|
||||
L["OPT_TIECENTERANDBORDER"] = "固定 MUF 中央與邊框的透明度"
|
||||
L["OPT_TIECENTERANDBORDER_OPT"] = "選取時邊界的透明度固定為中央的一半。"
|
||||
L["OPT_TIE_LIVELIST_DESC"] = "即時清單顯示與否取決於 \"Decursive\" 工作條是否顯示。"
|
||||
L["OPT_TIEXYSPACING"] = "固定水平與垂直距離。"
|
||||
L["OPT_TIEXYSPACING_DESC"] = "固定 MUFs 之間的水平與垂直距離(空白)。"
|
||||
L["OPT_UNITPERLINES"] = "每一行幾個 MUF"
|
||||
L["OPT_UNITPERLINES_DESC"] = "設定每行最多顯示幾個 micro-unit- frames。"
|
||||
L["OPT_USERDEBUFF"] = "這項負面效果不是 Decursive 預設的效果之一"
|
||||
L["OPT_XSPACING"] = "水平距離"
|
||||
L["OPT_XSPACING_DESC"] = "設定 MUFs 之間的水平距離。"
|
||||
L["OPT_YSPACING"] = "垂直距離"
|
||||
L["OPT_YSPACING_DESC"] = "設定 MUFs 之間的垂直距離。"
|
||||
L["PLAY_SOUND"] = "有玩家需要淨化時發出音效"
|
||||
L["POISON"] = "中毒"
|
||||
L["POPULATE"] = "p"
|
||||
L["POPULATE_LIST"] = "Decursive 名單快速添加介面"
|
||||
L["PRINT_CHATFRAME"] = "在聊天視窗顯示訊息"
|
||||
L["PRINT_CUSTOM"] = "在遊戲畫面中顯示訊息"
|
||||
L["PRINT_ERRORS"] = "顯示錯誤訊息"
|
||||
L["PRIORITY_LIST"] = "Decursive 優先名單"
|
||||
L["PRIORITY_SHOW"] = "P"
|
||||
L["RANDOM_ORDER"] = "隨機淨化玩家"
|
||||
L["REVERSE_LIVELIST"] = "反向顯示即時清單"
|
||||
L["SCAN_LENGTH"] = "即時檢測時間間隔(秒): "
|
||||
L["SHIFT"] = "Shift"
|
||||
L["SHOW_MSG"] = "要顯示 Decursive 視窗,請輸入 /dcrshow。"
|
||||
L["SHOW_TOOLTIP"] = "在即時清單顯示簡要說明"
|
||||
L["SKIP_LIST_STR"] = "Decursive 忽略名單"
|
||||
L["SKIP_SHOW"] = "S"
|
||||
L["SPELL_FOUND"] = "找到 %s 法術"
|
||||
L["STEALTHED"] = "已潛行"
|
||||
L["STR_CLOSE"] = "關閉"
|
||||
L["STR_DCR_PRIO"] = "Decursive 優先選單"
|
||||
L["STR_DCR_SKIP"] = "Decursive 忽略選單"
|
||||
L["STR_GROUP"] = "隊伍 "
|
||||
L["STR_OPTIONS"] = "Decursive 設定選項"
|
||||
L["STR_OTHER"] = "其他"
|
||||
L["STR_POP"] = "快速添加清單"
|
||||
L["STR_QUICK_POP"] = "快速添加介面"
|
||||
L["SUCCESSCAST"] = "|cFF22FFFF%s %s|r |cFF00AA00成功淨化|r %s"
|
||||
L["TARGETUNIT"] = "選取目標"
|
||||
L["TIE_LIVELIST"] = "即時清單顯示與 DCR 視窗連結"
|
||||
L["TOOFAR"] = "太遠"
|
||||
L["UNITSTATUS"] = "玩家狀態: "
|
||||
|
||||
|
||||
|
||||
T._LoadedFiles["zhTW.lua"] = "2.5.1-6-gd3885c5";
|
||||
@@ -0,0 +1,836 @@
|
||||
|
||||
Changes from Decursive 2.3.0 to Decursive 2.3.1
|
||||
-----------------------------------------------
|
||||
|
||||
- Fixes a very old rare issue where Decursive would miss debuff events.
|
||||
|
||||
- Fixes focus unit management.
|
||||
|
||||
- Fixes minimap icon and main bar management when Decursive is "Ace-disabled".
|
||||
|
||||
|
||||
Changes from Decursive 2.3.0 RC7 to Decursive 2.3.0
|
||||
---------------------------------------------------
|
||||
|
||||
- Added mixed file version check to the self-diagnostic.
|
||||
- Fix LUA error introduced in RC7.
|
||||
|
||||
Changes from Decursive 2.3.0 RC4 to Decursive 2.3.0 RC7
|
||||
-------------------------------------------------------
|
||||
|
||||
- Fix a LUA error when PrioList members where excluded from blacklisting and a
|
||||
blacklisting event fired (target not in line of sight etc...)
|
||||
- Cleanse Spirit Shaman spell seems to be cast two times instead of once in
|
||||
certain conditions (Blizzard issue), Decursive was displaying spell failure
|
||||
error because of that. This is fixed.
|
||||
- Fixes pet spells detection when pet scanning was disabled (this issue was
|
||||
introduced in 2.3 beta 2)
|
||||
- The MUF auto-hide option was not setting itself correctly at initialisation
|
||||
(init order issue)
|
||||
- Showing the MUFs didn't trigger an update of its display this could result in
|
||||
missing units when using the auto-hide option or if the MUF frame was hidden...
|
||||
- Removed "support" for Earth Panel because I don't know what it is and nor
|
||||
does Google...
|
||||
- Added and fixed a few comments
|
||||
|
||||
|
||||
Changes from Decursive 2.3.0 RC2 to Decursive 2.3.0 RC4
|
||||
-------------------------------------------------------
|
||||
|
||||
- Removed FubarPlugin-2.0 library (use "Broker2FuBar" to have Decursive in Fubar)
|
||||
- Added LibDataBroker-1.1 and LibDBIcon-1.0 libraries.
|
||||
- Removed compatibility code for WoW 2.4.
|
||||
- Moved and renamed localization files to a proper directory.
|
||||
- New option: "MiniMap Icon" to toggle the display of Decursive Icon around the MiniMap.
|
||||
- Fixes a NIL error when an outsider friendly target got stealth.
|
||||
- Fixes the LUA error related to the "test affliction" in the live-list options.
|
||||
|
||||
|
||||
Changes from Decursive 2.3 beta 3 to Decursive 2.3.0 RC2
|
||||
--------------------------------------------------------
|
||||
|
||||
Fixes faulty initialisation due to CreateMacro() API changes in WoW 3.0 (when
|
||||
the users per-character macro were full)
|
||||
|
||||
- Bugfix: CreateMacro() was changed in WoW 2.3 as a result Decursive was
|
||||
creating its macro "per character" instead of "per account" and was not
|
||||
checking the right limit...
|
||||
|
||||
- Updated minimum required revision of libraries to the latest at this date.
|
||||
|
||||
|
||||
Changes from Decursive 2.2.0 to Decursive 2.3 beta 3
|
||||
----------------------------------------------------
|
||||
|
||||
- Decursive now uses GUID internally instead of unit names (CPU and memory usage optimisation).
|
||||
- A change of pet in the group was still triggering a group rescan even if pet
|
||||
scanning was disabled.
|
||||
- CPU optimization when using the priority list.
|
||||
- WARNING: after installing this version, the priority and skip list will be cleared.
|
||||
|
||||
|
||||
Changes from Decursive 2.1.0 Final to Decursive 2.2.0
|
||||
-----------------------------------------------------
|
||||
|
||||
**Important changes:**
|
||||
|
||||
- Decursive no longer uses SpecialEvent-Aura-2.0 to detect afflictions, it uses
|
||||
the new combat log system introduced in WoW 2.4. This simplifies the code a
|
||||
lot and prevent far away units to be scanned uselessly.
|
||||
|
||||
- As a result Decursive is now able to detect missed dispels and missed or
|
||||
failed spells with complete accuracy.
|
||||
|
||||
- A new sound alerts you if one of your spell launched using the MUFs fails or is resisted.
|
||||
|
||||
- The success spell message has been removed and replaced by a failure message when appropriate.
|
||||
|
||||
- New affliction alert sound more audible for people without a good bass system.
|
||||
|
||||
- The 'focus' unit will only be shown if not hostile and if not already part of the displayed MUF.
|
||||
|
||||
- When the live-list tool tips are disabled, the Live-List won't catch mouse
|
||||
events, you can click right through it.
|
||||
|
||||
- Affliction history is populated only when you click on a MUF to dispel something.
|
||||
|
||||
- Complete Russian translation by StingerSoft
|
||||
|
||||
- Compatible with WotLK beta
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Fix a nil error when players with pets were excluded using the skip list.
|
||||
|
||||
- fix a lot of insidious bugs related to 'gendered' class names.
|
||||
|
||||
- fix problems in battlefields with players from other realms (group ordering failures)
|
||||
|
||||
- Units not in line of sight are now always properly blacklisted (except when
|
||||
using pets, no failure events are sent).
|
||||
|
||||
- When adding or removing a player/group/class to the exclusion list, the MUFs
|
||||
display was not updated immediately.
|
||||
|
||||
- Fix for Chinese priests (two different spells named the same in this localisation...)
|
||||
|
||||
- Better sound alert management, alert loops are no longer possible.
|
||||
|
||||
- The lock and buttons display/hide status of the "Decursive" bar (the
|
||||
live-list anchor) were not applied correctly on startup.
|
||||
|
||||
|
||||
Changes from Decursive 2.0.4 to Decursive 2.1.0 Final
|
||||
-----------------------------------------------------
|
||||
|
||||
**Important changes:**
|
||||
|
||||
- When a player is afflicted, a new chronometer appears on its MUF giving the
|
||||
time elapsed (enabled by default)
|
||||
|
||||
- Added an automatic self-diagnostic feature also available through the
|
||||
/DCRDIAG command. This diagnostic is run when the add-on is loaded and check
|
||||
if all required libraries are available and are up to date.
|
||||
It also checks if all Decursive internal files are loaded correctly.
|
||||
When the command /DCRDIAG is used it also tests if the library AceEvent is
|
||||
functioning properly.
|
||||
|
||||
- New option: "Align MUF window to the right" (defaults to off)
|
||||
If enabled, the MUFs will grow from right to left and the handle will be
|
||||
moved automatically.
|
||||
|
||||
- New option: "Auto-Hide" (defaults to "Never")
|
||||
Lets you choose if you want to auto-hide/show the MUF window when in party or raid.
|
||||
|
||||
- New option: "Colors" in the "Micro Unit Frame Settings" sub-menu
|
||||
It is now possible to change all the MUFs colors.
|
||||
|
||||
- It is now possible to add afflictions to the filters from a list of recently
|
||||
seen afflictions instead of typing their names.
|
||||
|
||||
- The cure order priorities are now saved per class
|
||||
(This change resets your cure order priorities to default values)
|
||||
|
||||
- Decursive no longer uses the Babble-Spell library that is deprecated since
|
||||
WoW 2.4, all spells are now dynamically translated at load time ensuring
|
||||
compatibility with current and futur localized versions of World of Warcraft.
|
||||
|
||||
**Minor changes:**
|
||||
|
||||
- When moving the cursor quickly over friendly and hostile units, sometimes a
|
||||
phantom affliction could appear in the live-list for 0.2 seconds this has
|
||||
been fixed.
|
||||
|
||||
- When a new MUF is created outside the screen, the MUF window is always
|
||||
automatically moved so that all MUFs are visible.
|
||||
|
||||
- Spells handled by pets will no longer interrupt the player spells (when using
|
||||
the MUFs)
|
||||
|
||||
- Performance optimizations.
|
||||
|
||||
- Workaround for polymorph spells name change in WoW 2.3 (Decursive was no
|
||||
longer casting rank 1 of this spell...)
|
||||
|
||||
- Clarification in the different localization files.
|
||||
|
||||
- Fix an initialization issue some users were experiencing.
|
||||
|
||||
- Added a new FAQ entry about a rumour according to which Decursive would be
|
||||
banned by Blizzard. (take a look at the end of the Readme.txt file)
|
||||
|
||||
|
||||
Changes from Decursive 2.0.3 to Decursive 2.0.4
|
||||
-----------------------------------------------
|
||||
|
||||
- From now on, Decursive is dedicated to the memory of Bertrand Sense who died
|
||||
a month ago and was known as Glorfindal on "Les Sentinelles" (EU server).
|
||||
A special menu entry has been added.
|
||||
|
||||
- Moved FuBarPlugin relative options to a sub-menu.
|
||||
- Fix problems with Spanish localization since WoW 2.2.3
|
||||
- Probably fixed a rare LUA error that could occur in race conditions.
|
||||
(IsSpellInRange(): Invalid spell slot)
|
||||
|
||||
|
||||
Changes from Decursive 2.0 Final to Decursive 2.0.3
|
||||
---------------------------------------------------
|
||||
|
||||
**New features**
|
||||
|
||||
- Added a message and a sound when the Unstable Affliction is detected on a MUF
|
||||
you're about to click (works only if the MUFs' tool-tips are active.
|
||||
|
||||
- Added support for Druid's Cyclone Spell on friendly mind-controlled players.
|
||||
Because of this change affliction cure priorities may have changed, go into
|
||||
Options -> 'Curing Options' and change the priorities as you like.
|
||||
|
||||
- New PayPal donation button.
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
- If some afflictions were filtered out while in combat, the MUFs of the afflicted
|
||||
units were not updated once the battle was over.
|
||||
|
||||
- If you changed the cure priorities while some afflictions were already
|
||||
displayed in the MUFs, their color was not updated.
|
||||
|
||||
- Fix a Lua error that occurred wen the user had the live-list AND the MUFs
|
||||
disabled at UI initialization and was changing its 'Focus' (/focus
|
||||
/clearfocus)
|
||||
|
||||
- Pet appearance/disappearance events were not triggering an update of the
|
||||
number of MUFs displayed.
|
||||
|
||||
- Fix a Lua error when mouse-overing the MUFs with the class borders disabled.
|
||||
|
||||
**Small changes**
|
||||
|
||||
- Pet management enhancement:
|
||||
- Pet class and name detection should be much more accurate.
|
||||
- Pet names in MUFs tool-tips are preceded by "Pet" (depends on the
|
||||
localization)
|
||||
- Fix a possible issue with pet management (when several pets are 'unknown
|
||||
entities')
|
||||
|
||||
- Small optimization when using cleansing spells (blacklist handling).
|
||||
|
||||
- Added 'lesser invisibility' to stealth detection.
|
||||
|
||||
- The sound played when a debuff is found is now in a profile setting
|
||||
(profile.SoundFile).
|
||||
|
||||
- Decurive's icon will become gray if no curing spell is available or if all
|
||||
types of afflictions are unchecked in "curing options".
|
||||
|
||||
- zhCN and koKR translation update.
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 2.0 RC1 to Decursive 2.0 Final
|
||||
-----------------------------------------------------
|
||||
|
||||
- Mages will now cast polymorph rank 1 instead of the highest rank (uses less
|
||||
mana and last less time).
|
||||
- "Cast success" messages now include the spell rank.
|
||||
- Lua error fixed when using the decurse key when no spell are registered.
|
||||
- Default position of the MUFs and live-list have been optimized.
|
||||
- A note has been added on how to move the live-list (in readme.txt and in
|
||||
game).
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 7-Pub to Decursive 2.0 RC1
|
||||
----------------------------------------------------------
|
||||
|
||||
- An error message is displayed if Decursive cannot load its main libraries
|
||||
properly.
|
||||
- It's now possible to disable the warning displayed when no key is mapped to
|
||||
the macro.
|
||||
- There should be no more "succeeded on NONAME" messages.
|
||||
- Descriptions in French and Traditional Chinese have been added.
|
||||
- .TOC updated for WoW 2.1.
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 6-Pub-fixed to Decursive 2.0 BETA 7-Pub
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
**New features:**
|
||||
|
||||
- It's now possible to add dynamic groups and classes in the priority and skip
|
||||
list: Instead of adding each unit separately, class and/or group entities
|
||||
(ex: [ group 1 ] , [ Mage ]) will appear in the lists. The old behavior can
|
||||
still be used by maintaining [SHIFT] when clicking on a group or class-name in
|
||||
the populate list tool (names will be added).
|
||||
|
||||
- The last change also allow to sort units per group AND classes at the same
|
||||
time.
|
||||
|
||||
- An informative help message is displayed when the user doesn't click a MUF
|
||||
with the correct mouse button.
|
||||
|
||||
- Major code optimization: reduced CPU usage from ~0.04 seconds per seconds to
|
||||
~0.001 seconds per second (results obtained with up to date external Ace2
|
||||
libraries, if Decursive's embedded shared libraries are the most up to date,
|
||||
Decursive CPU usage will also count the usage of the shared libraries by other
|
||||
add-ons).
|
||||
|
||||
- Added revised Traditional Chinese translation by Peter Sun.
|
||||
|
||||
**Changes:**
|
||||
- When a MUF is clicked, any spell targeting in progress is canceled.
|
||||
- The MUFs react upon mouse button release instead of mouse button press.
|
||||
- When adding an affliction to the filter, the entered name is trimmed.
|
||||
- It is now possible to move the "Decursive" bar maintaining the Alt key pushed
|
||||
with the buttons hidden.
|
||||
|
||||
- Live-list system entirely rewritten.
|
||||
- The scale and transparency of the live-list can be changed in the options.
|
||||
- A message is displayed if the user clicks on the live-list...
|
||||
- It is possible to hear Decursive's debuff alert sound when the live-list is
|
||||
disabled.
|
||||
|
||||
- Decursive uses SpecialEvent-Aura events to monitor debuffs.
|
||||
- You can create a virtual debuff to test the display (see in live-list
|
||||
options)
|
||||
- The MiniMap and FuBar Decursive Icon is now clickable and an information
|
||||
tool-tip is displayed when mouse-overing it.
|
||||
- Decursive Icon gets grey when both the live-list and MUFs are disabled.
|
||||
- Added Major Dreamless Sleep to the debuff skip list (Translation is needed
|
||||
for other localizations)
|
||||
|
||||
|
||||
**Fixed bug:**
|
||||
- The status tool-tip was not displayed if the live-list was hidden.
|
||||
- Warlock pet detection could fail in some conditions.
|
||||
- Default Warrior ignored debuffs were not used because of a spelling mistake.
|
||||
- If you were already in combat when logging-in or if you reloaded your UI in
|
||||
combat, Decursive was unable to operate correctly.
|
||||
- Other little bugs were fixed.
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 6-Pub to Decursive 2.0 BETA 6-Pub-fixed
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
- Fixed several problems with the curing order priority system.
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 5 to 2.0 BETA 6-Pub
|
||||
---------------------------------------------------
|
||||
|
||||
# Important changes:
|
||||
|
||||
- Now you need to press Alt to move the MUFs clicking the handle.
|
||||
- Now a border is displayed around the MUFs, its color depends on the unit's
|
||||
class.
|
||||
- When a unit is charmed, a small green square is displayed inside its MUF.
|
||||
- A new static option panel is available by ALT-RIGHT-CLICKING on the handle or
|
||||
typing /dcroptions (Ace2 Waterfall library).
|
||||
- Added two new sets of options:
|
||||
- Class border and center transparency can be set separately.
|
||||
- Spacing between MUFs can be changed.
|
||||
- Paladin always uses Cleanse instead of Purify (if they learned Cleanse).
|
||||
- There is no longer a default key bound to the macro, this caused too many
|
||||
problems with people not knowing how to change it.
|
||||
- You can bind a key to show/hide the micro-unit frames.
|
||||
- In the debuff filtering system, you can now ignore a debuff permanently and
|
||||
not only when in combat.
|
||||
|
||||
# Minor changes:
|
||||
|
||||
- MUFs display can be reversed (they will display from bottom to top instead of
|
||||
top to bottom).
|
||||
- The Readme.txt file has been reworked to be more clear, "FEATURES" and "FAQ"
|
||||
sections have been added.
|
||||
- Warlock's spell priorities are saved when they change of pet.
|
||||
- The focus MUF now disappear when the player clear the focus with
|
||||
"/clearfocus".
|
||||
- Fix a bug that caused unit unable to cure magic on magic-charmed unit to see
|
||||
a curable magic debuff on these units.
|
||||
- You can fill your priority/skip list with Paladins and Shamans correctly.
|
||||
- Added spacers in MUFs option menu for better readability.
|
||||
- The missing macro binding error message will not be shown if a global binding
|
||||
is available.
|
||||
- Minor code optimizations and bug fixes.
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 4 to 2.0 BETA 5
|
||||
|
||||
- Fix a bug that caused the loss of per-character bindings.
|
||||
- Added a new debuff type: 'Charm' that applies to charmed units so mages can
|
||||
see all charmed units ; previously they could only see charmed units with a
|
||||
magical debuff (as priests). (This need testing, the situation is difficult to
|
||||
reproduce)
|
||||
- Added an option to change the transparency (Alpha) of the MUFs when a unit is
|
||||
not afflicted, it can be set to 0 to be completely transparent.
|
||||
- The micro unit frames (MUFs) are set to a lower strata.
|
||||
- "Arcane Blast" will no longer be shown as a Debuff.
|
||||
- Added full French localization by Sylvin
|
||||
- Added full Korean localization by Fenlis
|
||||
- Fixed typos in localization.lua and added a missing option description.
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 3 to 2.0 BETA 4
|
||||
|
||||
- Changed the minimum number of MUF per row to 1
|
||||
- The 'Show Help' option also disable the handle tool-tip
|
||||
- The focused unit won't be scanned if it's unfriendly (you won't see it in the
|
||||
MUFs nor in the live-list).
|
||||
- The macro binding function has been enhanced, it correctly unbinds previously
|
||||
mapped key and restores previously mapped action and displays messages when a
|
||||
mapping succeed/fails or replace a currently mapped action.
|
||||
- Added an option to not show out of range units in the live-list (enabled by
|
||||
default).
|
||||
- On non-English client, the key is set to "NONE" in the localization files so
|
||||
Decursive will display a warning to the user.
|
||||
- Babble-Spell library has been updated, Spanish spells should be supported.
|
||||
- Decursive is now available on wowace.com SVN
|
||||
|
||||
|
||||
Changes from Decursive 2.0 BETA 2 to 2.0 BETA 3
|
||||
|
||||
- Fix the huge memory consumption of the scanning functions.
|
||||
- Fix a problem with the macro that was not updated if the macro frame was
|
||||
opened.
|
||||
- Fix some options in the menus that were not propagated correctly.
|
||||
- Code optimization.
|
||||
- Added a note in the readme.txt file about how to change the default key bound
|
||||
to the macro.
|
||||
|
||||
Changes from Decursive 2.0 BETA 1 to 2.0 BETA 2
|
||||
|
||||
- Fix Micro-Unit-Frames (MUFs) display: the first time you log on, the MUFs are
|
||||
displayed to a reachable place instead of the top left corner of your screen.
|
||||
- Fix the LUA error message that occurred when you had all your macro spot
|
||||
used.
|
||||
- The handle to move the MUFs (above the first MUF) now highlights when
|
||||
mouse-overred, a tooltip has been added.
|
||||
- Fix a huge bug in the priority and skip list management causing a variable
|
||||
number of unit to not be displayed in the MUFs if your lists were not empty.
|
||||
- MUFs scaling functions have been improved.
|
||||
- The readme.txt file has been updated.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.8.4 to 2.0 BETA 1
|
||||
|
||||
User significant changes:
|
||||
|
||||
- Debuff removal capability restored in several ways:
|
||||
- By clicking on-micro unit frames created by Decursive for a
|
||||
user-defined number of players.
|
||||
- By mouse-overring units or unit frames and pushing a user-defined
|
||||
keyboard key.
|
||||
- Read the readme file to know more about these changes
|
||||
- Priority list management:
|
||||
- Now fully operational, you can very easily change player positions in
|
||||
the list
|
||||
- List display has been very improved (scrollbars, colors...)
|
||||
- Priority list order defines the order of the micro-unit frames
|
||||
displayed
|
||||
- The option window has been removed:
|
||||
- All options are accessed through a drop down menu appearing when
|
||||
right-clicking on "Decursive" bar. (DewDrop Ace2Lib)
|
||||
- Every menu entries has a small explanation tooltip.
|
||||
- All options can be accessed through command line (AceConsole Ace2Lib)
|
||||
- Debuff skipping management
|
||||
- Users can easily add/delete debuffs to ignore on specific classes
|
||||
while in combat
|
||||
- Mage can sheep mind-controlled units (if other classes are interested, their
|
||||
spell can be added on request)
|
||||
- The readme.txt file has been rewritten and should be read of course.
|
||||
|
||||
Internal changes:
|
||||
|
||||
- Decursive was almost entirely rewritten and reorganized (the live list system
|
||||
has not been redisigned yet)
|
||||
- New code architecture, more ressource efficient and more scalable.
|
||||
- Decursive is now an Ace2 add-on using Ace2 embeded libraries.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.8.3 to 1.9.8.4
|
||||
|
||||
- Fix syntax for compatibility with BC and LUA 5.1.1
|
||||
- Huge memory usage improvement, Decursive re-uses tables and uses the Compost
|
||||
Ace2 library so Decursive uses 0.0 Kib/s when idle or in action.
|
||||
- Improved CPU usage, it should be minimum.
|
||||
|
||||
|
||||
After BC Decursive may no longer be used while in combat, it will just tell you
|
||||
who you SHOULD de-curse but won't be able to target or cast for you... It may
|
||||
still work out of combat but it's not certain at this stage. Blizzard has made
|
||||
big changes in the game play so de-cursing without Decursive may not be as
|
||||
boring as it used to be...
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 1.9.8.2 to 1.9.8.3
|
||||
|
||||
- The "nothing Cleaned" bug some people were experiencing should be fixed.
|
||||
- There is no more "dead zone" beneath the "Decursive" bar when the live-list
|
||||
is displayed (thanks to Chewster for accurately reporting this bug)
|
||||
- The Shaman 'Purge' spell should work again.
|
||||
- New option: when Decursive is asked to clean, it cancels any spell in
|
||||
progress. (except for warlocks and channeled spells).
|
||||
- A new PDF doc is available in the Archive (thanks to Whitney for writing it).
|
||||
|
||||
Changes from Decursive 1.9.8.1 to 1.9.8.2
|
||||
|
||||
- Now Decursive disables and re-enables the "self auto cast" option
|
||||
automatically, it's no longer a problem.
|
||||
- Last version I hope!!!
|
||||
|
||||
Changes from Decursive 1.9.8 RC2 to 1.9.8.1
|
||||
|
||||
- Fix the LUA error happening on BG when a player from another server has a
|
||||
debuff to ignore (such as Mind Vision), other related issues should be fixed.
|
||||
- The WoW UI option "Auto Self Cast" is causing problems: Decursive is enable
|
||||
to cast on anyone but yourself while this option is active. Now Decursive
|
||||
will pop-up a warning if this option is enabled and will propose to disable it.
|
||||
- Chinese localization has been updated (thanks to Peter Sun).
|
||||
- French localization revised by The Grinch.
|
||||
|
||||
Changes from Decursive 1.9.8 RC1 to 1.9.8
|
||||
|
||||
- Fixed the LUA error happening for people who had the 'Print messages in
|
||||
default chat' option checked before upgrading to 1.9.8.
|
||||
- Fixed the custom message frame display, now it has a font to print
|
||||
something...
|
||||
|
||||
Changes from Decursive 1.9.7 to 1.9.8 RC1
|
||||
|
||||
************************ ====> IMPORTANT CHANGES: ************************
|
||||
|
||||
- TREMENDOUS PERFORMANCE IMPROVEMENTS (no more lag) (thanks to Lex for his
|
||||
cache idea)
|
||||
- You can choose in the options the type of debuff you want to cure (Magic,
|
||||
Poison, Curse, Disease)
|
||||
- Added cure priority based on debuff type (select the types in the order you
|
||||
want to de-curse). NOTE: For now this only works on a per unit basis,
|
||||
Decursive will de-curse a unit in the order you set debuff types. For example
|
||||
if you set (Poison, Curse), Decursive will first remove Poison on a unit then
|
||||
or if no poison, it will remove curses on that same unit...
|
||||
- TOC updated for 1.12
|
||||
|
||||
************************** ====> INTERESTING CHANGES:
|
||||
**************************
|
||||
|
||||
- When you have a target selected, whether it's in your raid or not it will
|
||||
appear in Decursive live-list if you can cure it.
|
||||
- Now you can see how many times a debuff is applied on a player in the live
|
||||
list.
|
||||
- Affliction type is displayed in the live list.
|
||||
|
||||
****************** ====> NEW OPTIONS: ******************
|
||||
|
||||
- New Option: Now you can decide how the text is displayed in the custom frame
|
||||
(From top or from bottom)
|
||||
- New Option: "Reverse live-list display"
|
||||
- New Option: "Show Tooltips in afflicted list"
|
||||
- New Option: "Hide the live-list"
|
||||
- New Option: "Tie live-list visibility to DCR window" (if the main DCR window
|
||||
is closed then the live-list is hidden...)
|
||||
- New command line and key binding: /dcrhide will hide Decursive window leaving
|
||||
the live-list visible /dcrshow shows Decursive window
|
||||
- New command line and key binding: /dcroption will open and close the option
|
||||
window
|
||||
- Added the global variable Dcr_Saved.Dcr_OutputWindow to change the default
|
||||
output window (use /script Dcr_Saved.Dcr_OutputWindow = ChatFrame2 for
|
||||
example).
|
||||
- Added /dcrdebug command to enable/disable debug info. (thanks to @derey)
|
||||
|
||||
******************** ====> MINOR CHANGES: ********************
|
||||
|
||||
- Enhanced message display with colors (you can also click character names in
|
||||
default chat window).
|
||||
- Raid curing order is now truly per group: your group, the groups after yours
|
||||
and the groups before yours. Before 1.9.8 BETA 2 it was: your group, the
|
||||
players from groups after yours and the players from groups before yours.
|
||||
- Fix the delay problem with text message (it was related to a change in 1.11)
|
||||
- If Decursive fails because the target is invalid, the target is blacklisted.
|
||||
- Internal code reorganization and sorting.
|
||||
- Updated .toc for 1.12
|
||||
- Other minor fixes.
|
||||
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 1.9.6 FINAL to 1.9.7
|
||||
|
||||
******************* ====> New features: *******************
|
||||
|
||||
- Now when a cast fails, only "out of sight" persons are blacklisted.
|
||||
|
||||
- You can hide the buttons by right clicking on "Decursive", when the buttons
|
||||
are hidden, the Decursive frame is locked so you can't move it by accident.
|
||||
|
||||
- Added the Option "Don't blacklist priority list names" (defaults to off)
|
||||
|
||||
- Added Chinese localization (zhTW)
|
||||
|
||||
******************* ====> Enhancements: *******************
|
||||
|
||||
- Performance improve.
|
||||
|
||||
- Debuffs to not cure (Dreamless Sleep and Mind Vision), will not be displayed
|
||||
nor cured unless the unit is debuffed by other debuffs of the same kind. In
|
||||
previous versions, those debuffs were skipped only if the player was in combat.
|
||||
|
||||
- Decursive's frame is smaller: the version is displayed in a tooltip.
|
||||
|
||||
- No more risk to lose the current target when the "Check for range" option is
|
||||
used.
|
||||
|
||||
- Decursive no longer checks for mana or for the state of your curing spell, it
|
||||
is no longer necessary (and may avoid some freezes).
|
||||
|
||||
- The display of Decursive message is now more logical, the text begins to be
|
||||
displayed just at the bottom of the "Text Anchor" frame (you can move it by
|
||||
clicking on the 'A' in the top-right corner of the option window)
|
||||
|
||||
- It is now more clear to see on who Decursive is casting the curring spell.
|
||||
|
||||
***************** ====> Bugs fixed: *****************
|
||||
|
||||
- The forgotten debug message Shamans were seeing has been removed.
|
||||
|
||||
- The problem priests in shadow form were experiencing has been fixed.
|
||||
|
||||
- No more freeze issue when a lot of players are out of range, thanks to Alason
|
||||
who gave me a new way to test for range.
|
||||
|
||||
- When you left-click on someone in the Decursive live-list Decursive won't try
|
||||
to cure your current target.
|
||||
|
||||
- No more 'awaiting for target state' when the cast fails.
|
||||
|
||||
******************** ====> Small Changes: ********************
|
||||
|
||||
- Scanning code has been slightly optimized.
|
||||
|
||||
- Out of range players are no longer added to the blacklist (this was useless
|
||||
since Decursive is able to bypass them).
|
||||
|
||||
- Removed the option "check for range", Decursive will always check for range.
|
||||
|
||||
- The sliders in the option window have been moved to the top to avoid clicking
|
||||
on the last one by accident when closing the window.
|
||||
|
||||
- Localization files have been updated.
|
||||
|
||||
- French and Chinese localization files are encoded in UTF-8.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.6.5 to Decursive 1.9.7
|
||||
- Decursive no longer check for mana or for the status of a spell, those were
|
||||
here to avoid to blacklist people for false reason. (LoS is detected since
|
||||
1.9.6.5)
|
||||
|
||||
Changes from Decursive 1.9.6.4 to Decursive 1.9.6.5
|
||||
|
||||
- Added the Option "Don't blacklist priority list names" (defaults to off)
|
||||
- Removed the option "check for range", Decursive will always check for range.
|
||||
- Now when a cast fails, only "out of sight" persons are blacklisted.
|
||||
- Out of range players are no longer added to the blacklist (this was useless).
|
||||
- Probably fix the freeze issue some people were experiencing.
|
||||
- Updated Chinese localization.
|
||||
|
||||
Changes from Decursive 1.9.6.3 to Decursive 1.9.6.4
|
||||
|
||||
- Debuffs to not cure (Dreamless Sleep and Mind Vision), will not be displayed
|
||||
nor cured unless the unit is debuffed by other debuffs of the same kind. In
|
||||
previous versions, those debuffs were skipped only if the player was in combat.
|
||||
- Added Chinese localization (zhTW)
|
||||
- Scanning code has been slightly optimized.
|
||||
- Now, French and Chinese localization files are in UTF-8
|
||||
|
||||
Changes from Decursive 1.9.6.2 to Decursive 1.9.6.3
|
||||
|
||||
- When you hide the buttons, the "Decursive" frame is locked so you can't move
|
||||
it by accident.
|
||||
- When Decursive dispels someone, the text displayed is shorter.
|
||||
- Small changes in the German localization.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.6.1 to Decursive 1.9.6.2
|
||||
|
||||
- Really fixed the bug with priests in shadow form.
|
||||
- When you left-click on someone in the Decursive live-list Decursive won't try
|
||||
to decurse your current target.
|
||||
- The display of Decursive message is now more logical, the text begins to be
|
||||
displayed just at the bottom of the "Text Anchor" frame (you can move it by
|
||||
clicking on the 'A' in the top-right corner of the option window)
|
||||
- The sliders in the option window have been moved to the top to avoid clicking
|
||||
on the last one by accident when closing the window.
|
||||
- It is now more clear to see on who Decursive is casting the curring spell.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.6 FINAL to Decursive 1.9.6.1
|
||||
|
||||
This is mainly a bug-fix release:
|
||||
- The forgotten debug message Shamans were seeing has been removed.
|
||||
- The problem priests in shadow form were experiencing has been fixed.
|
||||
- No more freeze issue when a lot of players are out of range, thanks to Alason
|
||||
who gave me a new way to test for range.
|
||||
- No more risk to lose the current target when the "Check for range" option is
|
||||
used.
|
||||
- No more 'awaiting for target state' when the cast fails.
|
||||
- Decursive's frame is smaller: the version is displayed in a tooltip.
|
||||
- You can hide the buttons by right clicking on "Decursive".
|
||||
- Small changes in the German localization.
|
||||
|
||||
|
||||
Changes from Decursive 1.9.4 to Decursive 1.9.6 Final
|
||||
|
||||
Important changes:
|
||||
|
||||
- Massive global performance improvement (important code optimization
|
||||
everywhere).
|
||||
- Re-Added support for warlock pets (Felhunter and Doomguard spells)
|
||||
- Added an option (on by default) to play a sound when you have someone to cure
|
||||
(Breenild idea).
|
||||
- Now when you click on a cursed person in Decursive's frame you will keep your
|
||||
current target unless you use the right-button of your mouse.
|
||||
- Now Decursive is able to check if you have enough mana before casting.
|
||||
- Complete French and German localization (Thanks to Archiv and WalleniuM for
|
||||
the German translations) So Decursive is able to ignore and skip correctly
|
||||
certain classes and debuffs in those localizations. This also corrects
|
||||
multiple dispels problem for those localizations.
|
||||
- Changed the licence to GNU GPL (Decursive 1.9.4 is in public domain)
|
||||
|
||||
Minor changes:
|
||||
|
||||
- Added a reminder at startup about the available options.
|
||||
- If you don't have one of your curring spell in your action bar, Decursive
|
||||
will display an error message when initializing.
|
||||
- Out of ranges units are added to the blacklist.
|
||||
- Options and lists are saved for each characters.
|
||||
- Options are reset to defaults with this version.
|
||||
- Improved re-targeting.
|
||||
|
||||
|
||||
Bugs fixed:
|
||||
|
||||
- Fixed initialization, 1.9.4 was sometime unable to find a spell to use.
|
||||
- Mind Control dispel was impossible.
|
||||
- The "check for range" option couldn't be set/unset and was causing Decursive
|
||||
to get stuck on out of range persons.
|
||||
- Improved Event handling (faster when zoning)
|
||||
- When you are in the priority list, your name is no longer displayed twice.
|
||||
- the "Ignore Stealthed Units" should work as intended (it never worked before)
|
||||
- Tooltip are displayed correctly.
|
||||
- Other minor bug fixes.
|
||||
|
||||
|
||||
|
||||
See below for a detailed change log between my versions of Decursive.
|
||||
|
||||
Changes on 1.9.6 FINAL (Release)
|
||||
|
||||
- the "Ignore Stealthed Units" should work as intended (it never worked before)
|
||||
- Performance improve when the option "Check for Abolish before curing" is used
|
||||
- Decursive can't put the current player to the blacklist anymore.
|
||||
|
||||
Changes in 1.9.6 RC4 (Release Candidate)
|
||||
|
||||
- Added a mana check, Decursive won't try to cast if there is not enough mana.
|
||||
(not available for warlocks)
|
||||
- Performance improve when the live list is displayed and contains afflicted
|
||||
people.
|
||||
- Performance improve when checking for range.
|
||||
- Added unlocalized strings to loc. (French and German loc. updated, thanks to
|
||||
Archiv for the German translations).
|
||||
- Options and lists are now saved per character (options reset to default with
|
||||
this version).
|
||||
|
||||
|
||||
Changes in 1.9.6 RC3 (Release Candidate)
|
||||
|
||||
- The correction about the MC bug in RC2 introduced a problem with units
|
||||
controlled by priests, changed the fix to a better one :)
|
||||
- Fixed tooltip display (tooltips were not displayed)
|
||||
|
||||
|
||||
Changes in 1.9.6 RC2 (Release Candidate)
|
||||
|
||||
- Probably fixed the MC issue.
|
||||
- Fixed: When left-clicking on Decursive's frame, the cured unit may not be the
|
||||
one you cliked on.
|
||||
- Fixed a bug (nil method) if the option "Check for range" was used.
|
||||
- Fixed the "Check for range" option, depending on the cases checking or
|
||||
unchecking it had no effect on the actual result.
|
||||
- When the option "Check for range" is enabled, and a unit is out of range,
|
||||
it's added to the blacklist.
|
||||
- Updated French localisation so Decursive can correctly ignored stealthed unit
|
||||
(if the option is set).
|
||||
- Updated German localization (problem with accents and a forgotten string,
|
||||
thanks to Archiv).
|
||||
|
||||
Changes in 1.9.6 RC1 (Release Candidate):
|
||||
|
||||
- Added new translations to French loc to prevent Decursive from dispelling:
|
||||
"Sommeil sans rêve" and "Vision télépathique"
|
||||
- Updated German localization (thanks to WalleniuM)
|
||||
- Overall performance improve (no more multiple calls to SetOwner()) This
|
||||
change may also fix the "Nothing cleaned" bug some people were still
|
||||
experiencing.
|
||||
- When you are in the priority list, your name is no longer displayed twice.
|
||||
- Warlocks can correctly switch to the target if they right click on it in
|
||||
Decursive's frame.
|
||||
|
||||
Changes in 1.9.6c (Was released in Dev Zone):
|
||||
|
||||
- Changed the alert sound to a better one.
|
||||
- Added a reminder at startup about the available options.
|
||||
- Fixed a possible issue with cool downs detection.
|
||||
- Added a possible fix for the reported warlock problem (it's still working
|
||||
with my Warlock and another warlock level 60).
|
||||
- When you right click on a cursed person in Dcr's window, it's selected even
|
||||
if nothing is done (spell not ready).
|
||||
|
||||
Changes in 1.9.6b (Was released in Dev Zone):
|
||||
|
||||
- Changed the licence to GNU GPL
|
||||
- Now when you click on a cursed person in Decursive's frame you will keep your
|
||||
current target unless you use the right-button of your mouse.
|
||||
- Small fixes in French localization.
|
||||
- Will never check for range if this is a warlock pet spell.
|
||||
- Added some debug information for people who have problems with the
|
||||
Fellhunter's spell.
|
||||
|
||||
Changes in 1.9.5c (Release):
|
||||
|
||||
- Added an option (on by default) to play a sound when you have someone to cure
|
||||
(Breenild idea).
|
||||
- Fixed a bug that could cause the cast of a wrong spell if you learn a new
|
||||
spell.
|
||||
|
||||
|
||||
Changes in 1.9.5b (changes from last Quu's version 1.9.4):
|
||||
|
||||
- Added support for warlock pet Felhunter spell 'Devour Magic' (tested on a
|
||||
French version but should work for English and German as well unless the
|
||||
localisation is not correct in Decursive 1.9.4)
|
||||
- Fixed French localization for Priests and Druids.
|
||||
- Improved Event handling (faster when zoning)
|
||||
- Fixed initialization, 1.9.4 was sometime unable to find a spell to use
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Decursive for World of Warcraft
|
||||
===============================
|
||||
|
||||
Download and documentation:
|
||||
|
||||
http://www.2072productions.com/to/decursive.php
|
||||
|
||||
http://www.wowace.com/addons/decursive/
|
||||
|
||||
Documentation is also available under the doc/ directory:
|
||||
|
||||
./doc/Description.txt
|
||||
|
||||
./doc/user-actions.txt
|
||||
|
||||
./doc/commands.txt
|
||||
|
||||
./doc/macro.txt
|
||||
|
||||
./doc/MUFs.txt
|
||||
|
||||
./doc/faq.txt
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
@@ -0,0 +1,27 @@
|
||||
TODO:
|
||||
|
||||
- add a donators credit section in the About UI
|
||||
|
||||
- change timers when mass debuff so that only the 5 or so first units of the array get updated in priority all the rest should be handled by the roaming MUF updater
|
||||
|
||||
- Add a menu option to choose between available spells. (will also allow to choose other polymorph spells)
|
||||
|
||||
- Add an option to disable spell stopping when clicking on a MUF
|
||||
|
||||
- Add an option to automatically focus sheeped/cycloned units (if no other focus)
|
||||
|
||||
- Add a user debuff warning mechanism where you could define debuff names you
|
||||
want to be aware of, then Decursive would add a special status, such as a
|
||||
little colored triangle in the middle of the MUFs and then you will have to
|
||||
create a mouseover macro (using default Blizzard macro interface) and use it on
|
||||
the MUF of your choice...
|
||||
|
||||
-/ when a mind controlled unit is sheepped we should be able to know it without having to target it and look for the sheep debuff
|
||||
(maybe just check for polymorph debuff/buff? on the target and remove the charmed bit if found) ----> or focus it...
|
||||
|
||||
- Add an option to let the user choose the alert sound.
|
||||
|
||||
|
||||
A very nice review of Decursive :
|
||||
|
||||
http://www.hotsdots.com/2009/07/improving-the-interface-using-addons-7-decursive-cleansing-and-dispelling/
|
||||
@@ -0,0 +1,256 @@
|
||||
Decursive 2.5.1 by Archarodim (2010-07-31)
|
||||
==========================================
|
||||
|
||||
|
||||
Changes from Decursive 2.5.0 to Decursive 2.5.1
|
||||
-----------------------------------------------
|
||||
|
||||
- *Raid Target Icons are now supported* (MUFs and Live-List display)
|
||||
|
||||
- *NEW option*: "Do not use 'Abolish' spells" (in the cure options). If enabled
|
||||
will prefer 'Cure Disease' and 'Cure Poison' over their 'Abolish' equivalent.
|
||||
(Defaults to off)
|
||||
|
||||
- "Check for 'Abolish' before curing" option now defaults to off. (May not be
|
||||
wanted when a disease or poison needs to be removed at all costs ; it was
|
||||
also confusing for some users)
|
||||
|
||||
- *NEW option*: "Allow macro edition" preventing Decursive from updating its
|
||||
macro and letting the user change it and still use Decursive macro key-binding
|
||||
management. (Defaults to off)
|
||||
|
||||
- *NEW command line option* to hide and disable the MUFs handle:
|
||||
(/dcr HideMUFsHandle)
|
||||
|
||||
- German translation is now complete (thanks to Freydis88).
|
||||
|
||||
- Remove the ERR_GENERIC_NO_TARGET debug report happening when the player
|
||||
tries to use Polymorph or Purge on himself or another friendly player.
|
||||
|
||||
- Fix to "LiveList:Update_Display(): couldn't get range" error occurring when
|
||||
not using the MUFs.
|
||||
|
||||
- Removed the French version of 'readme' and 'changelog' since 3 persons only
|
||||
were reading those.
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 2.4.5.1 to Decursive 2.5.0
|
||||
-------------------------------------------------
|
||||
|
||||
|
||||
*IMPORTANT CHANGES:*
|
||||
|
||||
- *NEW OPTION*: "Time left" for MUF chronometers. (Defaults to off) Displays time
|
||||
left instead of time elapsed on afflicted MUFs.
|
||||
|
||||
- *NEW OPTION PANEL*: (under the MUF options) to let the user choose the
|
||||
MUF's mouse button assignments. The middle-mouse button can be used to cast
|
||||
curing spells too.
|
||||
|
||||
- *NEW OPTION*: Testing MUF display layout is now possible. Look in the MUF
|
||||
display options.
|
||||
|
||||
- It's now possible to *check Decursive versions* used in your current group or
|
||||
Guild (From the 'About' option panel).
|
||||
|
||||
|
||||
|
||||
*MINOR CHANGES AND IMPROVEMENTS:*
|
||||
|
||||
- The 'Unstable Affliction' warning will also work when tool-tip display is
|
||||
disabled.
|
||||
|
||||
- Added a new option (under the general tab) to disable the three welcome
|
||||
messages Decursive prints at each login.
|
||||
|
||||
- Enhancement: The MUF tool-tip is always displayed above the MUFs or beneath
|
||||
them if it's not possible. (it can't overlap the MUFS anymore).
|
||||
|
||||
- The 'target' and 'mouseover' units will no longer be displayed in the
|
||||
Live-list if the player is part of the group.
|
||||
|
||||
- Non-release versions (alphas, betas and release candidates) of Decursive will
|
||||
expire after 30 days instead of 10. The expiration alert of these versions
|
||||
will be displayed only once every 48 hours (and no longer at every login).
|
||||
|
||||
- Updated minimum library versions requirements.
|
||||
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 2.4.5 to Decursive 2.4.5.1
|
||||
---------------------------------------------------
|
||||
|
||||
- Fix a problem where Decursive would not correctly detect priest talent 'Body
|
||||
and Soul' at login.
|
||||
|
||||
- Re-enabled debuglocals() hotfix for 3.3 when Lua error reporting is enabled.
|
||||
|
||||
- Localization update.
|
||||
|
||||
- TOC update for WoW 3.3.
|
||||
|
||||
|
||||
Changes from Decursive 2.4.3.2 to Decursive 2.4.5
|
||||
-------------------------------------------------
|
||||
|
||||
- **Major changes:**
|
||||
|
||||
- Decursive has been fully converted to Ace3.
|
||||
|
||||
- Decursive is no longer licensed under the GNU GPL, License has changed
|
||||
to 'All Rights Reserved' (see LICENSE.txt).
|
||||
|
||||
- Due to the conversion to Ace3, there is no longer a drop down menu to
|
||||
access the option.
|
||||
|
||||
- New option panel available through Blizzard add-ons option UI, you can also
|
||||
access the options by alt-right clicking on Decursive Icon.
|
||||
|
||||
- Decursive options will be reset to default upon installation of this version.
|
||||
|
||||
- **Minor changes:**
|
||||
|
||||
- Fix for Shamans: 'Cleans Spirit' was not replacing 'Cure Toxins', the two
|
||||
spells were both active and confusing for the user.
|
||||
|
||||
- Removed the 'Ignore stealthed units' option that is useless since several
|
||||
years.
|
||||
|
||||
- The Macro key binding is now a global setting (no longer bind to the
|
||||
profile).
|
||||
|
||||
- Replaced TabbletLib by LibQtip-1.0.
|
||||
|
||||
- Removed DewDrop-2.0 which has no replacement in Ace3 framework.
|
||||
|
||||
- Added an about panel.
|
||||
|
||||
- Various little enhancements and code cleanup.
|
||||
|
||||
|
||||
Changes from Decursive 2.4.3 to Decursive 2.4.3.2
|
||||
-------------------------------------------------
|
||||
|
||||
- A Lua error could occur in rare race conditions (when clicking on a MUF at the
|
||||
exact moment its debuff disappears).
|
||||
|
||||
- 'Shadoweld' was no longer detected as stealth because its spell ID changed.
|
||||
(future spell ID changes will generate debug reports).
|
||||
|
||||
Changes from Decursive 2.4.2 to Decursive 2.4.3
|
||||
-----------------------------------------------
|
||||
|
||||
- Implemented a permanent solution for debuffs not detected by direct debuff events.
|
||||
|
||||
- Made the macro options more reliable and logical:
|
||||
- When the macro creation is disabled, the currently assigned key is removed.
|
||||
- The assigned key is also removed when the profile options are reset.
|
||||
- Key assignment feature is disabled if the macro creation is disabled.
|
||||
|
||||
- The 'no macro key warning' is now turned off by default since this whole
|
||||
mouseover macro thing is not really interesting after all...
|
||||
|
||||
- Removed LibBabble-Class-3.0 (replaced by _G.LOCALIZED_CLASS_NAMES_MALE)
|
||||
|
||||
- Added an exception for the 'Dark Matter' debuff for which no SPELL_AURA_APPLIED
|
||||
event is generated by the game.
|
||||
|
||||
- Re-enabled Lua error handler but added security checks and also dynamic
|
||||
hotfixes to Blizzard_DebugTools errors that resulted in C Stack Overflows.
|
||||
- **IMPORTANT**: Because of (or rather thanks to) those hotfixes, Decursive installation may reveal some Lua errors
|
||||
that you couldn't see before.
|
||||
|
||||
- Always use the "player" unitID in raid (was using raid# when the player was included in the priority list)
|
||||
This prevents the player MUF from disappearing temporarily while a group update is in progress.
|
||||
|
||||
|
||||
Changes from Decursive 2.4.1 to Decursive 2.4.2
|
||||
-----------------------------------------------
|
||||
|
||||
- IMPORTANT STABILITY AND RELIABILITY FIXES: Problems fixed in this release
|
||||
could prevent Decursive from reporting afflictions in race conditions (all
|
||||
previous versions are affected).
|
||||
|
||||
- Added Shaman's "Hex" spell to crowd control charmed players.
|
||||
|
||||
- Added new Shaman spell "Cure Toxins".
|
||||
|
||||
- Documentation completely rewritten and reorganised using .docmeta and markdown
|
||||
formatting. Users don't have any excuse left to not read it now ;) The
|
||||
documentation is accessible there: <http://www.wowace.com/addons/decursive/>
|
||||
|
||||
- Decursive is now able to report LUA errors related to itself using the
|
||||
wonderful "non-annoying after combat auto report feature" introduced in 2.4.1 :)
|
||||
|
||||
- Added support for AddonLoader http://www.wowwiki.com/AddonLoader (auto-load
|
||||
if your class is any of Mage, Priest, Paladin, Druid, Hunter, Warlock,
|
||||
Shaman).
|
||||
|
||||
- Added an option to disable the macro creation.
|
||||
|
||||
- Miscellaneous enhancements and minor bug fixes.
|
||||
|
||||
|
||||
Changes from Decursive 2.4 to Decursive 2.4.1
|
||||
-----------------------------------------------
|
||||
|
||||
- Added support for the new priest talent 'Body and soul' to be able to cleanse
|
||||
a poison effect on self when using 'Abolish Disease'.
|
||||
|
||||
- Added the 'Tranquilizing Shot' Hunter spell to remove magic debuff on mind
|
||||
controlled units.
|
||||
|
||||
- Important enhancements and fixes to the MUF positioning/scaling system:
|
||||
- Changing their scale will no longer affect their position in an illogical
|
||||
way.
|
||||
- MUFs are maintained on screen whatever happens ; their position will
|
||||
no longer be reset to default.
|
||||
|
||||
- Multiple fixes and enhancements to charm (mind control state) detection.
|
||||
|
||||
- Fixes to Decursive icon: now it does what the tool-tip says and it doesn't
|
||||
throw a LUA error if tool-tips are disabled in the LDB client.
|
||||
|
||||
- The MUFs no longer depend on the 'mouseover' unit (internal simplification,
|
||||
more reliability).
|
||||
|
||||
- Added a new advanced debug report system.
|
||||
|
||||
|
||||
|
||||
Changes from Decursive 2.3.1 to Decursive 2.4
|
||||
---------------------------------------------
|
||||
|
||||
- New feature: The cool down of the curing spell to be used is displayed
|
||||
(clock) on afflicted MUFs.
|
||||
|
||||
- Decursive uses AceLocal-3.0 ; localization is now made using this interface:
|
||||
http://wow.curseforge.com/projects/decursive/localization/
|
||||
|
||||
- Miscellaneous localization updates in various languages.
|
||||
|
||||
- Re-implemented the max unit to show option.
|
||||
|
||||
- Added a warning when the user disables Decusive and an explanation on how to
|
||||
re-enable it (/dcr standby)
|
||||
|
||||
- Translations for key bindings descriptions (WoW key binding interface)
|
||||
|
||||
- It's no longer possible to map the button 1 and 2 of the mouse to Decursive's
|
||||
macro by accident.
|
||||
|
||||
- Fixes a problem if the game is loaded without any "saved variables" where the
|
||||
API GetCurrentBindingSet() would return incorrect values unusable with the
|
||||
API SaveBindings() preventing Decursive from initializing correctly.
|
||||
|
||||
- Bug fix: Charmed unit detection wasn't working if the player himself was charmed.
|
||||
|
||||
- Bug fix: The focus MUF was not added at the end but just before pets.
|
||||
|
||||
- Bug fix: The stick to right option (concerning the MUFs positions) was broken.
|
||||
|
||||
- Some other minor bug fixes.
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
Decursive for World of Warcraft
|
||||
===============================
|
||||
|
||||
*Decursive is a cleansing mod intended to render affliction removal easy, effective and fun for all the classes having this ability.*
|
||||
|
||||
[Decursive usage][user-actions] - [Micro Unit Frames documentation][MUFs] - [Decursive Macro documentation][mouse-over macro] - [Frequently Asked Questions][FAQ] - [commands][]
|
||||
|
||||
Decursive key benefits
|
||||
----------------------
|
||||
|
||||
- **Ease of use:**
|
||||
|
||||
- Decursive configures itself **automatically** for your character class, *it works straight out of the box*, no configuration is required.
|
||||
- Intuitive interface and detailed options, Decursive is suitable for simple usage and power users.
|
||||
|
||||
- Control **what and who** you want to dispel:
|
||||
|
||||
- Easily **Filter out** afflictions you don't want to cure or that are useless to remove by class (*some are pre-configured*).
|
||||
(Such as afflictions affecting mana on non-mana classes, etc...).
|
||||
- **Choose** between what you can dispel (**magic, curses, poison, diseases, charms**) choosing their priority.
|
||||
(this allows you to *share* the cleansing work with other players effectively)
|
||||
- **Prioritize** or exclude members.
|
||||
(keep players, classes, or raid groups in a specific order to cleanse them in order of importance)
|
||||
|
||||
- **Manage Mind controlled units:**
|
||||
|
||||
- If you are a Mage, a Druid or a Shaman you can *Polymorph/Cyclone/Hex* mind-controlled players.
|
||||
- In any case Decursive will allow you to target mind controlled units easily.
|
||||
- Decursive supports **magic charming affect removal** for Shamans (*Purge* and *Hex*), Priests (*Dispel Magic*),
|
||||
Hunters (*Tranquilizing Shot*), and Warlocks (*Fellhunter and Doomguards spells*).
|
||||
|
||||
- **Don't waste time:**
|
||||
|
||||
- Your cleansing spell **Cooldown** is displayed to maximize your dispel speed.
|
||||
- An **automatic blacklist** will prevent you from loosing time on players that cannot be dispelled.
|
||||
(player 'out of line of sight' for example).
|
||||
- Decursive choose a **logical cleansing order** depending on your current position in the raid.
|
||||
(preventing dispel concurrence between players and thus 'nothing to dispel' messages)
|
||||
|
||||
- **React faster:**
|
||||
|
||||
- **Visual** and/or **auditive** alerts when someone needs your attention and *can* be dispelled.
|
||||
- Special sound alert when *Unstable Affliction* is detected and you're about to dispel it.
|
||||
- Visual and auditive alert when your dispel attempts are *resisted or fail*.
|
||||
|
||||
- **Integration in any interface:**
|
||||
|
||||
- Decursive is designed to **save screen real estate** and to be forgotten when not needed.
|
||||
- Many options allow you to customize Decursive appearance and interface behavior.
|
||||
- All Decursive alert colors can be modified making it suitable for color-blind people.
|
||||
|
||||
- **Highly optimized and effective coding:**
|
||||
|
||||
- Decursive was developed with **memory and CPU usage** in mind, **installing Decursive won't affect your frame rate even in the worst battle conditions**.
|
||||
- Bug free: **bugs are not tolerated in Decursive**.
|
||||
|
||||
|
||||
In brief, what you get with Decursive is **effectiveness**, *a player using Decursive will always dispel faster than other players*.
|
||||
|
||||
|
||||
*See also:*
|
||||
|
||||
- [Decursive usage][user-actions]
|
||||
- [Micro Unit Frames documentation][MUFs]
|
||||
- [Decursive Macro documentation][mouse-over macro]
|
||||
- [Frequently Asked Questions][FAQ] *try this before asking any question*
|
||||
- [commands][]
|
||||
|
||||
******************************************
|
||||
|
||||
|
||||
Decursive is dedicated to the memory of Bertrand Sense known as Glorfindal on
|
||||
the European server *Les Sentinelles*.
|
||||
He was the raid leader of my guild (<http://www.wow-horizon.org>)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[MUFs]: http://www.wowace.com/projects/decursive/pages/main/mufs/ "Micro Unit Frames"
|
||||
[MUF]: http://www.wowace.com/projects/decursive/pages/main/mufs/ "Micro Unit Frame"
|
||||
[FAQ]: http://www.wowace.com/projects/decursive/pages/main/faq/ "F.A.Q section"
|
||||
[mouse-over macro]: http://www.wowace.com/projects/decursive/pages/main/macro/ "Decursive's mouse-over macro documentation"
|
||||
[commands]: http://www.wowace.com/projects/decursive/pages/main/commands/ "Command lines"
|
||||
[user-actions]: http://www.wowace.com/projects/decursive/pages/main/user-actions/ "Decursive, user possible actions"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user