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.

2481 lines
84 KiB

local INPSECT_CONFIG_ID = -1;
local HIDE_INACTIVE_NODE = false;
local USE_CLASS_BACKGROUND = false;
local _, addon = ...
local LoadingBarUtil = addon.TalentTreeLoadingBarUtil;
local ClassTalentTooltipUtil = addon.ClassTalentTooltipUtil;
local DataProvider = addon.TalentTreeDataProvider;
local OnEnterDelay = addon.TalentTreeOnEnterDelay;
local TextButtonUtil = addon.TalentTreeTextButtonUtil;
local TextureUtil = addon.TalentTreeTextureUtil;
local UniversalFont = addon.UniversalFontUtil.Create();
local NodeUtil = addon.TalentTreeNodeUtil;
--local ActionBarUtil = addon.TalentTreeActionBarUtil;
local L = Narci.L;
do
local playerNameFonts = {
rm = "Interface\\AddOns\\Narcissus\\Font\\SourceSansPro-Semibold.ttf",
cn = "Interface\\AddOns\\Narcissus\\Font\\NotoSansCJKsc-Medium.otf",
ru = "Interface\\AddOns\\Narcissus\\Font\\NotoSans-Medium.ttf",
};
UniversalFont:SetFonts(playerNameFonts);
UniversalFont:SetFontStyle("");
UniversalFont:CheckFirstLetterOnly(false);
end
local NarciAPI = NarciAPI;
local C_Traits = C_Traits;
local C_ClassTalents = C_ClassTalents;
local C_SpecializationInfo = C_SpecializationInfo;
local C_PvP = C_PvP;
local CAN_USE_TALENT_UI = true;
local CanPlayerUseTalentSpecUI = C_SpecializationInfo.CanPlayerUseTalentSpecUI;
local GetSpecializationInfoByID = GetSpecializationInfoByID;
local GetInspectSpecialization = GetInspectSpecialization;
local UnitClass = UnitClass;
local UnitSex = UnitSex;
local UnitLevel = UnitLevel;
local IsSpecializationActivateSpell = IsSpecializationActivateSpell;
local sqrt = math.sqrt;
local atan2 = math.atan2;
local ipairs = ipairs;
local floor = math.floor;
local BUTTON_PIXEL_SIZE = 32;
local ICON_PIXEL_SIZE = 24;
local FONT_PIXEL_SIZE = 16;
do
local function ChangePixelSize(sizeInfo)
BUTTON_PIXEL_SIZE = sizeInfo.buttonSize;
ICON_PIXEL_SIZE = sizeInfo.iconSize;
FONT_PIXEL_SIZE = sizeInfo.fontHeight;
end
addon.TalentTreeTextureUtil:AddSizeChangedCallback(ChangePixelSize);
end
local DISTANCE_UNIT = 300; --600 --neighboring node distance 600
local PADDING = 1;
local HEADER_SIZE;
local SECTOR_WIDTH = 11; --the width of each tab (spec talent, class talent). unit is button wdith.
local BUTTON_SIZE = 32;
local BUTTON_SIZE_HALF = BUTTON_SIZE * 0.5;
local BRANCH_WEIGHT = 1;
local ICON_SIZE = 24;
local FONT_HEIGHT = 16;
local PIXEL = 1;
local MainFrame;
local Nodes = {};
local Branches = {};
local NodeIDxNode = {};
local NodeHighlights = {};
local EventCenter = CreateFrame("Frame");
local LoadoutUtil = {};
local LayoutUtil = {};
LayoutUtil.editboxes = {};
function LayoutUtil:Reset()
self.leftMinX = 69;
self.leftMaxX = 0;
self.leftMinY = 69;
self.rightMinX = 69;
self.rightMaxX = 1;
self.rightMinY = 69;
end
function LayoutUtil:UpdateFrameSize()
local pvpFrameWidth = (MainFrame.PvPTalentFrame:IsShown() and 3*BUTTON_SIZE) or 0;
local w = BUTTON_SIZE * 2 * SECTOR_WIDTH + pvpFrameWidth;
local h = BUTTON_SIZE * (10 + 2*PADDING) + HEADER_SIZE;
self.frameWidth = w;
self.frameHeight = h;
MainFrame:SetSize(w, h);
self:UpdateArtworkTexCoord();
end
function LayoutUtil:UpdateArtworkTexCoord()
local l, r, t, b = TextureUtil:CalculateTexCoord(self.frameWidth, self.frameHeight, "right");
MainFrame.SpecArt:SetTexCoord(l, r, t, b);
l, r, t, b = TextureUtil:CalculateTexCoord(216 * PIXEL, self.frameHeight, "left");
MainFrame.SideTab.ClipFrame.SpecArt:SetTexCoord(l, r, t, b);
end
function LayoutUtil:UpdateNodePosition()
local tileSize = BUTTON_SIZE;
local container = MainFrame;
local leftMinY = self.leftMinY;
local leftMinX = self.leftMinX;
local leftMaxX = self.leftMaxX;
local leftSpanX = leftMaxX - leftMinX + 1;
local rightMinY = self.rightMinY;
local rightMinX = self.rightMinX;
local rightMaxX = self.rightMaxX;
local rightSpanX = rightMaxX - rightMinX + 1;
local leftFromOffsetX = (SECTOR_WIDTH - leftSpanX)*0.5*tileSize;
local rightFromOffsetX = ((SECTOR_WIDTH - rightSpanX)*0.5 + SECTOR_WIDTH) *tileSize;
local fromOffsetY = - HEADER_SIZE - tileSize;
local node, x, y;
for i = 1, MainFrame.numAcitveNodes do
node = Nodes[i];
node:ClearAllPoints();
y = -(node.iY - leftMinY) * tileSize + fromOffsetY;
if node.isLeft then
x = (node.iX - leftMinX) * tileSize + leftFromOffsetX;
--y = -(node.iY - leftMinY) * tileSize + fromOffsetY;
--node.Order:SetText(node.iX - leftMinX)
else
x = (node.iX - rightMinX) * tileSize + rightFromOffsetX;
--y = -(node.iY - rightMinY) * tileSize + fromOffsetY;
--node.Order:SetText(node.iX - rightMinX)
end
node:SetPoint("TOPLEFT", container, "TOPLEFT", x, y);
node.x, node.y = x, y;
end
--print("Left Span", leftSpanX);
--print("Right Span", rightSpanX);
local middleOffsetX = (0.5*(leftMaxX + rightMinX) - leftMinX) * tileSize + leftFromOffsetX;
return middleOffsetX, fromOffsetY
end
function LayoutUtil:SetNodeTileIndex(node, isLeft, iX, iY)
node.iX = iX;
node.iY = iY;
node.isLeft = isLeft or nil;
if isLeft then
if iX > self.leftMaxX then
self.leftMaxX = iX;
end
if iX < self.leftMinX then
self.leftMinX = iX;
end
if iY < self.leftMinY then
self.leftMinY = iY;
end
else
if iX > self.rightMaxX then
self.rightMaxX = iX;
end
if iX < self.rightMinX then
self.rightMinX = iX;
end
if iY < self.rightMinY then
self.rightMinY = iY;
end
end
end
function LayoutUtil:UpdatePixel()
local f = MainFrame;
local px = NarciAPI.GetPixelForWidget(f, 1);
PIXEL = px;
BRANCH_WEIGHT = 2 * px;
BUTTON_SIZE = px * BUTTON_PIXEL_SIZE;
ICON_SIZE = px * ICON_PIXEL_SIZE;
BUTTON_SIZE_HALF = BUTTON_SIZE * 0.5;
FONT_HEIGHT = FONT_PIXEL_SIZE * px;
HEADER_SIZE = FONT_HEIGHT + BUTTON_SIZE;
UniversalFont:SetFontHeight(FONT_HEIGHT);
LayoutUtil:UpdateFrameSize();
TextButtonUtil:UpdatePixel(px, FONT_PIXEL_SIZE);
ClassTalentTooltipUtil:UpdatePixel();
f.PvPTalentFrame:UpdatePixel();
f.SideTab:UpdatePixel(px);
--f.MacroForge:UpdatePixel(px);
f.Divider:ClearAllPoints();
f.Divider:SetPoint("TOPLEFT", f, "TOPLEFT", SECTOR_WIDTH * BUTTON_SIZE, -BUTTON_SIZE/2 -HEADER_SIZE);
f.Divider:SetPoint("BOTTOMLEFT", f, "BOTTOM", 0, BUTTON_SIZE/2);
if f.LoadoutToggle then
f.LoadoutToggle:ClearAllPoints();
f.LoadoutToggle:SetPoint("TOP", f, "TOPLEFT", SECTOR_WIDTH * BUTTON_SIZE, -BUTTON_SIZE);
f.SideTabToggle:ClearAllPoints();
f.SideTabToggle:SetPoint("TOPLEFT", f, "TOPLEFT", BUTTON_SIZE, -BUTTON_SIZE);
f.PvPTalentToggle:ClearAllPoints();
f.PvPTalentToggle:SetPoint("TOPRIGHT", f, "TOPRIGHT", -BUTTON_SIZE, -BUTTON_SIZE);
f.DisplayModeButton1:ClearAllPoints();
f.DisplayModeButton1:SetPoint("TOPRIGHT", f, "TOP", 0, -BUTTON_SIZE);
f.DisplayModeButton2:ClearAllPoints();
f.DisplayModeButton2:SetPoint("TOPLEFT", f, "TOP", 8, -BUTTON_SIZE);
f.SettingsButton:ClearAllPoints();
f.SettingsButton:SetPoint("BOTTOMLEFT", f.SideTab, "BOTTOMLEFT", 20*px, 20*px);
f.ShareToggle:ClearAllPoints();
f.ShareToggle:SetPoint("BOTTOMLEFT", f.SideTab, "BOTTOMLEFT", 20*px, (20 + 16*4)*px);
f.SaveButton:ClearAllPoints();
f.SaveButton:SetPoint("TOP", f.SaveButton.anchor, "BOTTOM", 0, -16*px);
end
for _, node in ipairs(Nodes) do
node.Icon:SetSize(ICON_SIZE, ICON_SIZE);
node:SetSize(BUTTON_SIZE, BUTTON_SIZE);
end
local highlightSize = 2*px*BUTTON_PIXEL_SIZE;
for _, hl in ipairs(NodeHighlights) do
hl:SetSize(highlightSize, highlightSize);
end
end
function LayoutUtil:ClearTemps()
for nodeID, node in pairs(NodeIDxNode) do
node.x = nil;
node.y = nil;
end
end
local function CalculateNormalizedPosition(posX, posY)
--posX = posX - 1800;
--posY = 1200 - posY;
--debug
posX = posX;
posY = -posY
posX = floor(posX/DISTANCE_UNIT + 0.5);
posY = floor(posY/DISTANCE_UNIT + 0.5);
posY = -posY;
posX = posX * 0.5;
posY = posY * 0.5;
local isLeftSide;
if posX >= 12.5 then
posX = posX - 2;
else
isLeftSide = true
end
return posX, posY, isLeftSide
end
local function SetBranchColorYellow(branch, isActive)
if isActive then
branch:SetVertexColor(0.72, 0.6, 0);
else
branch:SetVertexColor(0.200, 0.200, 0.200);
end
end
local function SetBranchColorCyan(branch, isActive)
if isActive then
branch:SetVertexColor(0, 0.53, 0.65);
else
branch:SetVertexColor(0.200, 0.200, 0.200);
end
end
local function SetBranchColorGrey(branch, isActive)
if isActive then
branch:SetVertexColor(0.67, 0.67, 0.67);
else
branch:SetVertexColor(0.200, 0.200, 0.200);
end
end
local SetBranchColor = SetBranchColorYellow;
local function ShouldHideBackground()
return IsPlayerMoving() or IsMouselooking()
end
local InspectDisplayModeUtil = {};
InspectDisplayModeUtil.buttons = {};
InspectDisplayModeUtil.onEnter = function(f)
if not f.selected then
f:SetAlpha(1)
end
end
InspectDisplayModeUtil.onLeave = function(f)
if not f.selected then
f:SetAlpha(0.5);
end
end
InspectDisplayModeUtil.onClick = function(f)
if not f.selected then
MainFrame:SetInspectDisplayMode(f.id);
end
end
function InspectDisplayModeUtil:SetupButton(button, id)
button:SetScript("OnEnter", self.onEnter);
button:SetScript("OnLeave", self.onLeave);
button:SetScript("OnClick", self.onClick);
button.iconPosition = "left";
button.id = id;
if id == 1 then
button.ButtonText:SetText("THEY");
button.Icon:SetVertexColor(0, 0.84, 1);
button.ButtonText:SetTextColor(0, 0.84, 1);
else
button.ButtonText:SetText("DIFF");
button.Icon:SetVertexColor(1, 0.82, 0);
button.ButtonText:SetTextColor(1, 0.82, 0);
end
if not self.buttons[id] then
self.buttons[id] = button;
end
end
function InspectDisplayModeUtil:SelectButton(id)
if not self.highlight then
self.highlight = MainFrame:CreateTexture(nil, "ARTWORK");
self.highlight:SetSize(64, 32);
self.highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\TextButtonHighlight");
self.highlight:SetBlendMode("ADD");
self.highlight:Hide();
end
if self.buttons[id] then
for i, b in ipairs(self.buttons) do
if b.id == id then
b.selected = true;
b:SetAlpha(1);
self.highlight:ClearAllPoints();
self.highlight:SetPoint("CENTER", b, "CENTER", -4, 0);
self.highlight:Show();
else
b.selected = nil;
b:SetAlpha(0.5);
end
end
end
end
function InspectDisplayModeUtil:SetButtonVisibility(state)
for i, b in ipairs(self.buttons) do
b:SetShown(state);
end
if self.highlight then
self.highlight:SetShown(state);
end
MainFrame.LoadoutToggle:SetShown(not state);
end
NarciMiniTalentTreeMixin = {};
function NarciMiniTalentTreeMixin:OnLoad()
MainFrame = self;
ClassTalentTooltipUtil:AssignMainFrame(self);
LayoutUtil:UpdatePixel();
self.HeaderLight:ClearAllPoints();
self.HeaderLight:SetPoint("TOP", self, "TOPLEFT", SECTOR_WIDTH * BUTTON_SIZE, 0);
self.HeaderLight:SetSize(SECTOR_WIDTH * BUTTON_SIZE * 2 , SECTOR_WIDTH * BUTTON_SIZE * 0.5, 0);
self.Divider:ClearAllPoints();
self.Divider:SetPoint("TOPLEFT", self, "TOPLEFT", SECTOR_WIDTH * BUTTON_SIZE, -BUTTON_SIZE/2 -HEADER_SIZE);
self.Divider:SetPoint("BOTTOMLEFT", self, "BOTTOM", 0, BUTTON_SIZE/2);
local frameLevel = self:GetFrameLevel();
self.LoadoutToggle = TextButtonUtil:CreateButton(self, "right", "center", "vertical", 96, "arrowDown");
self.LoadoutToggle:SetFrameLevel(frameLevel + 18);
self.LoadoutToggle.ButtonText:SetText(L["Loadout"]);
self.LoadoutToggle:SetScript("OnClick", function()
LoadoutUtil:ToggleList();
end);
self.SideTabToggle = TextButtonUtil:CreateButton(self, "left", "left", "horizontal", nil, "arrowRight");
self.SideTabToggle:SetFrameLevel(frameLevel + 20);
self.SideTabToggle.ButtonText:SetText(SPECIALIZATION or "Specialization");
self.SideTabToggle:SetScript("OnClick", function(f)
self.SideTab:ShowFrame();
end);
self.MotionBlocker:SetFrameLevel(frameLevel + 19);
self.PvPTalentToggle = TextButtonUtil:CreateButton(self, "right", "right", "horizontal", nil, "arrowRight");
self.PvPTalentToggle:SetFrameLevel(frameLevel + 14);
self.PvPTalentToggle.ButtonText:SetText(L["PvP"]);
self.PvPTalentToggle:SetScript("OnClick", function(f)
self.PvPTalentFrame:Toggle();
end);
self.DisplayModeButton1 = TextButtonUtil:CreateButton(self, "left", "left", "vertical", 40, "inspectNode");
self.DisplayModeButton1:SetFrameLevel(frameLevel + 14);
self.DisplayModeButton1:Hide();
InspectDisplayModeUtil:SetupButton(self.DisplayModeButton1, 1);
self.DisplayModeButton2 = TextButtonUtil:CreateButton(self, "left", "left", "vertical", 40, "diffNode");
self.DisplayModeButton2:SetFrameLevel(frameLevel + 14);
self.DisplayModeButton2:Hide();
InspectDisplayModeUtil:SetupButton(self.DisplayModeButton2, 2);
InspectDisplayModeUtil:SelectButton(1);
self.SettingsButton = TextButtonUtil:CreateButton(self.SideTab, "left", "left", "horizontal", nil, "cog");
self.SettingsButton.ButtonText:SetText(SETTINGS or "Settings");
self.SettingsButton:SetPoint("BOTTOMLEFT", self.SideTab, "BOTTOMLEFT", 16, 16);
self.SettingsButton:SetScript("OnClick", function()
if not NarciSettingsFrame:IsShown() then
NarciSettingsFrame:ShowUI("talentTree", true, "talents");
end
end);
self.ShareToggle = TextButtonUtil:CreateButton(self.SideTab, "left", "left", "horizontal", nil, "share");
self.ShareToggle.ButtonText:SetText(L["Share"]);
self.ShareToggle:SetPoint("BOTTOMLEFT", self.SideTab, "BOTTOMLEFT", 16, 48);
self.ShareToggle:SetScript("OnClick", function(f)
f:Hide();
self.SideTab:TakeClipboard(true);
end);
local SaveButton = TextButtonUtil:CreateButton(self.SideTab, "left", "center", "horizontal", nil, "plus");
SaveButton.anchor = self.SideTab.InspectTab.LoadoutNameEditBox;
self.SaveButton = SaveButton;
self.SideTab.InspectTab.LoadoutNameEditBox.SaveButton = SaveButton;
SaveButton.ButtonText:SetText(L["Save"]);
SaveButton:SetPoint("TOP", SaveButton.anchor, "BOTTOM", 0, -8);
SaveButton:Hide();
function SaveButton:CaseValid()
self:Enable();
self.ButtonText:SetText(L["Save"]);
TextButtonUtil:SetButtonIcon(self, "plus");
TextButtonUtil:SetButtonColor(self, 0.5, 0.5, 0.5);
end
function SaveButton:CaseDuplicate()
self:Disable();
self.ButtonText:SetText("Duplicate Name");
TextButtonUtil:SetButtonIcon(self, "cross");
TextButtonUtil:SetButtonColor(self, 1, 0.31, 0.31);
end
function SaveButton:CaseSaved()
self:Disable();
self.ButtonText:SetText("Saved");
TextButtonUtil:SetButtonIcon(self, "check");
TextButtonUtil:SetButtonColor(self, 0.4862, 0.7725, 0.4627);
end
SaveButton:SetScript("OnClick", function(f)
local loadoutName = SaveButton.anchor:GetText();
local result, errorString = DataProvider:SaveInpsectLoadout(loadoutName);
if result then
f:CaseSaved();
else
f:Disable();
f.ButtonText:SetText(errorString);
end
end);
self.AnimationFrame.ShockwaveMask:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Masks\\Full", "CLAMPTOBLACKADDITIVE", "CLAMPTOBLACKADDITIVE", "NEAREST");
self.AnimationFrame:Hide();
self.AnimationFrame:SetScript("OnUpdate", function(f, elapsed)
f.t = f.t + elapsed;
if f.t > 2 then
f:Hide();
f.t = nil;
end
end);
end
function NarciMiniTalentTreeMixin:Init()
if self.PvPTalentFrame:IsWarModeActive() then
self.PvPTalentFrame:Toggle();
end
self.Init = nil;
end
function NarciMiniTalentTreeMixin:ShowActiveBuild()
local configID = DataProvider:GetSelecetdConfigID();
DataProvider:SetPlayerActiveConfigID(configID);
self:ShowConfig(configID);
end
local function IsValidEntryType(entryType)
return entryType == nil or entryType == 0 or entryType == 1 or entryType == 2
end
local function IsValidNodeInfo(nodeInfo)
return (nodeInfo) and (nodeInfo.type ~= 3) and (nodeInfo.isVisible) and (nodeInfo.posY >= 0) and (not nodeInfo.subTreeID)
end
local function IsSubTreeNode(nodeInfo, activeSubTreeID)
if nodeInfo and nodeInfo.isVisible and nodeInfo.subTreeID then
if activeSubTreeID then
return nodeInfo.subTreeID == activeSubTreeID
else
return true
end
end
end
local function SortFunc_SubTreeNode(a, b)
if a.posY ~= b.posY then
return a.posY > b.posY
end
return a.posX < b.posX
end
function NarciMiniTalentTreeMixin:ShowConfig(configID, isPreviewing)
if not configID then return end;
if not( (self.isDirty) or (configID ~= self.configID) ) then
return
end
self.configID = configID;
self.isDirty = nil;
local isInspecting = self:IsInspecting() and (configID == INPSECT_CONFIG_ID);
local canShowComparison = isInspecting and DataProvider:IsInpsectSameSpec();
local comparisonMode = self.showTalentDifferences and canShowComparison; --if the inspected unit and player have the same spec
InspectDisplayModeUtil:SetButtonVisibility(canShowComparison);
self:ReleaseAllNodes();
local specID = DataProvider:GetCurrentSpecID();
local configInfo = C_Traits.GetConfigInfo(configID);
if not configInfo then
return
end
local treeID = configInfo.treeIDs[1]
local nodeIDs = C_Traits.GetTreeNodes(treeID);
self.treeID = treeID;
local activeSubTreeID;
local node, nodeInfo, activeEntryID, entryInfo, entryType, iX, iY, isLeftSide;
local GetNodeInfo, GetEntryInfo;
local borderColor;
if isInspecting then
borderColor = 2;
GetNodeInfo = DataProvider.GetComparisonNodeInfo;
GetEntryInfo = DataProvider.GetComparisonEntryInfo;
activeSubTreeID = DataProvider:GetInspectActiveSubTreeID();
else
borderColor = 1;
DataProvider:SetPlayerActiveConfigID(configID);
GetNodeInfo = DataProvider.GetPlayerNodeInfo;
GetEntryInfo = DataProvider.GetPlayerEntryInfo;
activeSubTreeID = DataProvider:GetPlayerActiveSubTreeID();
end
if not comparisonMode then
for i, nodeID in ipairs(nodeIDs) do
nodeInfo = GetNodeInfo(nodeID);
if IsValidNodeInfo(nodeInfo) then ----Dracthyr has a Button that is out-of-bound for some reason
activeEntryID = nodeInfo.activeEntry and nodeInfo.activeEntry.entryID or nil;
entryInfo = (activeEntryID ~= nil) and GetEntryInfo(activeEntryID) or nil;
entryType = (entryInfo ~= nil) and entryInfo.type or nil;
if IsValidEntryType(entryType) then
node = self:AcquireNode();
node:SetBorderColor(borderColor);
iX, iY, isLeftSide = CalculateNormalizedPosition(nodeInfo.posX, nodeInfo.posY);
if (nodeInfo.ranksPurchased > 0) or (nodeInfo.activeRank > 0) or (DataProvider:IsAutoGrantedTalent(nodeID)) then
--ranksPurchased is 0 for freely-granted talent (some talent in the first row)
node.active = true;
if nodeInfo.ranksPurchased == 0 then
node.currentRank = 1;
else
node.currentRank = nodeInfo.ranksPurchased;
end
else
if HIDE_INACTIVE_NODE then
node:Hide();
end
node.active = nil;
node.currentRank = 0;
end
node.maxRanks = nodeInfo.maxRanks;
LayoutUtil:SetNodeTileIndex(node, isLeftSide, iX, iY);
NodeIDxNode[nodeID] = node;
if nodeInfo.type == 2 then
node.entryIDs = nodeInfo.entryIDs;
if activeEntryID == nodeInfo.entryIDs[1] then
node:SetNodeType(2, 1);
elseif activeEntryID == nodeInfo.entryIDs[2] then
node:SetNodeType(2, 2);
else
node:SetNodeType(2, 0);
node.Icon:SetTexture(nil);
end
else
node.entryIDs = nil;
if entryType == 0 then
--*Warrior Why do some passive traits use this type?
node:SetNodeType(1, 0);
elseif entryType == 1 then --square
node:SetNodeType(0, 1);
elseif entryType == 2 then --circle
if nodeInfo.type == 0 then
if nodeInfo.maxRanks == 1 then --1/1
node:SetNodeType(1, 0);
elseif nodeInfo.maxRanks == 2 then
if nodeInfo.ranksPurchased == 1 then --1/2
node:SetNodeType(1, 1);
else --2/2
node:SetNodeType(1, 0);
end
elseif nodeInfo.maxRanks == 3 then
if nodeInfo.ranksPurchased == 1 then --1/3
node:SetNodeType(1, 1);
elseif nodeInfo.ranksPurchased == 2 then --2/3
node:SetNodeType(1, 2);
else --3/3
node:SetNodeType(1, 0);
end
else
--0/4?
node.Symbol:SetVertexColor(1, 0, 0);
node:SetNodeType(1, 0);
end
else
node:Hide();
end
else
--nil is unselected octagon
node.Symbol:SetVertexColor(1, 0, 0);
--print(entryType, "Unknown type")
end
end
if node.active then
node.Symbol:SetVertexColor(0.67, 0.67, 0.67);
node:SetActive(true);
else
node.Symbol:SetVertexColor(0.160, 0.160, 0.160);
node:SetActive(false);
end
if entryInfo then
node:SetDefinitionID(entryInfo.definitionID);
end
node.nodeID = nodeID;
node.entryID = activeEntryID;
node.rank = nodeInfo.ranksPurchased;
end
end
end
self:CreateBranches(nodeIDs);
else
local playerNodeInfo, playerEntryInfo, playerEntryID;
local GetPlayerNodeInfo = DataProvider.GetPlayerNodeInfo;
local GetPlayerEntryInfo = DataProvider.GetPlayerEntryInfo;
local playerRank, targetRank;
local playerChoice, targetChoice;
local nodeTypeID; --custom value
for i, nodeID in ipairs(nodeIDs) do
nodeInfo = GetNodeInfo(nodeID);
playerNodeInfo = GetPlayerNodeInfo(nodeID);
if IsValidNodeInfo(nodeInfo) then ----Dracthyr has a Button that is out-of-bound for some reason
activeEntryID = nodeInfo.activeEntry and nodeInfo.activeEntry.entryID or nil;
entryInfo = (activeEntryID ~= nil) and GetEntryInfo(activeEntryID) or nil;
entryType = (entryInfo ~= nil) and entryInfo.type or nil;
if IsValidEntryType(entryType) then
playerEntryID = playerNodeInfo.activeEntry and playerNodeInfo.activeEntry.entryID or nil;
playerEntryInfo = (playerEntryID ~= nil) and GetPlayerEntryInfo(playerEntryID) or nil;
node = self:AcquireNode();
iX, iY, isLeftSide = CalculateNormalizedPosition(nodeInfo.posX, nodeInfo.posY);
targetRank = nodeInfo.ranksPurchased or 0;
playerRank = playerNodeInfo.ranksPurchased or 0;
if DataProvider:IsAutoGrantedTalent(nodeID) then
targetRank = 1;
playerRank = 1;
end
if targetRank == playerRank then
node.active = nil;
node.currentRank = targetRank;
else
if nodeInfo.ranksPurchased == 0 then
node.currentRank = 1;
else
node.currentRank = nodeInfo.ranksPurchased;
end
node.active = (targetRank > 0) or (playerRank > 0);
end
node:SetBorderColor(3);
node.maxRanks = nodeInfo.maxRanks;
LayoutUtil:SetNodeTileIndex(node, isLeftSide, iX, iY);
NodeIDxNode[nodeID] = node;
if nodeInfo.type == 2 then
node.entryIDs = nodeInfo.entryIDs;
if activeEntryID == nodeInfo.entryIDs[1] then
targetChoice = 1;
elseif activeEntryID == nodeInfo.entryIDs[2] then
targetChoice = 2;
else
targetChoice = 0;
end
if playerEntryID == playerNodeInfo.entryIDs[1] then
playerChoice = 1;
elseif playerEntryID == playerNodeInfo.entryIDs[2] then
playerChoice = 2;
else
playerChoice = 0;
end
if targetChoice ~= playerChoice and targetChoice ~= 0 then
node.active = true;
end
node:SetComparison(2, targetChoice, playerChoice);
if targetChoice == 0 and playerChoice ~= 0 and playerEntryInfo then
node:SetDefinitionID(playerEntryInfo.definitionID);
end
else
node.entryIDs = nil;
if entryType == 0 then
nodeTypeID = 1;
elseif entryType == 1 then --square
nodeTypeID = 0;
elseif entryType == 2 then --circle
nodeTypeID = 1;
else
nodeTypeID = 2;
--nil is unselected octagon
node.Symbol:SetVertexColor(1, 0, 0);
--print(entryType, "Unknown type")
end
node:SetComparison(nodeTypeID, targetRank, playerRank);
end
if node.active then
node.Symbol:SetVertexColor(0.67, 0.67, 0.67);
node.IconBorder:SetDesaturated(false);
node.IconBorder:SetVertexColor(1, 1, 1);
node.Icon:SetDesaturation(0.5);
node.Icon:SetVertexColor(0.67, 0.67, 0.67);
node.isActive = nil;
else
node.Symbol:SetVertexColor(0.160, 0.160, 0.160);
node:SetActive(false);
end
if entryInfo then
node:SetDefinitionID(entryInfo.definitionID);
end
node.nodeID = nodeID;
node.entryID = activeEntryID;
node.rank = targetRank;
if playerRank == 0 and targetRank == 0 then
node.Icon:SetTexture(nil);
end
end
end
end
self:RemoveBranches();
end
local middleX, middleY = LayoutUtil:UpdateNodePosition();
--Subtree
local subTreeNodes;
for i, nodeID in ipairs(nodeIDs) do
nodeInfo = GetNodeInfo(nodeID);
if IsSubTreeNode(nodeInfo, activeSubTreeID) then
--Only Show Choice Node
if nodeInfo.type == 2 then
activeEntryID = nodeInfo.activeEntry and nodeInfo.activeEntry.entryID;
if activeEntryID then
entryInfo = GetEntryInfo(activeEntryID);
if entryInfo and entryInfo.definitionID then
if not subTreeNodes then
subTreeNodes = {};
end
table.insert(subTreeNodes, {
nodeID = nodeID,
entryID = activeEntryID;
entryIDs = nodeInfo.entryIDs,
definitionID = entryInfo.definitionID,
selectLeft = activeEntryID == nodeInfo.entryIDs[1],
posX = nodeInfo.posX,
posY = nodeInfo.posY,
});
end
end
end
end
end
if subTreeNodes then
table.sort(subTreeNodes, SortFunc_SubTreeNode);
local tileSize = BUTTON_SIZE;
for i, nodeData in ipairs(subTreeNodes) do
--print(i, DataProvider:GetTraitNameByDefinitionID(nodeData.definitionID));
node = self:AcquireNode();
node:SetBorderColor(borderColor);
node:SetPoint("TOP", self, "TOPLEFT", middleX, middleY + (1- i)*tileSize);
if nodeData.selectLeft then
node:SetNodeType(2, 1);
else
node:SetNodeType(2, 2);
end
node.nodeID = nodeData.nodeID;
node.entryID = nodeData.entryID;
node.entryIDs = nodeData.entryIDs;
node.rank = 1;
node.currentRank = 1;
node.maxRanks = 1;
node:SetDefinitionID(nodeData.definitionID);
node:SetActive(true);
end
self.Divider:Hide();
else
self.Divider:Show();
end
if not isPreviewing and not isInspecting then
UniversalFont:SetText(self.LoadoutToggle.ButtonText, DataProvider:GetActiveLoadoutName());
self.SideTab:SetSelectedSpec(specID);
LoadoutUtil:SetSelectedConfigID(DataProvider:GetSelecetdConfigID());
LoadingBarUtil:HideBar();
self:SetSpecBackground(specID);
end
end
function NarciMiniTalentTreeMixin:SetSpecBackground(specID)
if not USE_CLASS_BACKGROUND then return end;
if specID ~= self.bgID then
self.bgID = specID;
self.HeaderLight:Hide();
local bgFile, blurFile = TextureUtil:GetSpecBackground(specID);
self.SpecArt:SetTexture(bgFile);
self.SideTab.ClipFrame.SpecArt:SetTexture(blurFile);
end
end
function NarciMiniTalentTreeMixin:ShowInspecting(inspectUnit)
self.inspectUnit = inspectUnit;
self:SetInspectMode(true);
DataProvider:ClearComparisonCache();
DataProvider:SetPlayerActiveConfigID();
self.configID = nil;
self:ShowConfig(INPSECT_CONFIG_ID);
end
function NarciMiniTalentTreeMixin:SetInspectDisplayMode(id)
if id ~= 1 and id ~= 2 then
id = 1;
end
InspectDisplayModeUtil:SelectButton(id);
--id: 1.Show Target Talents Only 2.Show Difference
local showDiff = (id == 2) or nil;
if showDiff ~= self.showTalentDifferences then
self.showTalentDifferences = showDiff;
if self:IsInspecting() then
self:ShowInspecting( self:GetInspectUnit() );
end
end
end
function NarciMiniTalentTreeMixin:SetInspectMode(state)
if state then
DataProvider:SetInspectMode(true);
self.SideTabToggle:Hide();
self.LoadoutToggle:Disable();
self.LoadoutToggle.Icon:Hide();
LoadingBarUtil:HideBar();
if self.SideTab:IsShown() then
self.SideTab:CloseFrame(true);
end
if self.PvPTalentFrame:IsShown() then
self.PvPTalentFrame:Update();
end
local loadoutName;
local unit = self:GetInspectUnit();
local playerName = UnitName(unit);
local specID = GetInspectSpecialization(unit);
local classDisplayName, class = UnitClass(unit);
playerName = playerName or "Unknown Player";
if specID then
local sex = UnitSex(unit);
local _, specName = GetSpecializationInfoByID(specID, sex);
--loadoutName = specName.." "..classDisplayName.." - "..playerName;
loadoutName = classDisplayName.." - "..playerName;
self.SideTabToggle:Show();
self.SideTabToggle.ButtonText:SetText(specName);
self:SetSpecBackground(specID);
else
loadoutName = playerName; --TALENTS_INSPECT_FORMAT
end
UniversalFont:SetText(self.LoadoutToggle.ButtonText, loadoutName);
SetBranchColor = SetBranchColorCyan;
DataProvider:SetInspectSpecID(specID);
self.SideTab:SetMode("inspect", DataProvider:IsInpsectSameSpec());
self.ShareToggle:Hide();
TextButtonUtil:SetButtonIcon(self.SideTabToggle, "share");
elseif self:IsInspecting() then
DataProvider:SetInspectMode(false);
self.inspectUnit = nil;
self.SideTabToggle:Show();
self.LoadoutToggle:Enable();
self.LoadoutToggle.Icon:Show();
UniversalFont:SetText(self.LoadoutToggle.ButtonText, DataProvider:GetActiveLoadoutName());
self.SideTabToggle.ButtonText:SetText(DataProvider:GetCurrentSpecName());
if self.PvPTalentFrame:IsShown() then
self.PvPTalentFrame:Update();
end
SetBranchColor = SetBranchColorYellow;
self.SideTab:SetMode("class");
self.ShareToggle:Show();
TextButtonUtil:SetButtonIcon(self.SideTabToggle, "arrowRight");
end
--self.MacroForge:HideFrame();
end
function NarciMiniTalentTreeMixin:ReleaseAllNodes()
for i = 1, #Nodes do
Nodes[i]:Hide();
Nodes[i]:ClearAllPoints();
end
self.numAcitveNodes = 0;
LayoutUtil:Reset();
end
function NarciMiniTalentTreeMixin:AcquireNode()
self.numAcitveNodes = self.numAcitveNodes + 1;
if not Nodes[self.numAcitveNodes] then
Nodes[self.numAcitveNodes] = CreateFrame("Frame", nil, self, "NarciTalentTreeNodeTemplate");
Nodes[self.numAcitveNodes].Symbol:SetVertexColor(0.67, 0.67, 0.67);
Nodes[self.numAcitveNodes].Icon:SetSize(ICON_SIZE, ICON_SIZE);
Nodes[self.numAcitveNodes]:SetSize(BUTTON_SIZE, BUTTON_SIZE);
end
Nodes[self.numAcitveNodes]:Show();
return Nodes[self.numAcitveNodes];
end
--[[
local BranchUpdater = CreateFrame("Frame");
local MAX_PROCESS_PER_FRAME = 400;
local function BranchUpdater_OnUpdate(self, elapsed)
local processedThisFrame = 0;
local nodeID;
local nodeInfo;
local fromNode, targetNode;
local b;
local x1, y1, x2, y2, d, rd;
local bchs = Branches;
local SZH = BUTTON_SIZE_HALF;
local notFound = true;
local main = MainFrame;
while self.fromNodeIndex <= self.numNodes do
if self.lastEdgeID and self.lastNodeInfo then
fromNode = self.lastFromNode;
for j = self.lastEdgeID, #self.lastNodeInfo.visibleEdges do
targetNode = NodeIDxNode[self.lastNodeInfo.visibleEdges[j].targetNode];
if targetNode then
processedThisFrame = processedThisFrame + 1;
if processedThisFrame > MAX_PROCESS_PER_FRAME then
self.lastEdgeID = j;
self.lastNodeInfo = nodeInfo;
return
end
self.numBranches = self.numBranches + 1;
b = bchs[self.numBranches];
if not b then
b = MainFrame:CreateTexture(nil, "OVERLAY");
bchs[self.numBranches] = b;
b:SetHeight(BRANCH_WEIGHT);
b:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\Branch");
end
x1, y1 = fromNode.x + SZH, fromNode.y - SZH;
x2, y2 = targetNode.x + SZH, targetNode.y - SZH;
d = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
rd = atan2(y2 - y1, x2 - x1);
b:SetWidth(d);
b:ClearAllPoints();
if fromNode.isLeft then
b:SetPoint("CENTER", main, "TOPLEFT", (x1+x2)*0.5, (y1+y2)*0.5);
else
b:SetPoint("CENTER", main, "TOPLEFT", (x1+x2)*0.5, (y1+y2)*0.5);
end
b:SetRotation(rd);
b:Show();
SetBranchColor(b, fromNode.active and targetNode.active);
end
end
self.fromNodeIndex = self.fromNodeIndex + 1;
self.lastEdgeID = nil;
self.lastNodeInfo = nil;
self.lastFromNode = nil;
if self.fromNodeIndex > self.numNodes then
break
end
end
nodeID = MainFrame.nodeIDs[self.fromNodeIndex];
nodeInfo = MainFrame:GetAndCacheNodeInfo(nodeID);
if nodeInfo then
fromNode = NodeIDxNode[nodeID];
if fromNode then
--print(nodeID)
--notFound = false;
for j, edgeVisualInfo in ipairs(nodeInfo.visibleEdges) do
targetNode = NodeIDxNode[edgeVisualInfo.targetNode];
if targetNode then
notFound = false;
processedThisFrame = processedThisFrame + 1;
if processedThisFrame > MAX_PROCESS_PER_FRAME then
self.lastEdgeID = j;
self.lastNodeInfo = nodeInfo;
self.lastFromNode = fromNode;
return
end
self.numBranches = self.numBranches + 1;
b = bchs[self.numBranches];
if not b then
b = MainFrame:CreateTexture(nil, "OVERLAY");
bchs[self.numBranches] = b;
b:SetHeight(BRANCH_WEIGHT);
b:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\Branch");
end
x1, y1 = fromNode.x + SZH, fromNode.y - SZH;
x2, y2 = targetNode.x + SZH, targetNode.y - SZH;
d = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
rd = atan2(y2 - y1, x2 - x1);
b:SetWidth(d);
b:ClearAllPoints();
if fromNode.isLeft then
b:SetPoint("CENTER", main, "TOPLEFT", (x1+x2)*0.5, (y1+y2)*0.5);
else
b:SetPoint("CENTER", main, "TOPLEFT", (x1+x2)*0.5, (y1+y2)*0.5);
end
b:SetRotation(rd);
b:Show();
SetBranchColor(b, fromNode.active and targetNode.active);
end
end
end
end
self.fromNodeIndex = self.fromNodeIndex + 1;
end
if notFound then
self:SetScript("OnUpdate", nil);
--print("Branches: "..self.numBranches);
end
end
--]]
local function PlayActivationAnimationAfterDelay(self, elapsed)
self.animT = self.animT + elapsed;
if self.activationAnimDelay then
if self.animT >= self.activationAnimDelay then
self:SetScript("OnUpdate", nil);
self.activationAnimDelay = nil;
self.animT = nil;
MainFrame:PlayActivationAnimation();
end
else
self:SetScript("OnUpdate", nil);
end
end
local function BranchUpdater_OnUpdate_OneFrame(self, elapsed)
self:SetScript("OnUpdate", self.nextOnUpdateFunc);
for i = 1, #Branches do
Branches[i]:Hide();
Branches[i]:ClearAllPoints();
end
local nodeIDs = self.nodeIDs;
local numBranches = 0;
local fromIndex = 1;
local numNodes = #nodeIDs;
local nodeID, nodeInfo;
local fromNode, targetNode;
local x1, y1, x2, y2, d, rd, b;
local bchs = Branches;
local SZH = BUTTON_SIZE_HALF;
local container = MainFrame;
local GetNodeInfo = DataProvider.GetNodeInfo;
local sqrt = sqrt;
local atan2 = atan2;
local SetBranchColor = SetBranchColor;
while fromIndex <= numNodes do
nodeID = nodeIDs[fromIndex];
nodeInfo = GetNodeInfo(nodeID);
if nodeInfo then
fromNode = NodeIDxNode[nodeID];
if fromNode then
for j, edgeVisualInfo in ipairs(nodeInfo.visibleEdges) do
targetNode = NodeIDxNode[edgeVisualInfo.targetNode];
if targetNode then
numBranches = numBranches + 1;
b = bchs[numBranches];
if not b then
b = container:CreateTexture(nil, "OVERLAY");
bchs[numBranches] = b;
b:SetHeight(BRANCH_WEIGHT);
b:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\TalentTree\\Branch");
end
x1, y1 = fromNode.x + SZH, fromNode.y - SZH;
x2, y2 = targetNode.x + SZH, targetNode.y - SZH;
d = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) );
rd = atan2(y2 - y1, x2 - x1);
b:SetWidth(d);
b:ClearAllPoints();
b:SetPoint("CENTER", container, "TOPLEFT", (x1+x2)*0.5, (y1+y2)*0.5);
b:SetRotation(rd);
b:Show();
SetBranchColor(b, fromNode.active and targetNode.active);
end
end
end
end
fromIndex = fromIndex + 1;
end
self.nodeIDs = nil;
LayoutUtil:ClearTemps();
end
function NarciMiniTalentTreeMixin:CreateBranches(nodeIDs)
self.nodeIDs = nodeIDs;
if self.activationAnimDelay then
self.animT = 0;
self.nextOnUpdateFunc = PlayActivationAnimationAfterDelay;
else
self.nextOnUpdateFunc = nil;
end
self:SetScript("OnUpdate", BranchUpdater_OnUpdate_OneFrame);
end
function NarciMiniTalentTreeMixin:RemoveBranches()
self:SetScript("OnUpdate", nil);
self.nodeIDs = nil;
for i = 1, #Branches do
Branches[i]:Hide();
Branches[i]:ClearAllPoints();
end
end
function NarciMiniTalentTreeMixin:RequestUpdate()
self.isDirty = true;
if not self:IsInspecting() then
if self:IsVisible() then
self:ShowActiveBuild();
else
local configID = DataProvider:GetSelecetdConfigID();
DataProvider:SetPlayerActiveConfigID(configID);
end
end
--ActionBarUtil:RequestUpdate();
end
function NarciMiniTalentTreeMixin:OnShow()
if self.Init then
self:Init();
end
DataProvider:StopCacheWipingCountdown();
--EventCenter:RegisterEvent("CURSOR_CHANGED");
EventCenter:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player");
self:RegisterEvent("PLAYER_STARTED_MOVING");
self:RegisterEvent("PLAYER_STOPPED_MOVING");
self:RegisterEvent("PLAYER_STARTED_LOOKING");
self:RegisterEvent("PLAYER_STOPPED_LOOKING");
self:RegisterEvent("PLAYER_STARTED_TURNING");
self:RegisterEvent("PLAYER_STOPPED_TURNING");
if ShouldHideBackground() then
self:SetBackgroundAlpha(0);
self:EnableMouse(false);
else
self:SetBackgroundAlpha(1);
self:EnableMouse(true);
end
end
function NarciMiniTalentTreeMixin:OnHide()
self.activationAnimDelay = nil;
DataProvider:StartCacheWipingCountdown();
--EventCenter:UnregisterEvent("CURSOR_CHANGED");
EventCenter:UnregisterEvent("UNIT_SPELLCAST_SUCCEEDED");
self:UnregisterEvent("PLAYER_STARTED_MOVING");
self:UnregisterEvent("PLAYER_STOPPED_MOVING");
self:RegisterEvent("PLAYER_STARTED_LOOKING");
self:RegisterEvent("PLAYER_STOPPED_LOOKING");
self:RegisterEvent("PLAYER_STARTED_TURNING");
self:RegisterEvent("PLAYER_STOPPED_TURNING");
self:SetFading(false);
end
function NarciMiniTalentTreeMixin:IsInspecting()
return self.inspectUnit ~= nil
end
function NarciMiniTalentTreeMixin:GetInspectUnit()
return self.inspectUnit;
end
local function SetPixelPerfectPosition(frame, relativeTo)
if relativeTo then
frame:ClearAllPoints();
local position = frame.position;
if position == "bottom" then
local offsetV = 32;
local bottom0 = relativeTo:GetBottom();
local bottom1 = floor( (bottom0 - offsetV) * PIXEL) / PIXEL;
frame:SetPoint("TOPLEFT", relativeTo, "BOTTOMLEFT", 0, bottom1 - bottom0);
else
local offsetH;
if frame.offsetH then
offsetH = frame.offsetH * UIParent:GetEffectiveScale();
else
offsetH = 4;
end
local right0 = relativeTo:GetRight();
local right1 = floor( (right0 + offsetH) * PIXEL + 0.5) / PIXEL;
local top0 = relativeTo:GetTop();
local top1 = floor( (top0 + 0) * PIXEL) / PIXEL;
frame:SetPoint("TOPLEFT", relativeTo, "TOPRIGHT", right1 - right0, top1 - top0);
end
end
end
function NarciMiniTalentTreeMixin:AnchorToInspectFrame()
self.anchor = "inspectframe";
local f = InspectFrame;
if f and f:IsShown() and f.unit then
SetPixelPerfectPosition(self, f);
self:Show();
self:ShowInspecting(f.unit);
self:SetFrameStrata("HIGH");
self:SetToplevel(false);
else
self:Hide();
end
end
function NarciMiniTalentTreeMixin:AnchorToPaperDoll()
self.anchor = "paperdoll";
self:SetFrameStrata("MEDIUM");
self:SetToplevel(false);
local f = PaperDollFrame;
if f and f:IsShown() then
SetPixelPerfectPosition(self, f);
else
self:Hide();
end
end
function NarciMiniTalentTreeMixin:SetUseClassBackground(state)
if state ~= USE_CLASS_BACKGROUND then
USE_CLASS_BACKGROUND = state;
if state then
local specID = DataProvider:GetCurrentSpecID();
self.HeaderLight:Hide();
local bgFile, blurFile = TextureUtil:GetSpecBackground(specID);
self.SpecArt:SetTexture(bgFile);
self.SideTab.ClipFrame.SpecArt:SetTexture(blurFile);
self.SideTab.FullFrameOverlay:SetColorTexture(0, 0, 0, 0.5);
self.SideTab.Shadow:SetColorTexture(0, 0, 0);
self.LoadoutDropdown.FullFrameOverlay:SetColorTexture(0, 0, 0, 0.5);
self.LoadoutDropdown.Background:SetVertexColor(0, 0, 0);
if self.LoadoutToggle then
TextButtonUtil:SetButtonNormalAndHiglightColor(self.LoadoutToggle, 0.8, 1);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.SideTabToggle, 0.8, 1);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.PvPTalentToggle, 0.8, 1);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.SettingsButton, 0.67, 0.92);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.ShareToggle, 0.67, 0.92);
end
else
self.HeaderLight:Show();
self.SpecArt:SetTexture(nil);
self.SideTab.ClipFrame.SpecArt:SetTexture(nil);
self.SideTab.FullFrameOverlay:SetColorTexture(0.1, 0.1, 0.1, 0.5);
self.SideTab.Shadow:SetColorTexture(0.08, 0.08, 0.08);
self.LoadoutDropdown.FullFrameOverlay:SetColorTexture(0.1, 0.1, 0.1, 0.5);
self.LoadoutDropdown.Background:SetVertexColor(0.1, 0.1, 0.1);
if self.LoadoutToggle then
TextButtonUtil:SetButtonNormalAndHiglightColor(self.LoadoutToggle, 0.67, 0.92);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.SideTabToggle, 0.5, 0.92);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.PvPTalentToggle, 0.5, 0.92);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.SettingsButton, 0.5, 0.92);
TextButtonUtil:SetButtonNormalAndHiglightColor(self.ShareToggle, 0.5, 0.92);
end
end
ClassTalentTooltipUtil:SetUseClassBackground(state);
end
self.Background:SetShown(not state);
end
function NarciMiniTalentTreeMixin:RaiseActiveNodesFrameLevel(state)
if not state then state = nil end;
if state == self.isNodeRaised then
return
else
self.isNodeRaised = state
end
local baseLevel = self:GetFrameLevel() + 1;
local activeLevel;
if state then
--activeLevel = self.MacroForge.MotionBlocker:GetFrameLevel() + 1;
NodeUtil:SetModePickIcon();
else
activeLevel = baseLevel;
NodeUtil:SetModeNormal();
end
for i, node in ipairs(Nodes) do
if node.isActive then
node:SetFrameLevel(activeLevel);
else
node:SetFrameLevel(baseLevel);
end
end
end
function NarciMiniTalentTreeMixin:SetFramePosition(position)
if position == "bottom" then
self.position = "bottom";
else
self.position = "right";
end
if self:IsShown() then
if self.anchor == "inspectframe" then
self:AnchorToInspectFrame();
elseif self.anchor == "paperdoll" then
self:AnchorToPaperDoll();
end
end
end
function NarciMiniTalentTreeMixin:PlayActivationAnimation()
self.AnimationFrame:StopAnimating();
if not self:IsVisible() then
self.AnimationFrame:Hide();
return
end
self.AnimationFrame.t = 0;
self.AnimationFrame:Show();
local sqrt = sqrt;
local node, highlight;
local n = 0;
for i = 1, self.numAcitveNodes do
node = Nodes[i];
if node.isActive then
n = n + 1;
highlight = NodeHighlights[n];
if not highlight then
highlight = self.AnimationFrame:CreateTexture(nil, "OVERLAY", "NarciTalentTreeNodeHighlightTemplate");
highlight:SetSize(2*BUTTON_SIZE, 2*BUTTON_SIZE);
NodeHighlights[n] = highlight;
end
if node.typeID == 0 then
highlight:SetTexCoord(0.5, 1, 0, 0.5); --square
elseif node.typeID == 2 then
highlight:SetTexCoord(0, 0.5, 0.5, 1); --octagon
else
highlight:SetTexCoord(0, 0.5, 0, 0.5); --circle
end
highlight:ClearAllPoints();
highlight:SetPoint("CENTER", node, "CENTER", 0, 0);
highlight.Glow.AnimDelay:SetStartDelay(sqrt( (node.iX - 9)*(node.iX - 9) + (node.iY - 5)*(node.iY - 5)) * 0.05);
highlight.Glow:Play();
highlight:Show();
end
end
self.AnimationFrame.ActivationShockwave.AnimIn:Play();
self.AnimationFrame.ActivationShockwave:Show();
for i = n + 1, #NodeHighlights do
NodeHighlights[i]:Hide();
end
end
function NarciMiniTalentTreeMixin:SetUseBiggerUI(larger)
TextureUtil:UpdateWidgetSize(larger);
LayoutUtil:UpdatePixel();
if self:IsVisible() then
self:RequestUpdate();
else
self.isDirty = true;
end
end
function NarciMiniTalentTreeMixin:OnEvent(event, ...)
if event == "PLAYER_STARTED_MOVING" or event == "PLAYER_STARTED_LOOKING" or event == "PLAYER_STARTED_TURNING" then
self:SetFading(-4);
elseif event == "PLAYER_STOPPED_MOVING" or event == "PLAYER_STOPPED_LOOKING" or event == "PLAYER_STOPPED_TURNING" then
if not ShouldHideBackground() then
self:SetFading(4);
end
end
end
local FadingFrame = CreateFrame("Frame");
FadingFrame:Hide();
FadingFrame:SetScript("OnUpdate", function(self, elapsed)
self.alpha = self.alpha + self.delta * elapsed;
if self.alpha >= 1 then
self.alpha = 1;
self:Hide();
elseif self.alpha <= 0 then
self.alpha = 0;
self:Hide();
end
MainFrame:SetBackgroundAlpha(self.alpha);
end);
function NarciMiniTalentTreeMixin:SetFading(delta)
if delta then
if delta > 0 then
FadingFrame.delta = 4;
self:EnableMouse(true);
elseif delta < 0 then
FadingFrame.delta = -4;
self:EnableMouse(false);
else
return
end
FadingFrame.alpha = self.Background:GetAlpha();
FadingFrame:Show();
else
FadingFrame:Hide();
self:SetBackgroundAlpha(1);
self:EnableMouse(true);
end
end
function NarciMiniTalentTreeMixin:SetBackgroundAlpha(alpha)
self.Background:SetAlpha(alpha);
self.SpecArt:SetAlpha(alpha);
end
function NarciMiniTalentTreeMixin:OnSwitchLoadoutFailed(reason)
self:RequestUpdate();
end
NarciTalentTreeLoadoutButtonMixin = {};
function NarciTalentTreeLoadoutButtonMixin:OnEnter()
if not self.selected then
self.ButtonText:SetTextColor(1, 1, 1);
end
if self.configID then
OnEnterDelay:WatchButton(self);
end
end
function NarciTalentTreeLoadoutButtonMixin:OnEnterCallback()
if self.configID then
MainFrame:ShowConfig(self.configID, true);
end
end
function NarciTalentTreeLoadoutButtonMixin:OnLeave()
if not self.selected then
self.ButtonText:SetTextColor(0.67, 0.67, 0.67);
end
OnEnterDelay:ClearWatch();
end
local function AttemptToApplyConfig(configIDToLoad)
if not configIDToLoad then return end;
MainFrame.lastConfigID = DataProvider:GetSelecetdConfigID();
if not ClassTalentFrame then
ClassTalentFrame_LoadUI();
end
if ClassTalentFrame then
ClassTalentFrame.TalentsTab:LoadConfigByPredicate(function(_, configID)
return configID == configIDToLoad;
end);
else
MainFrame.lastConfigID = DataProvider:GetSelecetdConfigID();
local autoApply = true;
local result = C_ClassTalents.LoadConfig(configIDToLoad, autoApply);
if result ~= 0 then
local currentSpecID = DataProvider:GetCurrentSpecID();
C_ClassTalents.UpdateLastSelectedSavedConfigID(currentSpecID, configIDToLoad);
end
return result
end
end
Narci.AC = AttemptToApplyConfig; --Name Shorten to be used in macro
function NarciTalentTreeLoadoutButtonMixin:OnClick()
if self.selected then
else
if self.configID and (ClassTalentHelper and ClassTalentHelper.SwitchToLoadoutByIndex) then
MainFrame.lastConfigID = DataProvider:GetSelecetdConfigID();
if ClassTalentHelper and ClassTalentHelper.SwitchToLoadoutByIndex then
ClassTalentHelper.SwitchToLoadoutByIndex(self.index);
end
--Talent swap may not succeed due to abilities in cooldown, but "ClassTalentHelper" itself doesn't return anything
--We check if loading start after 1s
LoadingBarUtil:SetFromLoadoutToggle(MainFrame.LoadoutToggle);
end
end
LoadoutUtil:HideList();
end
function NarciTalentTreeLoadoutButtonMixin:SetConfigID(configID)
self.configID = configID;
local name = DataProvider:GetConfigName(configID);
if name then
self.ButtonText:SetText(name);
self.Underline:SetWidth(self.ButtonText:GetWrappedWidth());
end
end
function LoadoutUtil:IsFocused()
if MainFrame.LoadoutToggle:IsMouseOver(12, -12, 0, 0) then
return true
end
for i = 1, #self.buttons do
if self.buttons[i]:IsShown() then
if self.buttons[i]:IsMouseOver() then
return true
end
else
return
end
end
end
function LoadoutUtil:Init()
self.buttons = {};
local function LoadoutDropdown_OnShow(f)
f:RegisterEvent("GLOBAL_MOUSE_DOWN");
end
local function LoadoutDropdown_OnEvent(f, event, ...)
if not self:IsFocused() then
f:UnregisterEvent("GLOBAL_MOUSE_DOWN");
self:HideList();
end
end
self.container = MainFrame.LoadoutDropdown;
self.container:SetScript("OnShow", LoadoutDropdown_OnShow);
self.container:SetScript("OnEvent", LoadoutDropdown_OnEvent);
self.font = MainFrame.LoadoutToggle.ButtonText:GetFont();
self.buttonHeight = 32*PIXEL;
self.Init = nil;
end
function LoadoutUtil:UpdateList()
for i = 1, #self.buttons do
self.buttons[i]:Hide();
end
local configs = DataProvider:GetConfigIDs();
local button;
for i = 1, #configs do
button = self.buttons[i];
if not button then
button = CreateFrame("Button", nil, self.container, "NarciTalentTreeLoadoutButtonTemplate");
self.buttons[i] = button;
button.index = i;
button.ButtonText:SetFont(self.font, FONT_HEIGHT, "");
button:SetPoint("TOP", MainFrame.LoadoutToggle, "TOP", 0, self.buttonHeight*( - i));
button:SetHeight(self.buttonHeight);
button.Underline:SetHeight(2*PIXEL);
button.Underline:SetPoint("TOPLEFT", button.ButtonText, "BOTTOMLEFT", 0, -2*PIXEL);
end
button:SetConfigID(configs[i]);
button:Show();
end
if button then
local top = self.container:GetTop();
local bottom = button:GetBottom();
self.container:SetHeight(top - bottom + 8);
local selectedConfigID = DataProvider:GetSelecetdConfigID();
if selectedConfigID then
self:SetSelectedConfigID(selectedConfigID);
end
return true
else
self.container:SetHeight(64);
return false
end
end
function LoadoutUtil.ShowFrame_OnUpdate(f, elapsed)
f.alpha = f.alpha + elapsed * 4;
if f.alpha > 1 then
f.alpha = 1;
f:SetScript("OnUpdate", nil);
end
f:SetAlpha(f.alpha);
end
function LoadoutUtil:ShowList()
if LoadingBarUtil:IsBarVisible() then
return
end
if self.Init then
self:Init();
end
local anyLoadout = self:UpdateList();
if self.activeButton then
self.activeButton.Underline.AnimIn:Stop();
self.activeButton.Underline.AnimIn:Play();
end
self.container:Show();
self.container.alpha = 0;
self.container:SetScript("OnUpdate", self.ShowFrame_OnUpdate);
if anyLoadout then
MainFrame.LoadoutToggle.ButtonText:SetText(L["Loadout"]);
else
MainFrame.LoadoutToggle.ButtonText:SetText(L["No Loadout"]);
end
MainFrame.LoadoutToggle.Icon:SetTexCoord(0.25, 0.5, 0.25, 0);
end
function LoadoutUtil:HideList()
self.container:Hide();
MainFrame.LoadoutToggle.Icon:SetTexCoord(0.25, 0.5, 0, 0.25);
if not LoadingBarUtil:IsBarVisible() then
UniversalFont:SetText(MainFrame.LoadoutToggle.ButtonText, DataProvider:GetActiveLoadoutName());
MainFrame:ShowActiveBuild();
end
end
function LoadoutUtil:ToggleList()
if self.container and self.container:IsShown() then
self:HideList();
else
self:ShowList();
end
end
function LoadoutUtil:SetSelectedConfigID(configID)
self.activeButton = nil;
self.activeConfigID = configID;
if self.buttons then
for i, b in ipairs(self.buttons) do
if b.configID == configID then
b.Underline:Show();
b.selected = true;
b.ButtonText:SetTextColor(1, 0.82, 0);
self.activeButton = b;
else
b.Underline:Hide();
b.selected = false;
b:OnLeave();
end
end
end
end
NarciTalentTreePvPFrameMixin = {};
function NarciTalentTreePvPFrameMixin:OnShow()
if self.isDirty then
self:Update();
end
end
function NarciTalentTreePvPFrameMixin:RequestUpdate()
if self:IsShown() then
self:Update();
else
self.isDirty = true;
end
end
function NarciTalentTreePvPFrameMixin:IsWarModeActive()
return C_PvP.IsWarModeDesired() or C_PvP.IsWarModeActive()
end
function NarciTalentTreePvPFrameMixin:Update()
self:Init();
self.isDirty = nil;
local talentID, talentInfo;
if MainFrame:IsInspecting() then
local unit = MainFrame:GetInspectUnit();
for i = 1, 3 do
talentID = C_SpecializationInfo.GetInspectSelectedPvpTalent(unit, i);
self.slots[i]:SetPvPTalent(talentID, unit);
self.slots[i]:Show();
self.slots[i].isInspecting = true;
self.slots[i]:SetBorderColor(2);
end
for i = 4, 6 do
talentInfo = C_SpecializationInfo.GetPvpTalentSlotInfo(i - 3);
self.slots[i]:SetPvPTalent((talentInfo ~= nil and talentInfo.selectedTalentID) or nil);
self.slots[i]:Show();
self.slots[i].isInspecting = false;
end
else
for i = 4, 6 do
self.slots[i]:Hide();
self.slots[i].isInspecting = false;
end
for i = 1, 3 do
talentInfo = C_SpecializationInfo.GetPvpTalentSlotInfo(i);
self.slots[i]:SetPvPTalent((talentInfo ~= nil and talentInfo.selectedTalentID) or nil);
self.slots[i]:Show();
self.slots[i].isInspecting = false;
self.slots[i]:SetBorderColor(1);
end
end
end
function NarciTalentTreePvPFrameMixin:Init()
if not self.slots then
self.slots = {};
local slot;
for i = 1, 6 do -- 4,5,6 are for inspection (1-3 for the inspectee, 4-6 for me)
slot = CreateFrame("Button", nil, self, "NarciTalentTreeNodeTemplate");
self.slots[i] = slot;
slot.Icon:SetSize(ICON_SIZE, ICON_SIZE);
slot:SetSize(BUTTON_SIZE, BUTTON_SIZE);
slot:SetNodeType(0, 1);
slot.Icon:SetTexCoord(0.0625, 0.9375, 0.0625, 0.9375);
slot.Symbol:SetVertexColor(0.160, 0.160, 0.160);
slot.isPvp = true;
if i <= 3 then
slot:SetPoint("TOP", self, "TOP", 0, -HEADER_SIZE -(i + 1) * BUTTON_SIZE);
slot.index = i;
else
slot:SetPoint("TOP", self, "TOP", 0, -HEADER_SIZE -(i + 3) * BUTTON_SIZE);
slot.index = i - 3;
end
end
self:SetWidth(BUTTON_SIZE * 3);
self.Divider:ClearAllPoints();
self.Divider:SetPoint("TOPLEFT", self, "TOPLEFT", 0, -BUTTON_SIZE/2 -HEADER_SIZE);
self.Divider:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, BUTTON_SIZE/2);
end
end
function NarciTalentTreePvPFrameMixin:Toggle()
if self:IsShown() then
self:Hide();
MainFrame.PvPTalentToggle.Icon:SetTexCoord(0, 0.125, 0, 0.25);
else
self:Show();
MainFrame.PvPTalentToggle.Icon:SetTexCoord(0.125, 0.25, 0, 0.25);
end
LayoutUtil:UpdateFrameSize();
end
function NarciTalentTreePvPFrameMixin:UpdatePixel()
if self.slots then
for i, slot in ipairs(self.slots) do
slot.Icon:SetSize(ICON_SIZE, ICON_SIZE);
slot:SetSize(BUTTON_SIZE, BUTTON_SIZE);
if i <= 3 then
slot:SetPoint("TOP", self, "TOP", 0, -HEADER_SIZE -(i + 1) * BUTTON_SIZE);
else
slot:SetPoint("TOP", self, "TOP", 0, -HEADER_SIZE -(i + 3) * BUTTON_SIZE);
end
end
end
self:SetWidth(BUTTON_SIZE * 3);
self.Divider:ClearAllPoints();
self.Divider:SetPoint("TOPLEFT", self, "TOPLEFT", 0, -BUTTON_SIZE/2 -HEADER_SIZE);
self.Divider:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 0, BUTTON_SIZE/2);
end
local CreateKeyChordStringUsingMetaKeyState = CreateKeyChordStringUsingMetaKeyState;
local function Clipboard_OnKeyDown(self, key)
local keys = CreateKeyChordStringUsingMetaKeyState(key);
if keys == "CTRL-C" or key == "COMMAND-C" then
self:SetScript("OnKeyDown", nil);
C_Timer.After(0, function()
self.Label:SetText(L["String Copied"]);
self.Label:StopAnimating();
self.Label.FadeOut:Play();
self:ClearFocus();
end);
end
end
local function LoadoutEditBox_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t >= 1 then
self.t = nil;
self:SetScript("OnUpdate", nil);
self:ShowLoadingIndicator(false);
self.SaveButton:Show();
local text = self:GetText();
if DataProvider:IsLoadoutNameValid(text) then
self.SaveButton:CaseValid();
else
self.SaveButton:CaseDuplicate();
end
end
end
local function LoadoutEditBox_OnTextChanged(self, isUserInput)
if isUserInput then
if not self.t then
self.t = 0;
self.SaveButton:Hide();
self:SetScript("OnUpdate", LoadoutEditBox_OnUpdate);
self:ShowLoadingIndicator(true);
end
self.t = 0
end
end
local function LoadoutEditBox_OnHide(self)
self:SetScript("OnUpdate", nil);
self.t = nil;
self.SaveButton:Hide();
end
NarciTalentTreeSharedEditBoxMixin = {};
function NarciTalentTreeSharedEditBoxMixin:OnLoad()
table.insert(LayoutUtil.editboxes, self);
self.Exclusion:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Masks\\Exclusion", "CLAMPTOWHITE", "CLAMPTOWHITE", "NEAREST");
if self.widgetType == "clipboard" then
self.isClipboard = true;
self:SetScript("OnTextChanged", NarciTalentTreeSharedEditBoxMixin.OnTextChanged_Forbidden);
self:SetScript("OnCursorChanged", NarciTalentTreeSharedEditBoxMixin.OnCursorChanged_Forbidden);
self:SetPropagateKeyboardInput(false);
local function LabelFadingComplete()
self.Label:SetText("Copy As Text");
self.Label.FadeIn:Play();
end
self.Label.FadeOut:SetScript("OnFinished", LabelFadingComplete);
elseif self.widgetType == "inputbox" then
self.LoadingIndicator:ClearAllPoints();
self.LoadingIndicator:SetPoint("LEFT", self, "LEFT", 4, 0);
self:SetMaxLetters(30);
self:SetScript("OnTextChanged", LoadoutEditBox_OnTextChanged);
self:SetScript("OnHide", LoadoutEditBox_OnHide);
end
if self.unfocusedLabel then
self:SetLabelText(self.unfocusedLabel);
end
if self.defaultTextKey and L[self.defaultTextKey] then
self.DefaultText:SetText(L[self.defaultTextKey]);
self.defaultTextKey = nil;
end
self.hitOffset = 0;
end
function NarciTalentTreeSharedEditBoxMixin:OnEnter()
if not self:HasFocus() then
self:SetStrokeGrayscale(0.4);
self.Label:SetTextColor(0.67, 0.67, 0.67);
end
end
function NarciTalentTreeSharedEditBoxMixin:OnLeave()
if not self:HasFocus() then
self:SetStrokeGrayscale(0.25);
self.Label:SetTextColor(0.5, 0.5, 0.5);
end
end
function NarciTalentTreeSharedEditBoxMixin:SetStrokeColor(r, g, b)
self.Border:SetColorTexture(r, g, b);
end
function NarciTalentTreeSharedEditBoxMixin:SetStrokeGrayscale(a)
self.Border:SetColorTexture(a, a, a);
end
function NarciTalentTreeSharedEditBoxMixin:OnEscapePressed()
self:ClearFocus();
end
function NarciTalentTreeSharedEditBoxMixin:OnEnterPressed()
if self.ConfirmChange then
self.ConfirmChange(self:GetText());
end
self:ClearFocus();
end
function NarciTalentTreeSharedEditBoxMixin:OnEditFocusGained()
self:HighlightText();
self:SetTextColor(0.92, 0.92, 0.92);
self:SetStrokeColor(0.05, 0.41, 0.85);
self.DefaultText:Hide();
if self.isClipboard then
self:SetScript("OnKeyDown", Clipboard_OnKeyDown);
self.Label:StopAnimating();
self.Label:SetText(L["Press To Copy"]);
end
end
function NarciTalentTreeSharedEditBoxMixin:OnEditFocusLost()
self:HighlightText(0, 0);
self:SetTextColor(0.5, 0.5, 0.5);
if self.isClipboard then
if self.copiedText then
self:SetText(self.copiedText);
else
self.DefaultText:Show();
end
if not self.Label.FadeOut:IsPlaying() then
self.Label:SetText("Copy As Text");
end
else
if not string.find(self:GetText(), "%S") then
self.DefaultText:Show();
end
end
if self:IsMouseOver(self.hitOffset, 0, 0, 0) then
self:OnEnter();
else
self:OnLeave();
end
self:SetScript("OnKeyDown", nil);
end
function NarciTalentTreeSharedEditBoxMixin.OnTextChanged_Forbidden(self, isUserInput)
if isUserInput then
self:ClearFocus();
end
end
function NarciTalentTreeSharedEditBoxMixin.OnCursorChanged_Forbidden(self)
if self:HasFocus() then
self:HighlightText();
end
end
function NarciTalentTreeSharedEditBoxMixin:SetLabelText(text, r, g, b)
self.Label:SetText(text);
if self.Label:IsTruncated() then
self.labelPixelHeight = 14;
local font = self.Label:GetFont();
local height = PIXEL * self.labelPixelHeight;
self.Label:SetFont(font, height, "");
end
if r and g and b then
self.Label:SetTextColor(r, g, b);
end
end
function NarciTalentTreeSharedEditBoxMixin:SetLabelText(text, r, g, b)
self.Label:SetText(text);
if r and g and b then
self.Label:SetTextColor(r, g, b);
end
end
function NarciTalentTreeSharedEditBoxMixin:UpdatePixel(px)
self:SetWidth(176*px);
self:SetHeight(24*px);
local font = self.Label:GetFont();
self.Label:SetFont(font, (self.labelPixelHeight or 16)*px, "");
self:SetFont(font, 16*px, "");
self.DefaultText:SetFont(font, 16*px, "");
self.Label:SetPoint("BOTTOM", self, "TOP", 0, 4);
self.Label:SetWidth(168*px);
self.Exclusion:SetPoint("TOPLEFT", px, -px);
self.Exclusion:SetPoint("BOTTOMRIGHT", -px, px);
if self.LoadingIndicator then
self.LoadingIndicator:SetSize(16*px, 16*px);
if self.widgetType == "inputbox" then
self.LoadingIndicator:SetPoint("LEFT", self, "LEFT", 4*px, 0);
end
end
local effectiveHitHeight = 24;
local verticalCompensation = (16*px - effectiveHitHeight); --upwards
if verticalCompensation > 0 then
verticalCompensation = 0;
end
self:SetHitRectInsets(0, 0, verticalCompensation, 0);
self.hitOffset = -verticalCompensation;
end
function NarciTalentTreeSharedEditBoxMixin:SetOnFocusGainedCallback(callback)
self.OonFocusGainedCallback = callback;
end
function NarciTalentTreeSharedEditBoxMixin:ShowLoadingIndicator(state)
if self.LoadingIndicator then
if state then
self.LoadingIndicator.AnimSpin:Play();
self.LoadingIndicator:Show();
else
self.LoadingIndicator.AnimSpin:Stop();
self.LoadingIndicator:Hide();
end
end
end
function NarciTalentTreeSharedEditBoxMixin:ResetState()
self:SetText("");
self.DefaultText:Show();
if self.SaveButton then
self.SaveButton:Hide();
end
end
EventCenter:RegisterEvent("PLAYER_ENTERING_WORLD");
EventCenter:RegisterEvent("PLAYER_PVP_TALENT_UPDATE");
EventCenter:RegisterEvent("ACTIVE_PLAYER_SPECIALIZATION_CHANGED");
EventCenter:RegisterEvent("TRAIT_CONFIG_UPDATED");
EventCenter:RegisterEvent("TRAIT_CONFIG_LIST_UPDATED");
EventCenter:RegisterEvent("TRAIT_CONFIG_DELETED");
EventCenter:RegisterEvent("TRAIT_CONFIG_CREATED");
EventCenter:RegisterEvent("CONFIG_COMMIT_FAILED");
EventCenter:RegisterEvent("ACTIVE_COMBAT_CONFIG_CHANGED");
EventCenter.onUpdate = function(self, elapsed)
self:SetScript("OnUpdate", nil);
if self.onUpdateCallback then
self.onUpdateCallback(MainFrame);
end
end
--[[
function EventCenter:RegisterDynamicEvents(state)
if state then
for i, event in ipairs(self.dynamicEvents) do
self:RegisterEvent(event);
end
else
for i, event in ipairs(self.dynamicEvents) do
self:UnregisterEvent(event);
end
end
end
EventCenter.dynamicEvents = {
"TRAIT_TREE_CHANGED", "TRAIT_NODE_CHANGED", "TRAIT_NODE_CHANGED_PARTIAL", "TRAIT_NODE_ENTRY_UPDATED", "TRAIT_CONFIG_UPDATED", "ACTIVE_PLAYER_SPECIALIZATION_CHANGED", "CONFIG_COMMIT_FAILED",
--TRAIT_NODE_CHANGED: Fires multiple times when cancel switching talent
--TRAIT_TREE_CHANGED: After clicking a loadout
--TRAIT_CONFIG_UPDATED: After successfully changing loadout
--ACTIVE_PLAYER_SPECIALIZATION_CHANGED: followed by TRAIT_CONFIG_UPDATED
};
--]]
EventCenter.onEvent = function(self, event, ...)
if event == "TRAIT_CONFIG_UPDATED" or event == "TRAIT_CONFIG_LIST_UPDATED" or event == "TRAIT_CONFIG_DELETED" or event == "TRAIT_CONFIG_CREATED" then
DataProvider:RefreshConfigIDs();
self.onUpdateCallback = MainFrame.RequestUpdate;
self:SetScript("OnUpdate", self.onUpdate);
if event == "TRAIT_CONFIG_CREATED" then
local configInfo = ...;
if configInfo and configInfo.type == 1 then
--Enum.TraitConfigType.Combat
DataProvider:MarkConfigIDValid(configInfo.ID, true);
end
elseif event == "TRAIT_CONFIG_DELETED" then
local configID = ...;
DataProvider:MarkConfigIDValid(configID, false);
end
elseif event == "CONFIG_COMMIT_FAILED" then
if MainFrame.lastConfigID then
local currentSpecID = DataProvider:GetCurrentSpecID();
local result = C_ClassTalents.LoadConfig( MainFrame.lastConfigID, true);
C_ClassTalents.UpdateLastSelectedSavedConfigID(currentSpecID, MainFrame.lastConfigID);
MainFrame.lastConfigID = nil;
end
self.onUpdateCallback = MainFrame.RequestUpdate;
self:SetScript("OnUpdate", self.onUpdate);
elseif event == "ACTIVE_COMBAT_CONFIG_CHANGED" then
local configID = ...;
elseif event == "ACTIVE_PLAYER_SPECIALIZATION_CHANGED" then
if MainFrame.SideTab:IsShown() then
MainFrame.SideTab:CloseFrame();
end
DataProvider:UpdateSpecInfo();
DataProvider:RefreshConfigIDs();
MainFrame:RequestUpdate();
MainFrame.PvPTalentFrame:RequestUpdate();
MainFrame.SideTabToggle.ButtonText:SetText(DataProvider:GetCurrentSpecName());
CAN_USE_TALENT_UI = CanPlayerUseTalentSpecUI();
elseif event == "PLAYER_ENTERING_WORLD" then
self:UnregisterEvent(event);
self:RegisterEvent("UI_SCALE_CHANGED");
self.onEvent(self, "ACTIVE_PLAYER_SPECIALIZATION_CHANGED");
LayoutUtil:UpdatePixel();
--AddOn Compatibility
if C_AddOns.IsAddOnLoaded("TinyInspect") or C_AddOns.IsAddOnLoaded("TinyInspect-Reforged") then
MainFrame.offsetH = 328 + 2;
end
elseif event == "UI_SCALE_CHANGED" then
LayoutUtil:UpdatePixel();
elseif event == "PLAYER_PVP_TALENT_UPDATE" then
MainFrame.PvPTalentFrame:RequestUpdate();
elseif event == "CURSOR_CHANGED" then
--MainFrame.MacroForge:OnCursorChanged(...);
elseif event == "UNIT_SPELLCAST_SUCCEEDED" then
local spellID = select(3, ...);
if spellID then
if IsSpecializationActivateSpell(spellID) then
MainFrame.activationAnimDelay = 0.4; --use delay for spec change coz game freezes shortly
elseif spellID == 384255 then
MainFrame.activationAnimDelay = 0;
end
end
end
--[[
if event == "TRAIT_TREE_CHANGED" then
elseif event == "TRAIT_NODE_CHANGED" then
elseif event == "TRAIT_NODE_CHANGED_PARTIAL" then
elseif event == "TRAIT_NODE_ENTRY_UPDATED" then
else
end
--]]
end
EventCenter:SetScript("OnEvent", EventCenter.onEvent);
if not addon.IsDragonflight() then return end;
local ENABLE_INSPECT = false;
local ENABLE_PAPERDOLL = false;
local ENABLE_EQUIPMENT_MANAGER = false;
local HookUtil = {};
function HookUtil:HookInpsectFrame()
if self.inspectFrameHooked then return end;
local InspectFrame = _G["InspectFrame"];
if InspectFrame then
self.inspectFrameHooked = true;
InspectFrame:HookScript("OnShow", function()
if ENABLE_INSPECT and InspectFrame.unit and UnitLevel(InspectFrame.unit) >= 10 then
MainFrame:AnchorToInspectFrame();
MainFrame:Show();
MainFrame:ShowInspecting(InspectFrame.unit);
end
end);
InspectFrame:HookScript("OnHide", function()
MainFrame:Hide();
end);
else
if self.inspectFuncHooked then return end;
self.inspectFuncHooked = true;
hooksecurefunc("InspectUnit", function()
if not self.inspectFrameHooked then
self.inspectFrameHooked = true;
InspectFrame = _G["InspectFrame"];
if not InspectFrame then return end;
InspectFrame:HookScript("OnShow", function()
if ENABLE_INSPECT and InspectFrame.unit and UnitLevel(InspectFrame.unit) >= 10 then
MainFrame:AnchorToInspectFrame();
end
end);
InspectFrame:HookScript("OnHide", function()
MainFrame:Hide();
end);
end
end);
end
end
function HookUtil:HookPaperDoll()
if self.paperdollHooked then return end;
self.paperdollHooked = true;
local PaperDoll = _G["PaperDollFrame"];
PaperDoll:HookScript("OnShow", function()
if ENABLE_PAPERDOLL and CAN_USE_TALENT_UI then
MainFrame:AnchorToPaperDoll();
MainFrame:SetInspectMode(false);
MainFrame:Show();
MainFrame:ShowActiveBuild();
end
end);
PaperDoll:HookScript("OnHide", function()
if ENABLE_INSPECT then
MainFrame:AnchorToInspectFrame();
else
MainFrame:Hide();
end
end);
end
function HookUtil:HookEquipmentManager()
if self.equipmentManageHooked then return end;
self.equipmentManageHooked = true;
local f = PaperDollFrame and PaperDollFrame.EquipmentManagerPane;
if not f then return end;
f:HookScript("OnShow", function()
if ENABLE_EQUIPMENT_MANAGER and CAN_USE_TALENT_UI then
MainFrame:AnchorToPaperDoll();
MainFrame:SetInspectMode(false);
MainFrame:Show();
MainFrame:ShowActiveBuild();
end
end);
f:HookScript("OnHide", function()
if ENABLE_PAPERDOLL and CAN_USE_TALENT_UI then
MainFrame:AnchorToPaperDoll();
MainFrame:SetInspectMode(false);
MainFrame:Show();
MainFrame:ShowActiveBuild();
else
MainFrame:Hide();
end
end);
end
do
local SettingFunctions = addon.SettingFunctions;
function SettingFunctions.ShowMiniTalentTreeForInspection(state, db)
if state == nil then
state = db["TalentTreeForInspection"];
end
if state then
ENABLE_INSPECT = true;
HookUtil:HookInpsectFrame();
else
ENABLE_INSPECT = false;
if MainFrame.anchor == "inpsectframe" then
MainFrame:Hide();
end
end
end
function SettingFunctions.ShowMiniTalentTreeForPaperDoll(state, db)
if state == nil then
state = db["TalentTreeForPaperDoll"];
end
if state then
ENABLE_PAPERDOLL = true;
HookUtil:HookPaperDoll();
else
ENABLE_PAPERDOLL = false;
if MainFrame.anchor == "paperdoll" then
MainFrame:Hide();
end
end
end
function SettingFunctions.ShowMiniTalentTreeForEquipmentManager(state, db)
if state == nil then
state = db["TalentTreeForEquipmentManager"];
end
if state then
ENABLE_EQUIPMENT_MANAGER = true;
HookUtil:HookEquipmentManager();
else
ENABLE_EQUIPMENT_MANAGER = false;
if MainFrame.anchor == "paperdoll" then
MainFrame:Hide();
end
end
end
function SettingFunctions.SetUseClassBackground(state, db)
if state == nil then
state = db["TalentTreeUseClassBackground"];
end
MainFrame:SetUseClassBackground(state);
end
function SettingFunctions.SetUseBiggerUI(state, db)
if state == nil then
state = db["TalentTreeBiggerUI"];
end
MainFrame:SetUseBiggerUI(state);
end
function SettingFunctions.SetTalentTreePosition(id, db)
if id == nil then
id = db["TalentTreeAnchor"];
end
local anchor;
if id == 2 then
anchor = "bottom";
else
anchor = "right";
end
MainFrame:SetFramePosition(anchor);
end
end
--[[
local gsub = string.gsub;
function TestEmojiEditBox_OnTextChanged(self, isUserInput)
if isUserInput then
local text = self:GetText();
text = gsub(text, " 1", "|cffa05548 1|r");
text = gsub(text, " 2", "|cffa6c7dd 2|r");
text = gsub(text, " 3", "|cffffd655 3|r");
text = gsub(text, " 4", "|cff33ffcc 4|r");
text = gsub(text, " 5", "|cffff931e 5|r");
self:SetText(text);
end
end
--]]