You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2142 lines
88 KiB

5 years ago
--[[
Extends Modules by adding:
Module:OnWindowCreated(winObj)
Module:OnWindowDestroyed(winObj)
Module:OnWindowPopped(winObj)
Module:OnWindowMessageAdded(winObj, msg, r, g, b)
Module:OnWindowShow(winObj)
Module:OnWindowHide(winObj)
Module:OnContainerShow()
Module:OnContainerHide()
]]
local WIM = WIM;
-- imports
local _G = _G;
local CreateFrame = CreateFrame;
local UIFrameFadeIn = UIFrameFadeIn;
local UIFrameFadeOut = UIFrameFadeOut;
local GetMouseFocus = GetMouseFocus;
local table = table;
local string = string;
local IsShiftKeyDown = IsShiftKeyDown;
local select = select;
local pairs = pairs;
local type = type;
local unpack = unpack;
local strsub = strsub;
local time = time;
local Ambiguate = Ambiguate;
local GetGuildInfo = GetGuildInfo;
local UnitClass = UnitClass;
local UnitLevel = UnitLevel;
local UnitRace = UnitRace;
-- set namespace
setfenv(1, WIM);
-- load message window related default settings.
db_defaults.displayColors = {
sysMsg = {
r=1,
g=0.6627450980392157,
b=0
},
errorMsg = {
r=1,
g=0,
b=0
},
useSkin = true,
};
db_defaults.fontSize = 12;
db_defaults.windowAlpha = 80;
db_defaults.windowOnTop = true;
db_defaults.keepFocus = true;
db_defaults.keepFocusRested = true;
db_defaults.autoFocus = false;
db_defaults.winSize = {
width = 333,
height = 220,
scale = 100,
strata = "DIALOG"
};
db_defaults.winLoc = {
left =217,
top =664
};
db_defaults.winCascade = {
enabled = true,
direction = 8
};
db_defaults.winFade = true;
db_defaults.winAnimation = true;
db_defaults.wordwrap_indent = false;
db_defaults.coloredNames = true;
db_defaults.escapeToHide = true;
db_defaults.ignoreArrowKeys = true;
db_defaults.pop_rules = {};
db_defaults.whoLookups = true;
db_defaults.hoverLinks = false;
db_defaults.tabAdvance = false;
db_defaults.clampToScreen = true;
db_defaults.formatting = {
bracketing = {
enabled = true,
type = 1,
},
};
WIM.lists.bracketing = {
[1] = {
[1] = "[",
[2] = "]"
},
[2] = {
[1] = "<",
[2] = ">"
},
}
local WindowSoupBowl = {
windowToken = 0,
available = 0,
used = 0,
windows = {
}
}
local FadeProps = {
min = .5,
max = 1,
interval = .25,
delay = 2
};
local cascadeDirection = {
{0, 25}, -- Up
{0, -25}, -- Down
{-50, 0}, -- Left
{50, 0}, -- Right
{-50, 25}, -- Up & Left
{50, 25}, -- Up & Right
{-50, -25}, -- Down & Left
{50, -25}, -- Down & Right
};
windowsByAge = {};
nextColor = {};
local FormattingCallsList = {}; -- used to get a list of available Formattings.
local FormattingCalls = {}; -- functions which are passed events to be formatted. Only one may be used at once.
local StringModifiers = {}; -- registered functions which will be used to format the message part of the string.
-- Window's Parent (Container for all Windows)
WindowParent = _G.CreateFrame("Frame", "WIM_UIParent", _G.UIParent);
WindowParent:SetFrameStrata("BACKGROUND");
WindowParent:SetPoint("BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", 0, 0);
WindowParent:SetScript("OnShow", function(self)
WindowParent:SetWidth(_G.UIParent:GetWidth());
WindowParent:SetHeight(_G.UIParent:GetHeight());
end);
-- WindowParent.test = WindowParent:CreateTexture("BACKGROUND");
-- WindowParent.test:SetColorTexture(1,1,1,.5)
-- WindowParent.test:SetAllPoints();
WindowParent:Hide();
-- the following table defines a list of actions to be taken when
-- script handlers are fired for different type windows.
-- use WIM:RegisterWidgetTrigger(WindowType, ScriptEvent, function());
local Widget_Triggers = {};
local function getFormatByName(format)
local i;
for i=1, #FormattingCalls do
if(FormattingCalls[i].name == format) then
return FormattingCalls[i].fun;
end
end
return FormattingCalls[1].fun;
end
function applyMessageFormatting(...)
local fun = getFormatByName(db.messageFormat);
return fun(...);
end
function applyStringModifiers(str, chatDisplay)
for i=1, #StringModifiers do
str = StringModifiers[i](str, chatDisplay);
end
chatDisplay.noEscapedStrings = nil;
return str;
end
local RegisteredWidgets = {}; -- a list of registered widgets added to windows from modules.
windows.widgets = RegisteredWidgets;
--[[ Sample Widget with triggers
RegisteredWidgets["Test"] = function(parentWindow)
_G.DEFAULT_CHAT_FRAME:AddMessage("Test Widget created!");
local t = CreateFrame("Frame");
t.SetDefaults = function()
_G.DEFAULT_CHAT_FRAME:AddMessage("Test Widget defaults set!");
end
t.UpdateProps = function()
_G.DEFAULT_CHAT_FRAME:AddMessage("Test Widget props updated!");
end
return t;
end
]]
local windowListByLevel_Recycle = {};
local function getActiveWindowListByLevel()
-- first remove items from previously used list.
local i;
for i=1,#windowListByLevel_Recycle do
table.remove(windowListByLevel_Recycle, 1);
end
-- load all used windows into table
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse and WindowSoupBowl.windows[i].obj:IsVisible()) then
table.insert(windowListByLevel_Recycle, WindowSoupBowl.windows[i].obj);
end
end
table.sort(windowListByLevel_Recycle, function(a,b)
a, b = a:GetFrameLevel(), b:GetFrameLevel();
return a>b;
end);
return windowListByLevel_Recycle;
end
function getWindowAtCursorPosition(excludeObj)
-- can optionaly exclude an object
local x,y = _G.GetCursorPosition();
local windows = getActiveWindowListByLevel();
local i;
for i=1,#windows do
if(excludeObj ~= windows[i]) then
local x1, y1 = windows[i]:GetLeft()*windows[i]:GetEffectiveScale(), windows[i]:GetTop()*windows[i]:GetEffectiveScale();
local x2, y2 = x1 + windows[i]:GetWidth()*windows[i]:GetEffectiveScale(), y1 - windows[i]:GetHeight()*windows[i]:GetEffectiveScale();
if(x >= x1 and x <= x2 and y <= y1 and y >= y2) then
return windows[i];
end
end
end
return nil;
end
-- window resizing helper
local resizeFrame = CreateFrame("Button", "WIM_WindowResizeFrame", WindowParent);
resizeFrame:Hide();
resizeFrame.widgetName = "resize";
resizeFrame:SetFrameStrata("TOOLTIP");
resizeFrame.Attach = function(self, win)
if(win.widgets.close ~= GetMouseFocus() and win.type ~= "demo") then
self:SetParent(win);
self.parentWindow = win;
ApplySkinToWidget(self);
self:Show();
-- resizeFrame:SetFrameLevel(999);
else
self:Reset();
resizeFrame:Hide();
end
end
resizeFrame.Reset = function(self)
self:SetParent(WindowParent);
self:ClearAllPoints();
self:SetPoint("TOPLEFT");
self:Hide();
end
resizeFrame:SetScript("OnMouseDown", function(self)
self.isSizing = true;
self.parentWindow.customSize = true;
self.parentWindow:SetResizable(true);
self.parentWindow:StartSizing("BOTTOMRIGHT");
end);
resizeFrame:SetScript("OnMouseUp", function(self)
self.isSizing = false;
self.parentWindow.customSize = true;
self.parentWindow:StopMovingOrSizing();
local tabStrip = self.parentWindow.tabStrip;
if(tabStrip) then
dPrint("Size sent to tab strip.");
end
-- DisplayTutorial(L["Window Resized!"], L["If you want all windows to be this size, you can set the default window size within WIM's options."]);
end);
resizeFrame:SetScript("OnHide", function(self)
if(self.parentWindow and self.isSizing) then
local OnMouseUp = self:GetScript("OnMouseUp");
OnMouseUp(self);
end
end);
resizeFrame:SetScript("OnUpdate", function(self)
if(self.isSizing and self.parentWindow and self.parentWindow.tabStrip) then
local curSize = self.parentWindow:GetWidth()..self.parentWindow:GetHeight();
if(self.prevSize ~= curSize) then
self.parentWindow.tabStrip:UpdateTabs();
self.prevSize = curSize;
end
end
if(self.parentWindow.isMoving) then
self:Reset();
end
end);
-- helperFrame's purpose is to assist with dragging and dropping of Windows into tab strips.
-- The frame will monitor which window objects are being dragged over and attach itself to them when
-- it's key trigger is pressed.
local helperFrame = CreateFrame("Frame", "WIM_WindowHelperFrame", WindowParent);
helperFrame.flash = helperFrame:CreateTexture(helperFrame:GetName().."Flash", "OVERLAY");
helperFrame.flash:SetPoint("BOTTOMLEFT");
helperFrame.flash:SetPoint("BOTTOMRIGHT");
helperFrame.flash:SetHeight(4);
helperFrame.flash:SetBlendMode("ADD");
helperFrame.flash:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight");
helperFrame:SetFrameStrata("TOOLTIP");
helperFrame:SetWidth(1);
helperFrame:SetHeight(1);
helperFrame.ResetState = function(self)
helperFrame:ClearAllPoints();
helperFrame:SetParent(UIPanel);
helperFrame:SetWidth(1);
helperFrame:SetHeight(1);
helperFrame:SetPoint("TOPLEFT", WindowParent, "TOPLEFT", 0, 0);
helperFrame.isAttached = false;
helperFrame.attachedTo = nil;
end
helperFrame:SetPoint("TOPLEFT", WindowParent, "TOPLEFT", 0, 0);
helperFrame:SetScript("OnUpdate", function(self)
if(IsShiftKeyDown()) then
local obj = GetMouseFocus();
if(obj and (obj.isWimWindow or obj.parentWindow)) then
local win;
if(obj.isWimWindow) then
win = obj;
else
win = obj.parentWindow;
end
if(win == WIM.DemoWindow) then
return;
end
if(not win.isMoving) then
resizeFrame:Attach(win);
end
if(win.isMoving and not (win.tabStrip and win.tabStrip:IsVisible())) then
local mWin = getWindowAtCursorPosition(win);
if(mWin) then
if(self.isAttached) then
if(mWin ~= self.attachedTo) then
self:ResetState();
end
else
if(mWin ~= WIM.DemoWindow) then
-- attach to window
local skinTable = GetSelectedSkin().tab_strip;
self.parentWindow = mWin;
self.attachedTo = mWin;
mWin.helperFrame = self;
self:SetParent(mWin);
SetWidgetRect(self, skinTable);
self:SetHeight(self.flash:GetHeight());
self.isAttached = true;
end
end
else
if(self.isAttached) then
self:ResetState();
end
end
else
if(self.isAttached) then
self:ResetState();
end
end
else
resizeFrame:Reset();
if(self.isAttached) then
self:ResetState();
end
end
else
resizeFrame:Reset();
if(self.isAttached) then
self:ResetState();
end
end
if(self.isAttached) then
self.flash:Show();
else
self.flash:Hide();
end
end);
helperFrame:Show();
local function executeHandlers(WidgetName, wType, HandlerName, ...)
local tbl, fun;
if(Widget_Triggers[WidgetName] and Widget_Triggers[WidgetName][HandlerName] and Widget_Triggers[WidgetName][HandlerName][wType]) then
tbl = Widget_Triggers[WidgetName][HandlerName][wType];
end
if(type(tbl) == "table") then
for i=1,#tbl do
fun = tbl[i];
fun(...);
end
end
end
-- Returns object, SoupBowl_windows_index or nil if window can not be found.
local function getWindowBy(userName)
if(type(userName) ~= "string") then
return nil;
end
for i=1,#WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].user == userName) then
return WindowSoupBowl.windows[i].obj, i;
end
end
end
-- Clean up the frame's points and make sure the main point TOPLEFT,BOTTOMRIGHT is set
function cleanPoints(win)
local x, y;
for i = 1, win:GetNumPoints() do
local p1, parent, p2, tx, ty = win:GetPoint(i);
_G.DEFAULT_CHAT_FRAME:AddMessage(p1..", ".._G.tostring(parent)..", "..p2..", "..tx..", "..ty);
end
_G.DEFAULT_CHAT_FRAME:AddMessage(" "..win:SafeGetLeft()..", "..win:SafeGetTop());
end
-- climb up inherritance tree and find parent window recursively.
local function getParentMessageWindow(obj)
if(not obj) then
return nil;
elseif(obj.isParent) then
return obj;
elseif(obj.parentWindow) then
return obj.parentWindow;
elseif(obj:GetName() == "UIParent") then
return nil;
else
return getParentMessageWindow(obj:GetParent())
end
end
local function animateFade(obj, directionIn, force)
local fadeAnimator = obj.animators.fade
local to = directionIn and FadeProps.max or FadeProps.min
local from = obj:GetAlpha()
if force then
obj:SetAlpha(to)
fadeAnimator.animation.fadingDiretionIn = directionIn
return
end
if fadeAnimator:IsPlaying() then
local progress = fadeAnimator:GetProgress()
from = fadeAnimator.animation:GetToAlpha() * progress
fadeAnimator:Stop()
fadeAnimator.animation:SetDuration(FadeProps.interval)
fadeAnimator.animation:SetFromAlpha(from)
fadeAnimator.animation:SetToAlpha(to)
fadeAnimator:Play()
fadeAnimator:SetScript("OnFinished", function ()
obj:SetAlpha(to)
end)
else
fadeAnimator.animation:SetDuration(FadeProps.interval)
fadeAnimator.animation:SetFromAlpha(from)
fadeAnimator.animation:SetToAlpha(to)
fadeAnimator:SetScript("OnFinished", function ()
obj:SetAlpha(to)
end)
fadeAnimator:Play()
end
fadeAnimator.animation.fadingDiretionIn = directionIn
end
local function setWindowAsFadedIn(obj)
if(WIM.db.winFade) then
if not obj.fadedIn then
obj:fadeIn()
obj.delayFadeElapsed = 0;
obj.delayFade = true;
obj.fadedIn = true;
end
else
obj:fadeIn(true);
end
end
--------------------------------------
-- Widget Script Handlers --
--------------------------------------
function updateScrollBars(parentWindow)
if(parentWindow and parentWindow.widgets and parentWindow.widgets.chat_display) then
if(parentWindow.widgets.chat_display:AtTop()) then
parentWindow.widgets.scroll_up:Disable();
else
parentWindow.widgets.scroll_up:Enable();
end
if(parentWindow.widgets.chat_display:AtBottom()) then
parentWindow.widgets.scroll_down:Disable();
else
parentWindow.widgets.scroll_down:Enable();
end
end
end
local function MessageWindow_MovementControler_OnDragStart(self)
local window = getParentMessageWindow(self);
if(window) then
window:StartMoving();
window.isMoving = true;
end
end
local function MessageWindow_MovementControler_OnDragStop(self)
local window = getParentMessageWindow(self);
if(window) then
local dropTo = helperFrame.attachedTo;
helperFrame:ResetState();
window:StopMovingOrSizing();
window.isMoving = false;
window.widgets.chat_display:Hide();
window.widgets.chat_display:Show();
window.hasMoved = true;
if(dropTo) then
if(dropTo.tabStrip) then
dropTo.tabStrip:Attach(window);
window:Hide();
dropTo.tabStrip:JumpToTab(dropTo);
else
window:Hide();
local tabStrip = GetAvailableTabGroup();
tabStrip:Attach(dropTo);
tabStrip:Attach(window);
tabStrip:JumpToTab(dropTo);
end
end
end
end
-- this needs to be looked at. it isn't doing anything atm...
local function MessageWindow_Frame_OnShow(self)
if(WindowParent.animUp) then
return;
end
-- _G.DEFAULT_CHAT_FRAME:AddMessage(_G.debugstack(1))
setWindowAsFadedIn(self);
if(self ~= DemoWindow) then
updateScrollBars(self);
CallModuleFunction("OnWindowShow", self);
for widgetName, widgetObj in pairs(self.widgets) do
if(type(widgetObj.OnWindowShow) == "function") then
widgetObj:OnWindowShow();
end
end
else
self.widgets.chat_display:Clear();
self.widgets.chat_display:AddMessage(L["_DemoText"]);
self.widgets.msg_box:Hide();
end
end
-- this needs to be looked at. it isn't doing anything atm...
local function MessageWindow_Frame_OnHide(self)
if ( self.isMoving ) then
self:StopMovingOrSizing();
self.isMoving = false;
end
self:ResetAnimation();
if(self.type == "demo" and self.demoSave) then
-- save window placement settings.
db.winLoc.left = self:SafeGetLeft()*self:GetEffectiveScale();
db.winLoc.top = self:SafeGetTop()*self:GetEffectiveScale();
options.frame:Enable();
self.demoSave = nil;
DestroyWindow(self);
WIM.DemoWindow = nil;
elseif(self.type ~= "demo") then
CallModuleFunction("OnWindowHide", self);
for widgetName, widgetObj in pairs(self.widgets) do
if(type(widgetObj.OnWindowHide) == "function") then
widgetObj:OnWindowHide();
end
end
end
end
local function updateTracker(win)
if(not WindowParent.animUp) then
local pS, sS = WindowParent:GetEffectiveScale(), win:GetEffectiveScale()
local pL, pR, pT, pB = WindowParent:GetLeft()*pS, WindowParent:GetRight()*pS, WindowParent:GetTop()*pS, WindowParent:GetBottom()/pS;
local sL, sR, sT, sB = win:GetLeft()*sS, win:GetRight()*sS, win:GetTop()*sS, win:GetBottom()*sS;
if(not db.clampToScreen and sT < 0) then -- bottom
if(win.offScreen ~= 1) then
win.offScreen = 1;
CallModuleFunction("OnWindowLeaveScreen", win, 1);
end
elseif(not db.clampToScreen and sB > pT) then -- top
if(win.offScreen ~= 2) then
win.offScreen = 2;
CallModuleFunction("OnWindowLeaveScreen", win, 2);
end
elseif(not db.clampToScreen and sR < 0) then -- left
if(win.offScreen ~= 3) then
win.offScreen = 3;
CallModuleFunction("OnWindowLeaveScreen", win, 3);
end
elseif(not db.clampToScreen and sL > pR) then -- right
if(win.offScreen ~= 4) then
win.offScreen = 4;
CallModuleFunction("OnWindowLeaveScreen", win, 4);
end
else
-- on screen
if(win.offScreen ~= 0) then
CallModuleFunction("OnWindowEnterScreen", win);
end
win.offScreen = 0;
end
end
end
local function MessageWindow_Frame_OnUpdate(self, elapsed)
-- window is visible, there aren't any messages waiting...
updateTracker(self);
self.msgWaiting = false;
self.unreadCount = 0;
-- animation segment
if(self.animation and self.animation.mode) then
local animate = self.animation;
if(animate.mode == "HIDE") then
animate.elapsed = animate.elapsed + elapsed;
if(animate.elapsed > animate.time) then
self:Hide_Normal();
else
local prct = animate.elapsed/animate.time;
local scale = (db.winSize.scale/100)*(1-prct);
scale = scale > animate.scaleLimit and scale or animate.scaleLimit;
self:SetScale(scale);
if(animate.to and animate.to.GetEffectiveScale) then
local to = animate.to;
local es, ts = self:GetEffectiveScale(), to:GetEffectiveScale();
es, ts = es > 0 and es or .01, ts > 0 and ts or .01;
local x1, y1, x2, y2 = animate.initLeft*es, animate.initTop*es, to:GetLeft()*ts, to:GetTop()*ts;
local rise, run = ((y2-y1)>=0) and (y2-y1) or 0, ((x2-x1)>=0) and (x2-x1) or 0;
self:ClearAllPoints();
self:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", (x1+run*prct)/es, (y1+rise*prct)/es);
end
end
end
else
-- fading segment
if(db.winFade and self ~= DemoWindow) then
self.fadeElapsed = (self.fadeElapsed or 0) + elapsed;
while(self.fadeElapsed > .1) do
local window = GetMouseFocus();
if(window) then
if(((window == self or window.parentWindow == self or self.isOnHyperLink or
self == helperFrame.attachedTo or
(EditBoxInFocus and EditBoxInFocus.parentWindow == self)) or
(window.tabStrip and window.tabStrip.selected.obj == self)) and
(not self.fadedIn or self.delayFade)) then
self:fadeIn()
self.fadedIn = true;
self.delayFade = false;
self.delayFadeElapsed = 0;
elseif(window ~= self and window.parentWindow ~= self and not self.isOnHyperLink and
(not (window.tabStrip and window.tabStrip.selected.obj == self)) and
helperFrame.attachedTo ~= self and
(not EditBoxInFocus or EditBoxInFocus.parentWindow ~= self) and self.fadedIn) then
if(self.delayFade) then
self.delayFadeElapsed = (self.delayFadeElapsed or 0) + elapsed;
while(self.delayFadeElapsed > FadeProps.delay) do
self.delayFade = false;
self.delayFadeElapsed = 0;
end
else
self.fadedIn = false;
self.delayFadeElapsed = 0;
self:fadeOut()
end
end
end
self.fadeElapsed = 0;
end
elseif(not self.fadedIn) then
setWindowAsFadedIn(self);
end
end
end
-- local function MessageWindow_MsgBox_OnMouseUp()
-- CloseDropDownMenus();
-- if(arg1 == "RightButton") then
-- WIM_MSGBOX_MENU_CUR_USER = this:GetParent().theUser;
-- UIDropDownMenu_Initialize(WIM_MsgBoxMenu, WIM_MsgBoxMenu_Initialize);
-- ToggleDropDownMenu(1, nil, WIM_MsgBoxMenu, this, 0, 0);
-- end
-- end
local function loadHandlers(obj)
local widgets = obj.widgets;
for widget, tbl in pairs(Widget_Triggers) do
for handler,_ in pairs(tbl) do
-- This is, what i feel an over kill of checks.. but if it works... /shrug.
if(widgets[widget] and widgets[widget]and not widgets[widget]:GetScript(handler)) then
widgets[widget]:SetScript(handler, function(...) executeHandlers(widget, obj.type, handler, ...); end)
end
end
end
end
local function setAllChildrenParentWindow(parent, child)
local i;
if(child ~= parent) then
child.parentWindow = parent;
end
local children = {child:GetChildren()};
for i=1,#children do
setAllChildrenParentWindow(parent, children[i]);
end
end
local function loadRegisteredWidgets(obj)
local widgets = obj.widgets;
for widget, createFun in pairs(RegisteredWidgets) do
if(widgets[widget] == nil) then
if(type(createFun) == "function") then
widgets[widget] = createFun();
widgets[widget]:SetParent(obj);
widgets[widget].widgetName = widget;
widgets[widget].parentWindow = obj;
widgets[widget].enabled = true;
widgets[widget].Enable = function(self)
self.enabled = true;
self:Show();
self.parentWindow:UpdateProps();
end
widgets[widget].Disable = function(self)
self.enabled = false;
self:Hide();
self.parentWindow:UpdateProps();
end
ApplySkinToWidget(widgets[widget]);
dPrint("Widget '"..widget.."' added to '"..obj:GetName().."'");
if(type(widgets[widget].SetDefaults) == "function") then
widgets[widget]:SetDefaults(); -- load defaults for this widget
end
end
else
if(type(widgets[widget].SetDefaults) == "function") then
widgets[widget]:SetDefaults(); -- load defaults for this widget
end
end
-- widgets[widget].parentWindow = obj;
if(type(widgets[widget]) == "table") then
widgets[widget].parentWindow = obj;
end
end
setAllChildrenParentWindow(obj, obj)
end
local function updateActiveObjects()
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse) then
loadRegisteredWidgets(WindowSoupBowl.windows[i].obj);
loadHandlers(WindowSoupBowl.windows[i].obj);
end
end
end
function scaleWindow(self, scale)
-- scale down window and preserve location
local left, top = self:SafeGetLeft()*self:GetEffectiveScale(), self:SafeGetTop()*self:GetEffectiveScale();
local setScale = self.SetScale_Orig or self.SetScale;
setScale(self, (scale > 0) and scale or 0.01)
self:ClearAllPoints();
local curScale = self:GetEffectiveScale();
curScale = (curScale > 0) and curScale or 0.01;
self:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", left/curScale, top/curScale);
end
-- create all of MessageWindow's object children
local function instantiateWindow(obj)
local fName = obj:GetName();
-- set frame's initial properties
obj:SetClampedToScreen(not WindowParent.animUp and db.clampToScreen);
obj:SetFrameStrata("DIALOG");
obj:SetMovable(true);
obj:SetToplevel(true);
obj:SetWidth(384);
obj:SetHeight(256);
obj:EnableMouse(true);
obj:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", 25, WindowParent:GetTop()-125);
obj:RegisterForDrag("LeftButton");
obj:SetScript("OnDragStart", MessageWindow_MovementControler_OnDragStart);
obj:SetScript("OnDragStop", MessageWindow_MovementControler_OnDragStop);
obj:SetScript("OnMouseUp", MessageWindow_MovementControler_OnDragStop);
obj:SetScript("OnShow", MessageWindow_Frame_OnShow);
obj:SetScript("OnHide", MessageWindow_Frame_OnHide);
obj:SetScript("OnUpdate", MessageWindow_Frame_OnUpdate);
obj.isWimWindow = true;
obj.helperFrame = helperFrame;
obj.animation = {};
obj.SetScale_Orig = obj.SetScale;
obj.SetScale = scaleWindow;
-- create animations
obj.animators = {}
obj.animators.fade = obj:CreateAnimationGroup()
obj.animators.fade.animation = obj.animators.fade:CreateAnimation("Alpha")
obj.fadeIn = function (self, force) animateFade(self, true, force) end
obj.fadeOut = function (self, force) animateFade(self, false, force) end
obj.fadedIn = true
obj.widgets = {};
local widgets = obj.widgets;
-- add window backdrop frame
widgets.Backdrop = CreateFrame("Frame", fName.."Backdrop", obj);
widgets.Backdrop:SetToplevel(false);
widgets.Backdrop:SetAllPoints(obj);
widgets.class_icon = widgets.Backdrop:CreateTexture(fName.."BackdropClassIcon", "BACKGROUND");
widgets.class_icon.widgetName = "class_icon";
widgets.class_icon.parentWindow = obj;
widgets.Backdrop.tl = widgets.Backdrop:CreateTexture(fName.."Backdrop_TL", "BORDER");
widgets.Backdrop.tr = widgets.Backdrop:CreateTexture(fName.."Backdrop_TR", "BORDER");
widgets.Backdrop.bl = widgets.Backdrop:CreateTexture(fName.."Backdrop_BL", "BORDER");
widgets.Backdrop.br = widgets.Backdrop:CreateTexture(fName.."Backdrop_BR", "BORDER");
widgets.Backdrop.t = widgets.Backdrop:CreateTexture(fName.."Backdrop_T" , "BORDER");
widgets.Backdrop.b = widgets.Backdrop:CreateTexture(fName.."Backdrop_B" , "BORDER");
widgets.Backdrop.l = widgets.Backdrop:CreateTexture(fName.."Backdrop_L" , "BORDER");
widgets.Backdrop.r = widgets.Backdrop:CreateTexture(fName.."Backdrop_R" , "BORDER");
widgets.Backdrop.bg = widgets.Backdrop:CreateTexture(fName.."Backdrop_BG", "BORDER");
widgets.from = widgets.Backdrop:CreateFontString(fName.."BackdropFrom", "OVERLAY", "GameFontNormalLarge");
widgets.from.widgetName = "from";
widgets.char_info = widgets.Backdrop:CreateFontString(fName.."BackdropCharacterDetails", "OVERLAY", "GameFontNormal");
widgets.char_info.widgetName = "char_info";
-- create core window objects
widgets.close = CreateFrame("Button", fName.."ExitButton", obj);
widgets.close:RegisterForClicks("LeftButtonUp", "RightButtonUp");
widgets.close.curTextureIndex = 1;
widgets.close.parentWindow = obj;
widgets.close.widgetName = "close";
widgets.scroll_up = CreateFrame("Button", fName.."ScrollUp", obj);
widgets.scroll_up:RegisterForClicks("LeftButtonUp", "RightButtonUp");
widgets.scroll_up.widgetName = "scroll_up";
widgets.scroll_down = CreateFrame("Button", fName.."ScrollDown", obj);
widgets.scroll_down:RegisterForClicks("LeftButtonUp", "RightButtonUp");
widgets.scroll_down.widgetName = "scroll_down";
widgets.chat_display = CreateFrame("ScrollingMessageFrame", fName.."ScrollingMessageFrame", obj);
-- widgets.chat_display:RegisterForDrag("LeftButton");
widgets.chat_display:SetHyperlinksEnabled(true)
widgets.chat_display:SetFading(false);
widgets.chat_display:SetMaxLines(128);
widgets.chat_display:SetMovable(true);
-- widgets.chat_display:SetScript("OnDragStart", function(self) MessageWindow_MovementControler_OnDragStart(self); end);
-- widgets.chat_display:SetScript("OnDragStop", function(self) MessageWindow_MovementControler_OnDragStop(self); end);
widgets.chat_display:SetJustifyH("LEFT");
widgets.chat_display:EnableMouse(true);
widgets.chat_display:EnableMouseWheel(1);
widgets.chat_display.widgetName = "chat_display";
widgets.msg_box = CreateFrame("EditBox", fName.."MsgBox", obj);
widgets.msg_box:SetAutoFocus(false);
widgets.msg_box:SetHistoryLines(32);
-- widgets.msg_box:SetMaxLetters(255);
widgets.msg_box:SetAltArrowKeyMode(true);
widgets.msg_box:EnableMouse(true);
widgets.msg_box.widgetName = "msg_box";
-- Addmessage functions
obj.AddMessage = function(self, msg, ...)
msg = applyStringModifiers(msg, self.widgets.chat_display);
self.widgets.chat_display:AddMessage(msg, ...);
updateScrollBars(self);
CallModuleFunction("OnWindowMessageAdded", self, msg, ...);
end
obj.AddMessageRaw = function(self, msg, ...)
self.widgets.chat_display:AddMessage(msg, ...);
end
obj.AddEventMessage = function(self, r, g, b, event, ...)
nextColor.r, nextColor.g, nextColor.b = r, g, b;
local str = applyMessageFormatting(self.widgets.chat_display, event, ...);
self:AddMessage(str, r, g, b);
self.msgWaiting = true;
self.lastActivity = _G.GetTime();
if(self.tabStrip) then
self.tabStrip:UpdateTabs();
end
end
obj.UpdateIcon = function(self)
local icon = self.widgets.class_icon;
if(self.type == "chat" and self.chatType) then
icon:SetTexture(GetSelectedSkin().message_window.widgets.class_icon.chatAlphaMask);
local chat_type = self.chatType == "battleground" and "INSTANCE_CHAT" or string.upper(self.chatType);
local color = _G.ChatTypeInfo[chat_type]; -- Drii: ticket 344
icon:SetTexCoord(0,1,0,1);
icon:SetGradient("VERTICAL", color.r, color.g, color.b, color.r, color.g, color.b);
if(GetSelectedSkin().message_window.widgets.from.use_class_color) then
self.widgets.from:SetTextColor(color.r, color.g, color.b);
end
else
local classTag = obj.class;
icon:SetGradient("VERTICAL", 1, 1, 1, 1, 1, 1);
if(self.bn and self.bn.client == _G.BNET_CLIENT_SC2) then
classTag = "sc2";--"Interface\\FriendsFrame\\Battlenet-Sc2icon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_SC) then
classTag = "sc1";--"Interface\\FriendsFrame\\Battlenet-SCicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_DESTINY2) then
classTag = "dsty2";--"Interface\\FriendsFrame\\Battlenet-SCicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_COD) then
classTag = "vipr";--"Interface\\FriendsFrame\\Battlenet-SCicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_D3) then
classTag = "d3";--"Interface\\FriendsFrame\\Battlenet-D3icon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_WTCG) then
classTag = "hs";--"Interface\\FriendsFrame\\Battlenet-WTCGicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_HEROES) then
classTag = "hots";--"Interface\\FriendsFrame\\Battlenet-HotSicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and self.bn.client == _G.BNET_CLIENT_OVERWATCH) then
classTag = "ow";--"Interface\\FriendsFrame\\Battlenet-Overwatchicon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.bn and (self.bn.client == _G.BNET_CLIENT_APP or self.bn.client == _G.BNET_CLIENT_CLNT or self.bn.client == "BSAp")) then--Battle.net Desktop/Mobile Apps
classTag = "bnd";--"Interface\\FriendsFrame\\Battlenet-Battleneticon"
icon:SetTexture(GetSelectedSkin().message_window.widgets.client_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.client_icon[classTag]));
elseif(self.class == "") then
classTag = "blank"
icon:SetTexture(GetSelectedSkin().message_window.widgets.class_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.class_icon[classTag]));
else
if(constants.classes[self.class]) then
classTag = string.lower(constants.classes[self.class].tag);
classTag = string.gsub(classTag, "f$", "");
else
classTag = "blank";
end
icon:SetTexture(GetSelectedSkin().message_window.widgets.class_icon.texture);
icon:SetTexCoord(unpack(GetSelectedSkin().message_window.widgets.class_icon[classTag]));
end
if(constants.classes[self.class]) then
self.classColor = constants.classes[self.class].color;
if(GetSelectedSkin().message_window.widgets.from.use_class_color) then
self.widgets.from:SetTextColor(RGBHexToPercent(constants.classes[self.class].color));
end
end
end
end
obj.UpdateCharDetails = function(self)
self.widgets.char_info:SetText(GetSelectedSkin().message_window.widgets.char_info.format(self, self.guild, self.level, self.race, self.class));
end
obj.WhoCallback = function(result)
if(result and result.Online and result.Name == obj.theUser) then
obj.class = result.Class;
obj.level = result.Level;
obj.race = result.Race;
obj.guild = result.Guild;
obj.location = result.Zone;
obj:UpdateIcon();
obj:UpdateCharDetails();
end
end
obj.SendWho = function(self)
if(self.type ~= "whisper") then
return;
end
if(self.isGM) then
self.WhoCallback({
Name = self.theUser,
Online = true,
Guild = "Blizzard",
Class = L["Game Master"],
Level = "",
Race = "",
Zone = L["Unknown"]
});
elseif(self.isBN) then
-- get information of BN user from friends data.
local id = self.theUser and _G.BNet_GetBNetIDAccount(self.theUser) or nil;
if(id) then
local _, _, _, _, _, bnetIDGameAccount = GetBNGetFriendInfoByID(id)
local hasFocus, toonName, client, realmName, realmID, faction, race, class, guild, zoneName, level, gameText, broadcastText, broadcastTime = GetBNGetGameAccountInfo(bnetIDGameAccount or 0);
self.class = class or "";
self.level = level or "";
self.race = race or "";
self.guild = guild or "";
self.location = client == _G.BNET_CLIENT_WOW and zoneName or gameText;
self.bn.class = class;
self.bn.level = level;
self.bn.race = race;
self.bn.guild = guild;
self.bn.location = client == _G.BNET_CLIENT_WOW and zoneName or gameText;
self.bn.gameText = gameText;
self.bn.toonName = toonName;
self.bn.client = client;
self.bn.realmName = realmName;
self.bn.faction = faction;
self.bn.broadcastText = broadcastText;
self.bn.broadcastTime = broadcastTime;
self.bn.hasFocus = hasFocus;
self.bn.id = id;
-- self.widgets.from:SetText(self.theUser.." - "..toonName);
self:UpdateIcon();
if (client == _G.BNET_CLIENT_WOW) then
self:UpdateCharDetails();
end
else
self:AddMessage(_G.BN_UNABLE_TO_RESOLVE_NAME, db.displayColors.errorMsg.r, db.displayColors.errorMsg.g, db.displayColors.errorMsg.b);
end
else
--Check if sending unit is in your party, then check guild
if _G.IsInRaid() then
for i = 1, _G.GetNumGroupMembers() do
local unitId = "raid"..i
local name = _G.GetUnitName(unitId, true)
if self.theUser == name then
self.WhoCallback({
Name = name,
Online = true,
Guild = self.guild or "",
Class = UnitClass(unitId) or "",
Level = UnitLevel(unitId) or "",
Race = UnitRace(unitId) or "",
Zone = self.zone or ""
});
break
end
end
elseif _G.IsInGroup() then
for i = 1, _G.GetNumSubgroupMembers() do
local unitId = "party"..i
local name = _G.GetUnitName(unitId, true)
if self.theUser == name then
self.WhoCallback({
Name = name,
Online = true,
Guild = self.guild or "",
Class = UnitClass(unitId) or "",
Level = UnitLevel(unitId) or "",
Race = UnitRace(unitId) or "",
Zone = self.zone or ""
});
break
end
end
end
if _G.IsInGuild() then
local lookupName = Ambiguate(self.theUser, "none");
local playerGuildIndex = lists.guild[lookupName];
if (playerGuildIndex) then
local name, rank, rankIndex, level, class, zone = _G.GetGuildRosterInfo(playerGuildIndex)
if name and lookupName:lower() == Ambiguate(name, "none"):lower() then --no name, means during our scan someone left guild and we hit an index that no longer returns player name, or the index is outdated and names do not match
self.WhoCallback({
Name = self.theUser,
Online = true,
Guild = select(1, GetGuildInfo("player")) or "",
Class = class or "",
Level = level or "",
Race = self.race or "",
Zone = zone or ""
});
end
end
end
end
end
obj.GetRuleSet = function(self)
if(db.pop_rules[self.type]) then
local curState = db.pop_rules[self.type].alwaysOther and "other" or curState
return db.pop_rules[self.type][curState];
else
return db.pop_rules.whisper.other;
end
end
-- PopUp rules
obj.Pop = function(self, msgDirection, forceResult, forceFocus) -- true to force show, false it ignore rules and force quiet.
-- account for variable arguments.
if(type(msgDirection) == "boolean") then
forceResult, forceFocus = msgDirection, forceResult;
msgDirection = "in";
elseif(msgDirection == nil) then
msgDirection = "in";
end
local rules = self:GetRuleSet(); -- defaults incase unknown
-- pass isNew to pop ruleset.
if(forceResult == true) then
-- go by forceResult and ignore rules
if(self.tabStrip) then
-- if(not EditBoxInFocus) then
ShowContainer();
self.tabStrip:JumpToTab(self);
if(not getVisibleChatFrameEditBox() and (rules.autofocus or forceFocus)) then
self.widgets.msg_box:SetFocus();
end
-- end
else
ShowContainer();
self:ResetAnimation();
self:Show();
if((not getVisibleChatFrameEditBox() and not EditBoxInFocus and rules.autofocus) or forceFocus) then
self.widgets.msg_box:SetFocus();
end
local count = 0;
for i=1, #WindowSoupBowl.windows do
count = WindowSoupBowl.windows[i].obj:IsShown() and count + 1 or count;
end
--[[ if(count > 1) then
DisplayTutorial(L["Creating Tab Groups"], L["You can group two or many windows together by <Shift-Clicking> a window and dragging it on top of another."]);
else
DisplayTutorial(L["Resizing Windows"], L["You can resize a window by holding <Shift> and dragging the bottom right corner of the window."]);
end-- ]]
end
else
-- execute pop rules.
if((rules.onSend and msgDirection == "out") or (rules.onReceive and msgDirection == "in")) then
if(self.tabStrip) then
self:ResetAnimation();
local infocus = EditBoxInFocus and EditBoxInFocus:GetParent().tabStrip;
if(infocus ~= self.tabStrip) then
self.tabStrip:JumpToTab(self);
setWindowAsFadedIn(self);
end
else
self:ResetAnimation();
self:Show();
setWindowAsFadedIn(self);
end
if(self:IsVisible() and not getVisibleChatFrameEditBox and not EditBoxInFocus and rules.autofocus) then
self.widgets.msg_box:SetFocus();
end
end
end
-- at this state the message is no longer classified as a new window, reset flag.
obj.isNew = false;
CallModuleFunction("OnWindowPopped", self);
end
obj.UpdateProps = function(self)
self:SetFrameStrata(db.winSize.strata);
self:SetScale(db.winSize.scale/100);
self.widgets.Backdrop:SetAlpha(db.windowAlpha/100);
local Path,_,Flags = self.widgets.chat_display:GetFont();
self:SetClampedToScreen(not WindowParent.animUp and db.clampToScreen);
self.widgets.chat_display:SetFont(Path or _G["ChatFontNormal"]:GetFont(),db.fontSize+2,Flags);
self.widgets.chat_display:SetAlpha(1);
self.widgets.chat_display:SetIndentedWordWrap(db.wordwrap_indent);
self.widgets.msg_box:SetAlpha(1);
self.widgets.msg_box:SetAltArrowKeyMode(db.ignoreArrowKeys);
self.widgets.from:SetAlpha(1);
self.widgets.char_info:SetAlpha(1);
self.widgets.close:SetAlpha(db.windowAlpha);
self.widgets.scroll_up:SetAlpha(db.windowAlpha);
self.widgets.scroll_down:SetAlpha(db.windowAlpha);
if(not self.customSize) then
self:SetWidth(db.winSize.width);
self:SetHeight(db.winSize.height);
end
local minWidth, minHeight = GetSelectedSkin().message_window.min_width, GetSelectedSkin().message_window.min_height;
-- process registered widgets
local widgetName, widgetObj;
for widgetName, widgetObj in pairs(obj.widgets) do
if(type(widgetObj.UpdateProps) == "function") then
widgetObj:UpdateProps();
end
if(widgetObj.type) then
if(widgetObj.enabled and string.match(widgetObj.type, obj.type)) then
widgetObj:Show();
local w, h = widgetObj:GetWidth(), widgetObj:GetHeight();
minWidth = _G.math.max(minWidth, (self:SafeGetLeft() - widgetObj:GetLeft()) + w + (widgetObj:GetRight() - self:SafeGetRight()));
minHeight = _G.math.max(minHeight, (self:SafeGetTop() - widgetObj:GetTop() - WindowParent:GetBottom()) + h + (widgetObj:GetBottom() - self:SafeGetBottom() - WindowParent:GetBottom()));
else
widgetObj:Hide()
end
end
end
self:SetMinResize(minWidth, minHeight);
self:SetWidth(_G.math.max(minWidth, self:GetWidth()));
self:SetHeight(_G.math.max(minHeight, self:GetHeight()));
self.initialized = true;
end
obj.Hide_Normal = obj.Hide;
obj.Hide = function(self, animate)
if(not self:IsShown() or self.animation.mode) then
-- don't do anything if window is already hidden.
return;
end
if(not animate) then
self:Hide_Normal();
self:ResetAnimation();
else
if(not db.winAnimation) then
self:Hide_Normal();
self:ResetAnimation();
else
self.widgets.chat_display:SetParent("UIParent");
self.widgets.chat_display:Hide();
local a = self.animation;
obj:SetClampedToScreen(false);
a.initLeft = self:SafeGetLeft();
a.initTop = self:SafeGetTop();
a.to = MinimapIcon or nil;
a.elapsed, a.time = 0, .5;
a.scaleLimit = .001 -- _G.math.max(_G.math.ceil((100-_G.UIParent:GetScale()*100)/2)/100 + .04, .01);
a.mode = "HIDE"; -- this starts the animation
dPrint("Animation Started: "..self:GetName());
end
end
end
obj.ResetAnimation = function(self)
if(self.animation.mode) then
self:SetClampedToScreen(not WindowParent.animUp and db.clampToScreen);
self:SetScale_Orig(db.winSize.scale/100);
self:ClearAllPoints();
self:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", self.animation.initLeft, self.animation.initTop - WindowParent:GetBottom());
self.widgets.chat_display:Show();
self.widgets.chat_display:SetParent(self);
dPrint("Animation Reset: "..self:GetName());
end
for key, _ in pairs(self.animation) do
self.animation[key] = nil;
end
end
obj.SafeGetLeft = function(self)
return self:GetLeft() - WindowParent:GetLeft();
end
obj.SafeGetRight = function(self)
return self:GetRight() - WindowParent:GetLeft();
end
obj.SafeGetTop = function(self)
return self:GetTop() - WindowParent:GetBottom();
end
obj.SafeGetBottom = function(self)
return self:GetBottom() - WindowParent:GetBottom();
end
-- enforce that all core widgets have parentWindow set.
local w;
for _, w in pairs(obj.widgets) do
w.parentWindow = obj;
end
-- load Registered Widgets
loadRegisteredWidgets(obj);
loadHandlers(obj);
-- local shortcuts = CreateFrame("Frame", fName.."ShortcutFrame", obj);
-- shortcuts:SetToplevel(true);
-- shortcuts:SetFrameStrata("DIALOG");
-- for i=1,ShortcutCount do
-- CreateFrame("Button", fName.."ShortcutFrameButton"..i, shortcuts, "WIM_ShortcutButtonTemplate");
-- end
end
local function placeWindow(win)
win:ClearAllPoints();
local lastWindow = nil;
for i=1, #windowsByAge do
if(windowsByAge[i] ~= win and windowsByAge[i]:IsShown() and windowsByAge[i].hasMoved == false) then
lastWindow = windowsByAge[i];
break;
end
end
if (not lastWindow or db.winCascade.enabled == false) or (db.tabs.whispers.enabled and win.type == "whisper") or (db.tabs.chat.enabled and win.type == "chat") then
win:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", db.winLoc.left/win:GetEffectiveScale(), (db.winLoc.top)/win:GetEffectiveScale());
else
local casc = cascadeDirection[db.winCascade.direction];
win:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", lastWindow:SafeGetLeft()+casc[1], lastWindow:SafeGetTop()+casc[2]);
end
end
-- load object into it's default state.
local function loadWindowDefaults(obj)
obj:Hide();
obj.age = _G.GetTime();
obj.hasMoved = false;
obj.lastActivity = _G.GetTime();
obj.customSize = false;
obj.guild = "";
obj.level = "";
obj.race = "";
obj.class = "";
obj.location = "";
obj.demoSave = nil;
obj.classColor = "ffffff";
obj.isGM = lists.gm[obj.theUser];
obj:UpdateIcon();
obj.isNew = true;
obj:SetScale(1);
obj:SetAlpha(1);
obj.widgets.Backdrop:SetAlpha(1);
obj.widgets.from:SetText(GetReadableName(obj.theUser));
obj.widgets.from:SetTextColor(RGBHexToPercent(GetSelectedSkin().message_window.widgets.from.font_color));
obj.widgets.char_info:SetText("");
obj.widgets.msg_box.setText = 0;
obj.widgets.msg_box:SetText("");
obj.widgets.msg_box:Show();
obj.widgets.chat_display:Clear();
obj.widgets.chat_display:AddMessage(" ");
obj.widgets.chat_display:AddMessage(" ");
updateScrollBars(obj);
obj.widgets.close.forceShift = false;
-- load Registered Widgets (if not created already) & set defaults
loadRegisteredWidgets(obj);
loadHandlers(obj);
-- process registered widgets
local widgetName, widgetObj;
for widgetName, widgetObj in pairs(obj.widgets) do
if(type(widgetObj.SetDefaults) == "function") then
widgetObj:SetDefaults();
end
end
ApplySkinToWindow(obj);
obj:UpdateProps();
placeWindow(obj);
end
-- Create (recycle if available) message window. Returns object.
-- (wtype == "whisper", "chat" or "w2w")
local function createWindow(userName, wtype)
if(type(userName) ~= "string") then
return;
end
-- if(type(WIM:GetSelectedSkin()) ~= "table") then
-- WIM:LoadSkin(WIM.db.skin.selected, WIM.db.skin.style);
-- end
local func = function ()
if(WindowSoupBowl.available > 0) then
local i;
for i=1,#WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse == false) then
return WindowSoupBowl.windows[i].obj, i;
end
end
else
return nil;
end
end
local obj, index = func();
if(obj) then
-- object available...
WindowSoupBowl.available = WindowSoupBowl.available - 1;
WindowSoupBowl.used = WindowSoupBowl.used + 1;
WindowSoupBowl.windows[index].inUse = true;
WindowSoupBowl.windows[index].user = userName;
obj.theUser = userName;
obj.type = wtype;
loadWindowDefaults(obj); -- clear contents of window and revert back to it's initial state.
dPrint("Window recycled '"..obj:GetName().."'");
CallModuleFunction("OnWindowCreated", obj);
table.insert(windowsByAge, obj);
table.sort(windowsByAge, function(a, b) return a.age > b.age; end);
return obj;
else
-- must create new object
WindowSoupBowl.used = WindowSoupBowl.used + 1;
WindowSoupBowl.windowToken = WindowSoupBowl.windowToken + 1; -- increment token for propper frame name creation.
local fName = "WIM3_msgFrame"..WindowSoupBowl.windowToken;
local f = CreateFrame("Frame",fName, WindowParent);
local winTable = {
user = userName,
frameName = fName,
inUse = true,
obj = f
};
table.insert(WindowSoupBowl.windows, winTable);
f.theUser = userName;
f.type = wtype;
f.isParent = true;
instantiateWindow(f);
-- f.icon.theUser = userName;
loadWindowDefaults(f);
dPrint("Window created '"..f:GetName().."'");
CallModuleFunction("OnWindowCreated", f);
table.insert(windowsByAge, f);
table.sort(windowsByAge, function(a, b) return a.age > b.age; end);
return f;
end
end
-- Returns object, SoupBowl_windows_index or nil if window can not be found.
local function getWindowByName(userName)
if(type(userName) ~= "string") then
return nil;
end
for i=1,#WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].user == userName) then
return WindowSoupBowl.windows[i].obj, i;
end
end
end
-- Deletes message window and makes it available in the Soup Bowl.
local function destroyWindow(userNameOrObj)
local obj, index;
if(type(userNameOrObj) == "string") then
obj, index = getWindowByName(userNameOrObj);
else
obj, index = getWindowByName(userNameOrObj.theUser);
end
if(obj) then
if(obj.tabStrip) then
obj.tabStrip:Detach(obj);
end
WindowSoupBowl.windows[index].inUse = false;
WindowSoupBowl.windows[index].user = "";
WindowSoupBowl.available = WindowSoupBowl.available + 1;
WindowSoupBowl.used = WindowSoupBowl.used - 1;
obj:Show();
obj.widgets.chat_display:Clear();
obj:Hide();
obj.initialized = nil;
dPrint("Window '"..obj:GetName().."' destroyed.");
CallModuleFunction("OnWindowDestroyed", obj);
removeFromTable(windowsByAge, obj);
end
end
function RegisterWidgetTrigger(WidgetName, wType, HandlerName, Function)
-- config table to handle widget
if(not Widget_Triggers[WidgetName]) then
Widget_Triggers[WidgetName] = {}
end
-- config widget table to handle hander
if(not Widget_Triggers[WidgetName][HandlerName]) then
Widget_Triggers[WidgetName][HandlerName] = {
whisper = {},
chat = {},
w2w = {},
demo = {},
};
end
-- register to table
for i=1,select("#", string.split(",", wType)) do
table.insert(Widget_Triggers[WidgetName][HandlerName][select(i, string.split(",", wType))], Function);
end
updateActiveObjects();
end
function GetWindowSoupBowl()
return WindowSoupBowl;
end
function CreateWhisperWindow(playerName)
return createWindow(playerName, "whisper");
end
function CreateChatWindow(chatName)
return createWindow(chatName, "chat");
end
function CreateW2WWindow(chatName)
return createWindow(chatName, "w2w");
end
function DestroyWindow(playerNameOrObject)
destroyWindow(playerNameOrObject);
end
function ShowDemoWindow()
if(options.frame and options.frame:IsShown()) then
options.frame:Disable();
if(not WIM.DemoWindow) then
WIM.DemoWindow = createWindow(L["Demo Window"], "demo");
end
WIM.DemoWindow:Show();
WIM.DemoWindow.demoSave = true;
end
end
function RegisterWidget(widgetName, createFunction, moduleName)
-- moduleName is optional if not being called from a module.
-- including module name will force the UI to be reloaded before removing the widgets.
RegisteredWidgets[widgetName] = createFunction;
if(moduleName) then
modules[moduleName].hasWidget = true;
end
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse) then
loadRegisteredWidgets(WindowSoupBowl.windows[i].obj);
end
end
updateActiveObjects();
end
-- iterator: All loaded widgets
function Widgets(widgetName)
local index = 1
return function()
for i=index, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].obj.widgets[widgetName]) then
index = i+1;
return WindowSoupBowl.windows[i].obj.widgets[widgetName];
end
end
end
end
function RegisterStringModifier(fun, prioritize)
addToTableUnique(StringModifiers, fun, prioritize);
end
function UnregisterStringModifier(fun)
removeFromTable(StringModifiers, fun);
end
function RegisterMessageFormatting(name, fun)
table.insert(FormattingCalls, {
name = name,
fun = fun
});
table.insert(FormattingCallsList, name);
end
function GetMessageFormattingList()
return FormattingCallsList;
end
function HideAllWindows(type)
ShowContainer();
type = type and string.lower(type) or nil;
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse and WindowSoupBowl.windows[i].obj.type == (type or WindowSoupBowl.windows[i].obj.type)) then
WindowSoupBowl.windows[i].obj:Hide(true);
end
end
end
local showAllTbl = {};
function ShowAllWindows(type)
type = type and string.lower(type) or nil;
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse and WindowSoupBowl.windows[i].obj.type == (type or WindowSoupBowl.windows[i].obj.type)) then
local obj = WindowSoupBowl.windows[i] and WindowSoupBowl.windows[i].obj;
if(obj.tabStrip and #obj.tabStrip.attached > 1) then
if(addToTableUnique(showAllTbl, obj.tabStrip)) then
obj.tabStrip.selected.obj:Pop(true);
end
else
WindowSoupBowl.windows[i].obj:Pop(true);
end
end
end
-- clean table
for key, _ in pairs(showAllTbl) do
showAllTbl[key] = nil;
end
end
local showAllUnreadTbl = {};
function ShowAllUnreadWindows(type)
type = type and string.lower(type) or nil;
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse and WindowSoupBowl.windows[i].obj.type == (type or WindowSoupBowl.windows[i].obj.type)) then
local obj = WindowSoupBowl.windows[i] and WindowSoupBowl.windows[i].obj;
if(obj and obj.unreadCount and obj.unreadCount > 0) then
if(obj.tabStrip) then
if(addToTableUnique(showAllUnreadTbl, obj.tabStrip)) then
WindowSoupBowl.windows[i].obj:Pop(true);
end
else
WindowSoupBowl.windows[i].obj:Pop(true);
end
end
end
end
-- clean table
for key, _ in pairs(showAllUnreadTbl) do
showAllUnreadTbl[key] = nil;
end
end
function UpdateAllWindowProps()
for i=1, #WindowSoupBowl.windows do
if(WindowSoupBowl.windows[i].inUse) then
WindowSoupBowl.windows[i].obj:UpdateProps();
end
end
end
function AddEscapeWindow(frame)
for i=1, #_G.UISpecialFrames do
if(_G.UISpecialFrames[i] == frame:GetName()) then
return;
end
end
table.insert(_G.UISpecialFrames, frame:GetName());
end
function RemoveEscapeWindow(frame)
for i=1, #_G.UISpecialFrames do
if(_G.UISpecialFrames[i] == frame:GetName()) then
table.remove(_G.UISpecialFrames, i);
return;
end
end
end
------------------------------------
-- WindowParent - Container Calls --
------------------------------------
local function WindowParent_AnimPos(self, fraction)
if(db.expose.direction == 1) then
-- UP
return "BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", 0, fraction*(_G.UIParent:GetHeight());
elseif(db.expose.direction == 2) then
-- DOWN
return "BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", 0, -fraction*(_G.UIParent:GetHeight());
elseif(db.expose.direction == 3) then
-- LEFT
return "BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", -fraction*(_G.UIParent:GetWidth()), 0;
elseif(db.expose.direction == 4) then
-- RIGHT
return "BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", fraction*(_G.UIParent:GetWidth()), 0;
end
end
local WindowParentAnimTable = {
totalTime = 0.5,
updateFunc = "SetPoint",
getPosFunc = WindowParent_AnimPos,
}
local function WindowParent_AnimFinished(self)
self.animFinished = true;
if(self.animUp) then
self:Hide();
else
self:SetPoint("BOTTOMLEFT", _G.UIParent, "BOTTOMLEFT", 0, 0);
self:SetWidth(_G.UIParent:GetWidth());
self:SetHeight(_G.UIParent:GetHeight());
end
for i=1, #WindowSoupBowl.windows do
local win = WindowSoupBowl.windows[i].obj;
win:SetClampedToScreen(not self.animUp and db.clampToScreen);
if(win:IsVisible()) then
WIM.CallModuleFunction("OnWindowShow", win);
end
end
end
function ShowContainer(animate)
if(not WindowParent.animUp) then
return;
end
WindowParent:Show();
WindowParent.animUp = false;
if(animate) then
WindowParentAnimTable.totalTime = 0.3;
else
WindowParentAnimTable.totalTime = 0;
end
WindowParent.animFinished = false;
WindowParent.inSequence = true;
--[[for i=1, #WindowSoupBowl.windows do
local win = WindowSoupBowl.windows[i].obj;
win:SetClampedToScreen(false);
local left, top = win:SafeGetLeft(), win:SafeGetTop()*win:GetScale();
win:ClearAllPoints();
win:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", left, top);
win:SetClampedToScreen(false);
end]]
if(animate) then
WIM.SetUpAnimation(WindowParent, WindowParentAnimTable, WindowParent_AnimFinished, true);
else
WindowParent:SetPoint(WindowParent_AnimPos(WindowParent, 100));
WindowParent_AnimFinished(WindowParent);
end
WIM.CallModuleFunction("OnContainerShow");
end
function HideContainer(animate)
if(WindowParent.animUp) then
return;
end
WindowParent.animUp = true;
if(animate) then
WindowParentAnimTable.totalTime = 0.3;
else
WindowParentAnimTable.totalTime = 0;
end
WindowParent.animFinished = false;
WindowParent.inSequence = true;
for i=1, #WindowSoupBowl.windows do
local win = WindowSoupBowl.windows[i].obj;
win:SetClampedToScreen(false);
local left, top = win:SafeGetLeft(), win:SafeGetTop();
win:ClearAllPoints();
win:SetPoint("TOPLEFT", WindowParent, "BOTTOMLEFT", left, top);
win:SetClampedToScreen(false);
end
if(animate) then
WIM.SetUpAnimation(WindowParent, WindowParentAnimTable, WindowParent_AnimFinished, false);
else
WindowParent:SetPoint(WindowParent_AnimPos(WindowParent, 0));
WindowParent_AnimFinished(WindowParent);
end
WIM.CallModuleFunction("OnContainerHide");
end
function ToggleContainer(animate)
if(WindowParent.animUp) then
ShowContainer(animate);
else
HideContainer(animate);
end
end
----------------------------------
-- Set default widget triggers --
----------------------------------
RegisterWidgetTrigger("close", "whisper,chat,w2w", "OnEnter", function(self)
if(db.showToolTips == true) then
_G.GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
_G.GameTooltip:SetText(L["<Shift-Click> to close window."]);
end
end);
RegisterWidgetTrigger("close", "whisper,chat,w2w", "OnLeave", function(self) _G.GameTooltip:Hide(); end);
RegisterWidgetTrigger("close", "whisper,chat,w2w,demo", "OnClick", function(self)
if(IsShiftKeyDown() or self.forceShift or self.parentWindow.type == "demo") then
self.forceShift = false;
destroyWindow(self:GetParent());
else
-- DisplayTutorial(L["Message Window Hidden"], L["WIM's message window has been hidden to WIM's Minimap Icon. If you want to end a conversation, you may do so by <Shift-Clicking> the close button."]);
self:GetParent():Hide(true);
end
end);
RegisterWidgetTrigger("close", "whisper,chat,w2w", "OnUpdate", function(self)
local SelectedSkin = WIM:GetSelectedSkin();
if(GetMouseFocus() == self) then
if(IsShiftKeyDown() and self.curTextureIndex == 1) then
self:SetNormalTexture(SelectedSkin.message_window.widgets.close.state_close.NormalTexture);
self:SetPushedTexture(SelectedSkin.message_window.widgets.close.state_close.PushedTexture);
self:SetHighlightTexture(SelectedSkin.message_window.widgets.close.state_close.HighlightTexture, SelectedSkin.message_window.widgets.close.state_close.HighlightAlphaMode);
self.curTextureIndex = 2;
elseif(not IsShiftKeyDown() and self.curTextureIndex == 2) then
self:SetNormalTexture(SelectedSkin.message_window.widgets.close.state_hide.NormalTexture);
self:SetPushedTexture(SelectedSkin.message_window.widgets.close.state_hide.PushedTexture);
self:SetHighlightTexture(SelectedSkin.message_window.widgets.close.state_hide.HighlightTexture, SelectedSkin.message_window.widgets.close.state_hide.HighlightAlphaMode);
self.curTextureIndex = 1;
end
elseif(self.curTextureIndex == 2) then
self:SetNormalTexture(SelectedSkin.message_window.widgets.close.state_hide.NormalTexture);
self:SetPushedTexture(SelectedSkin.message_window.widgets.close.state_hide.PushedTexture);
self:SetHighlightTexture(SelectedSkin.message_window.widgets.close.state_hide.HighlightTexture, SelectedSkin.message_window.widgets.close.state_hide.HighlightAlphaMode);
self.curTextureIndex = 1;
end
end);
RegisterWidgetTrigger("scroll_up", "whisper,chat,w2w", "OnClick", function(self)
local obj = self:GetParent();
if( _G.IsControlKeyDown() ) then
obj.widgets.chat_display:ScrollToTop();
else
if( _G.IsShiftKeyDown() ) then
obj.widgets.chat_display:PageUp();
else
obj.widgets.chat_display:ScrollUp();
end
end
updateScrollBars(obj);
end);
RegisterWidgetTrigger("scroll_down", "whisper,chat,w2w", "OnClick", function(self)
local obj = self:GetParent();
if( _G.IsControlKeyDown() ) then
obj.widgets.chat_display:ScrollToBottom();
else
if( _G.IsShiftKeyDown() ) then
obj.widgets.chat_display:PageDown();
else
obj.widgets.chat_display:ScrollDown();
end
end
updateScrollBars(obj);
end);
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w", "OnMouseWheel", function(self, ...)
if(select(1, ...) > 0) then
if( _G.IsControlKeyDown() ) then
self:ScrollToTop();
else
if( _G.IsShiftKeyDown() ) then
self:PageUp();
else
self:ScrollUp();
end
end
else
if( _G.IsControlKeyDown() ) then
self:ScrollToBottom();
else
if( _G.IsShiftKeyDown() ) then
self:PageDown();
else
self:ScrollDown();
end
end
end
updateScrollBars(getParentMessageWindow(self));
end);
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w,demo", "OnMouseDown", function(self)
self:GetParent().prevLeft = self:GetParent():SafeGetLeft();
self:GetParent().prevTop = self:GetParent():SafeGetTop();
MessageWindow_MovementControler_OnDragStart(self);
end);
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w,demo", "OnMouseUp", function(self)
MessageWindow_MovementControler_OnDragStop(self);
if(self.parentWindow ~= DemoWindow) then
self:Hide();
self:Show();
end
if(self:GetParent().prevLeft == self:GetParent():SafeGetLeft() and self:GetParent().prevTop == self:GetParent():SafeGetTop() and self.parentWindow ~= DemoWindow) then
--[ Frame was clicked not dragged
local msg_box = self:GetParent().widgets.msg_box;
if(EditBoxInFocus == nil) then
msg_box:SetFocus();
else
if(EditBoxInFocus == msg_box) then
msg_box:Hide();
msg_box:Show();
else
msg_box:SetFocus();
end
end
end
end);
local myself = _G.UnitName("player")
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w", "OnHyperlinkClick", function(self, link, text, button)
local t,n,i = string.split(":", link)
if n == myself then
return
end
if link == "garrmission:weakauras" then
_G.SetItemRef(link, text, button, self);
else
_G.SetItemRef(link, text:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""), button, self);
end
end);
--RegisterWidgetTrigger("chat_display", "whisper,chat,w2w","OnMessageScrollChanged", function(self) updateScrollBars(self:GetParent()); end);
local lastTTlink
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w", "OnHyperlinkEnter", function(self, link)
local obj = self.parentWindow;
obj.isOnHyperLink = true;
if(db.hoverLinks) then
local t = string.match(link, "^(.-):")
if(t == "item" or t == "enchant" or t == "spell" or t == "quest") then
lastTTlink = t
_G.GameTooltip:SetOwner(_G.UIParent, "ANCHOR_CURSOR");
_G.GameTooltip:SetHyperlink(link);
_G.GameTooltip:Show();
end
end
end)
RegisterWidgetTrigger("chat_display", "whisper,chat,w2w", "OnHyperlinkLeave", function(self, link)
local obj = self.parentWindow;
obj.isOnHyperLink = false;
if(db.hoverLinks) then
local t = lastTTlink --string.match(link, "^(.-):")
if(t == "item" or t == "enchant" or t == "spell" or t == "quest") then
_G.GameTooltip:ClearLines()
_G.GameTooltip:Hide()
lastTTlink = nil
end
end
end)
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w,demo", "OnEnterPressed", function(self)
if(strsub(self:GetText(), 1, 1) == "/") then
EditBoxInFocus = nil;
_G.ChatFrame1EditBox:SetText(self:GetText());
_G.ChatEdit_SendText(_G.ChatFrame1EditBox, 1);
self:SetText("");
EditBoxInFocus = self;
else
if(self:GetText() == "") then
self:Hide();
self:Show();
return;
end
end
-- keep focus or not
if(self:GetParent():GetRuleSet().keepfocus) then
self:SetFocus();
else
self:Hide();
self:Show();
end
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w,demo", "OnEscapePressed", function(self)
self:SetText("");
self:Hide();
self:Show();
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w,demo", "OnUpdate", function(self)
if(self.setText == 1) then
self.setText = 0;
self:SetText(self.textToSet or "");
self.textToSet = "";
end
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnEditFocusGained", function(self)
EditBoxInFocus = self;
-- _G.ACTIVE_CHAT_EDIT_BOX = self; -- preserve linking abilities.
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnEditFocusLost", function(self)
EditBoxInFocus = nil;
-- _G.ACTIVE_CHAT_EDIT_BOX = nil;
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnMouseUp", function(self, button)
_G.CloseDropDownMenus();
if(button == "RightButton") then
PopContextMenu("MENU_MSGBOX", self);
else
-- DisplayTutorial(L["Right-Mouse Click!"], L["There might be useful tools hidden under the message box. Right-Click to see them!"]);
end
end);
RegisterWidgetTrigger("msg_box", "whisper,chat,w2w", "OnMouseDown", function(self, button)
MSG_CONTEXT_MENU_EDITBOX = self;
end);
RegisterWidgetTrigger("msg_box", "whisper,w2w", "OnTabPressed", function(self)
if(db.tabAdvance and not _G.IsShiftKeyDown()) then
-- Get the current whisper target
local win = getParentMessageWindow(self)
local whisperTarget = win.isBN and win.toonName or win.theUser
local chatType = win.isBN and "BN_WHISPER" or "WHISPER"
-- Lookup the next whisper target
local nextWhisperTarget = _G.ChatEdit_GetNextTellTarget(whisperTarget,chatType)
if nextWhisperTarget ~= "" then
local win = GetWhisperWindowByUser(nextWhisperTarget);
chatType = win.isBN and "BN_WHISPER" or "WHISPER"
win:Hide();
win:Pop(true); -- force popup
win.widgets.msg_box:SetFocus();
_G.ChatEdit_SetLastTellTarget(nextWhisperTarget,chatType);
end
end
end);
-- handle formatting options.
local function applyBracket(index)
if(db.formatting.bracketing.enabled) then
local tbl = lists.bracketing[db.formatting.bracketing.type];
return tbl[(index or 1)];
else
return "";
end
end
RegisterMessageFormatting(L["Default"], function(smf, event, ...)
local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 = ...;
arg11 = arg11 or 0;
local doColoredNames = constants.classes.GetColoredNameByChatEvent;
if(event == "CHAT_MSG_WHISPER") then
return applyBracket().."|Hplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and doColoredNames(event, ...) or arg2).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_WHISPER_INFORM") then
arg11 = arg11 or 0;
return applyBracket().."|Hplayer:".._G.UnitName("player")..":"..arg11.."|h"..(db.coloredNames and constants.classes.GetMyColoredName() or _G.UnitName("player")).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_BN_WHISPER") then
local win = smf.parentWindow;
local color;
if(win.bn.client == _G.BNET_CLIENT_WOW and constants.classes[win.bn.class] and constants.classes[win.bn.class].color) then
color = constants.classes[win.bn.class].color
color = string.len(color) == 6 and color or nil;
end
return applyBracket().."|HBNplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and color and "|cff"..color..arg2.."|r" or arg2).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_BN_WHISPER_INFORM") then
arg11 = arg11 or 0;
return applyBracket().."|Hplayer:".._G.UnitName("player")..":"..arg11.."|h"..(db.coloredNames and constants.classes.GetMyColoredName() or _G.UnitName("player")).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_AFK") then
return _G.format(L["%s is Away From Keyboard: %s"], applyBracket().."|Hplayer:"..arg2..":"..arg11.."|h"..arg2.."|h"..applyBracket(2), arg1);
elseif(event == "CHAT_MSG_DND") then
return _G.format(L["%s does not wish to be disturbed: %s"], applyBracket().."|Hplayer:"..arg2..":"..arg11.."|h"..arg2.."|h"..applyBracket(2), arg1);
elseif(event == "CHAT_MSG_GUILD" or event == "CHAT_MSG_OFFICER" or event == "CHAT_MSG_PARTY" or
event == "CHAT_MSG_RAID" or event == "CHAT_MSG_RAID_LEADER" or event == "CHAT_MSG_SAY" or event == "CHAT_MSG_PARTY_LEADER" or
event == "CHAT_MSG_CHANNEL" or event == "CHAT_MSG_INSTANCE_CHAT" or event == "CHAT_MSG_INSTANCE_CHAT_LEADER") then
return applyBracket().."|Hplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and doColoredNames(event, ...) or arg2).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_EMOTE") then
return "|Hplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and doColoredNames(event, ...) or arg2).."|h".." "..arg1;
elseif(event == "CHAT_MSG_TEXT_EMOTE") then
local user = "|Hplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and doColoredNames(event, ...) or arg2).."|h"
return arg1;
elseif(event == "CHAT_MSG_RAID_WARNING") then
return _G.RAID_WARNING.." "..applyBracket().."|Hplayer:"..arg2..":"..arg11.."|h"..(db.coloredNames and doColoredNames(event, ...) or arg2).."|h"..applyBracket(2)..": "..arg1;
elseif(event == "CHAT_MSG_CHANNEL_JOIN") then
return string.format(_G.CHAT_CHANNEL_JOIN_GET, arg2);
elseif(event == "CHAT_MSG_CHANNEL_LEAVE") then
return string.format(_G.CHAT_CHANNEL_LEAVE_GET, arg2);
elseif(event == "CHAT_MSG_CHANNEL_NOTICE_USER") then
if(_G.strlen(arg5) > 0) then
-- TWO users in this notice (E.G. x kicked y)
return _G.format(_G["CHAT_"..arg1.."_NOTICE"], arg8, arg4, arg2, arg5);
elseif ( arg1 == "INVITE" ) then
return _G.format(_G["CHAT_"..arg1.."_NOTICE"], arg4, arg2);
else
return _G.format(_G["CHAT_"..arg1.."_NOTICE"], arg8, arg4, arg2);
end
elseif(event == "CHAT_MSG_CHANNEL_NOTICE") then
return _G.format(_G["CHAT_"..arg1.."_NOTICE"], arg8, arg4);
else
return "Unknown event received...";
end
end);
-- handle escape to close windows
local escapeFrame = CreateFrame("Frame", "WIM_SpecialWindowMonitor")
table.insert(_G.UISpecialFrames, "WIM_SpecialWindowMonitor");
escapeFrame.Hide = function(self)
if(WindowParent.animUp or not (db and db.escapeToHide)) then
return nil; -- don't close windows if WindowParent is in use.
end
-- lets do some checks first shall we?
local stack = _G.debugstack(1);
if(stack:match("TOGGLEWORLDMAP")) then
-- we do not want to close the windows.
return;
elseif(stack:match("UIParent_OnEvent")) then
-- need some checks here. we want to close the windows at some point...
return;
end
for i=1, #WindowSoupBowl.windows do
local win = WindowSoupBowl.windows[i].obj;
if(win:IsShown()) then
win:Hide();
end
end
end
escapeFrame.IsShown = function(self)
if(WindowParent.animUp or not (db and db.escapeToHide)) then
return nil; -- don't close windows if WindowParent is in use.
end
for i=1, #WindowSoupBowl.windows do
local win = WindowSoupBowl.windows[i].obj;
if(win:IsVisible()) then
return 1;
end
end
return nil;
end
escapeFrame:Show();
-- define context menu
local info = _G.UIDropDownMenu_CreateInfo();
info.text = "MENU_MSGBOX";
local msgBoxMenu = AddContextMenu(info.text, info);
local info = _G.UIDropDownMenu_CreateInfo();
info.text = _G.CANCEL;
info.notCheckable = true;
info.func = function() _G.CloseDropDownMenus(); end
msgBoxMenu:AddSubItem(AddContextMenu("MENU_CANCEL", info));