This commit is contained in:
Andrew6810
2022-10-21 06:52:48 -07:00
parent 4ceaf3a125
commit 6988cc52f5
110 changed files with 32921 additions and 2 deletions
+56
View File
@@ -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
+430
View File
@@ -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";
+138
View File
@@ -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
+186
View File
@@ -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>
+834
View File
@@ -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
+202
View File
@@ -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";
+575
View File
@@ -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";
+211
View File
@@ -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>
+783
View File
@@ -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"
+601
View File
@@ -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";
+913
View File
@@ -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
+525
View File
@@ -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";
+889
View File
@@ -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
+73
View File
@@ -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
+352
View File
@@ -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>
+23
View File
@@ -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.
+30
View File
@@ -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>
+309
View File
@@ -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>
+728
View File
@@ -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
+4
View File
@@ -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>
+805
View File
@@ -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)
+28
View File
@@ -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)
+514
View File
@@ -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
+29
View File
@@ -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
+4
View File
@@ -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>
+390
View File
@@ -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";
+395
View File
@@ -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";
+103
View File
@@ -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";
+78
View File
@@ -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";
+392
View File
@@ -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 é 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";
+385
View File
@@ -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";
+14
View File
@@ -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>
+388
View File
@@ -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";
+384
View File
@@ -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";
+382
View File
@@ -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 19692007"
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";
+836
View File
@@ -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
+23
View File
@@ -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

+27
View File
@@ -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/
+256
View File
@@ -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.
+85
View File
@@ -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