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.
2618 lines
80 KiB
2618 lines
80 KiB
local UPDATE_PORTRAIT_DELAY = 0.2;
|
|
|
|
|
|
local _, addon = ...
|
|
|
|
local API = addon.API;
|
|
local StatManager = addon.StatManager;
|
|
local HotkeyManager = addon.HotkeyManager;
|
|
local GetPortraitCameraInfoByModelFileID = API.GetPortraitCameraInfoByModelFileID;
|
|
|
|
local FadeFrame = NarciFadeUI.Fade;
|
|
local TransitionAPI = NarciAPI.TransitionAPI;
|
|
|
|
local C_BarberShop = C_BarberShop;
|
|
local SetCustomizationChoice = C_BarberShop.SetCustomizationChoice;
|
|
--C_BarberShop.SetViewingChrModel(chrModelID) New API for Dragon Customization
|
|
|
|
local After = C_Timer.After;
|
|
local sin = math.sin;
|
|
local cos = math.cos;
|
|
local pi = math.pi;
|
|
local sqrt = math.sqrt;
|
|
local abs = math.abs;
|
|
local tremove = table.remove;
|
|
local tinsert = table.insert;
|
|
local unpack = unpack;
|
|
local wipe = wipe;
|
|
local tostring = tostring;
|
|
|
|
local IsMouseButtonDown = IsMouseButtonDown;
|
|
local GetMouseFocus = GetMouseFocus;
|
|
local PlaySound = PlaySound;
|
|
|
|
local function IsWidgetFocused(widget1, widget2)
|
|
local focus = GetMouseFocus();
|
|
if widget2 then
|
|
return focus == widget1 or focus == widget2
|
|
elseif widget1 then
|
|
return focus == widget1
|
|
end
|
|
end
|
|
|
|
local function linear(t, b, e, d)
|
|
return (e - b) * t / d + b
|
|
end
|
|
|
|
local function outSine(t, b, e, d)
|
|
return (e - b) * sin(t / d * (pi / 2)) + b
|
|
end
|
|
|
|
local function inOutSine(t, b, e, d)
|
|
return (b - e) / 2 * (cos(pi * t / d) - 1) + b
|
|
end
|
|
|
|
|
|
local L = Narci.L;
|
|
-----------------------------------------------
|
|
|
|
local MainFrame, ScrollModelFrame, EditButton, EditBox, DeleteButton, PlusButton, SettingFrame, SettingButton, LoadingFrame, SavedLookButtons;
|
|
local BarbershopModel, ExportEditBox;
|
|
local BarberShopUI; --Blizzard BarberShopUI
|
|
|
|
|
|
local HAS_ALTERNATE_FORM = false;
|
|
local IN_ALTERNATE_FORM = false; --For worgen, human form is the alternate form
|
|
local IS_SAVE_SUPPORTED = true; --Disable saves for non-Moonkin Shapeshifts
|
|
|
|
local RACE_WITH_ALTERNATE_FORM = {
|
|
[22] = "human", --worgen
|
|
[52] = "bloodelf", --dracthyr
|
|
[70] = "bloodelf", --dracthyr
|
|
};
|
|
|
|
|
|
local function UpdatePortraitCamera(model)
|
|
local fileID = model:GetModelFileID();
|
|
local cameraInfo = GetPortraitCameraInfoByModelFileID(fileID);
|
|
if cameraInfo then
|
|
local modelX, modelY, modelZ, modelYaw = unpack(cameraInfo);
|
|
model:MakeCurrentCameraCustom();
|
|
model:SetFacing(modelYaw);
|
|
model:SetPosition(modelX, modelY, modelZ);
|
|
local cameraX, cameraY, cameraZ = TransitionAPI.TransformCameraSpaceToModelSpace(model, 4, 0, 0);
|
|
local targetX, targetY, targetZ = TransitionAPI.TransformCameraSpaceToModelSpace(model, 0, 0, 0);
|
|
TransitionAPI.SetCameraPosition(model, cameraX, cameraY, cameraZ);
|
|
TransitionAPI.SetCameraTarget(model, targetX, targetY, targetZ);
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
|
|
local ModelPool = {};
|
|
ModelPool.pools = {};
|
|
|
|
function ModelPool:Init()
|
|
local f = CreateFrame("Frame", nil, MainFrame);
|
|
f:SetSize(8, 8);
|
|
f:SetPoint("TOP", MainFrame, "BOTTOM", 0, -8);
|
|
f:Hide();
|
|
self.container = f;
|
|
end
|
|
|
|
local function PortaitModel_OnModelLoaded(self)
|
|
self:SetCamera(0);
|
|
self:SetAnimation(0, 0);
|
|
self:SetPaused(true);
|
|
self:SetPortraitZoom(0.975);
|
|
self:SetPortraitZoom(1);
|
|
self.isModelLoaded = true;
|
|
self:SetIgnoreParentAlpha(true);
|
|
LoadingFrame:LoadNextPortrait(self.parentButton.order);
|
|
UpdatePortraitCamera(self);
|
|
end
|
|
|
|
function ModelPool.SetupModel(model)
|
|
model:SetSize(56, 56);
|
|
model:SetUnit("player");
|
|
model:SetKeepModelOnHide(true);
|
|
model:SetFacing(pi/24);
|
|
model:SetCamera(0);
|
|
model:SetPortraitZoom(1);
|
|
model:SetAnimation(0, 0);
|
|
model:SetPaused(true);
|
|
model:SetScript("OnModelLoaded", PortaitModel_OnModelLoaded);
|
|
model:SetViewTranslation(0, 0);
|
|
TransitionAPI.SetModelLight(model, true, false, cos(pi/4)*sin(-pi/4) , cos(pi/4)*cos(-pi/4) , -cos(pi/4), 1, 0.5, 0.5, 0.5, 1, 0.9, 0.9, 0.9);
|
|
end
|
|
|
|
function ModelPool:SetActiveModelPool(poolID)
|
|
self:ReleaseModels();
|
|
if not self.pools[poolID] then
|
|
self.pools[poolID] = {};
|
|
end
|
|
self.activeModelPool = self.pools[poolID];
|
|
end
|
|
|
|
function ModelPool:AcquireModel(modelID)
|
|
if not self.activeModelPool[modelID] then
|
|
self.activeModelPool[modelID] = CreateFrame("PlayerModel", nil, self.container);
|
|
self.SetupModel( self.activeModelPool[modelID] );
|
|
end
|
|
return self.activeModelPool[modelID]
|
|
end
|
|
|
|
function ModelPool:ReleaseModels()
|
|
if self.activeModelPool then
|
|
for _, model in pairs(self.activeModelPool) do
|
|
model:Hide();
|
|
model:ClearAllPoints();
|
|
model:SetParent(self.container);
|
|
model:SetPoint("TOP", self.container, "TOP", 0, 0);
|
|
end
|
|
end
|
|
end
|
|
|
|
function ModelPool:AssignModelToButton(savedLookButton, identifier)
|
|
local model = self:AcquireModel(identifier);
|
|
model:ClearAllPoints();
|
|
model:SetPoint("CENTER", savedLookButton.Border, "CENTER", 0, 0);
|
|
model:SetParent(savedLookButton);
|
|
model:SetFrameLevel(savedLookButton:GetFrameLevel());
|
|
model:Show();
|
|
model.parentButton = savedLookButton;
|
|
savedLookButton.Model = model;
|
|
end
|
|
|
|
|
|
local ALTERNATE_FORM_SAVED_ID = "alternateForm"; --OLD:220 (number)
|
|
local MAX_SAVES = 20;
|
|
local NUM_ACTIVE_BUTTONS = 0;
|
|
local SCROLLFRAME_CENTER_Y;
|
|
|
|
local function UpdateScrollButtonAlpha(buttons)
|
|
local button;
|
|
local alpha;
|
|
local x, y, dy;
|
|
|
|
for i = 1, NUM_ACTIVE_BUTTONS do
|
|
button = buttons[i];
|
|
x, y = button:GetCenter();
|
|
dy = abs(y - SCROLLFRAME_CENTER_Y);
|
|
if dy < 128 then
|
|
alpha = 1;
|
|
button:Show();
|
|
else
|
|
alpha = 1 - (dy - 128)/64;
|
|
if alpha < 0 then
|
|
alpha = 0;
|
|
button:Hide();
|
|
else
|
|
button:Show();
|
|
if alpha > 1 then
|
|
alpha = 1;
|
|
end
|
|
end
|
|
end
|
|
button:SetButtonAlpha(alpha);
|
|
end
|
|
end
|
|
|
|
local ScrollButtonAlphaUpdater = CreateFrame("Frame");
|
|
ScrollButtonAlphaUpdater:Hide();
|
|
ScrollButtonAlphaUpdater.t = 0;
|
|
ScrollButtonAlphaUpdater.duration = 1/60;
|
|
ScrollButtonAlphaUpdater:SetScript("OnUpdate", function(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t >= self.duration then
|
|
self.t = 0;
|
|
UpdateScrollButtonAlpha(self.activeButtons);
|
|
end
|
|
end);
|
|
|
|
function ScrollButtonAlphaUpdater:Start()
|
|
self:Show();
|
|
end
|
|
|
|
function ScrollButtonAlphaUpdater:Stop()
|
|
self:Hide();
|
|
end
|
|
|
|
function ScrollButtonAlphaUpdater:Refresh()
|
|
UpdateScrollButtonAlpha(self.activeButtons);
|
|
end
|
|
|
|
function ScrollButtonAlphaUpdater:SetActiveButtonAlpha(alpha)
|
|
for i = 1, NUM_ACTIVE_BUTTONS do
|
|
self.activeButtons[i]:SetButtonAlpha(alpha);
|
|
end
|
|
end
|
|
|
|
local ScrollBoundMarkUpdater = CreateFrame("Frame");
|
|
ScrollBoundMarkUpdater:Hide();
|
|
ScrollBoundMarkUpdater.t = 0;
|
|
ScrollBoundMarkUpdater.duration = 0.2;
|
|
ScrollBoundMarkUpdater.lastAlpha = 0;
|
|
ScrollBoundMarkUpdater:SetScript("OnUpdate", function(self, elapsed)
|
|
local alpha = self.lastAlpha + 2 * elapsed;
|
|
self.lastAlpha = alpha;
|
|
if alpha >= self.toAlpha then
|
|
alpha = self.toAlpha;
|
|
self:Hide();
|
|
end
|
|
self.object1:SetAlpha(alpha);
|
|
self.object2:SetAlpha(alpha);
|
|
end);
|
|
|
|
function ScrollBoundMarkUpdater:Start()
|
|
self.lastAlpha = 0; --self.object1:GetAlpha();
|
|
self.toAlpha = 0.5;
|
|
self:Show();
|
|
end
|
|
|
|
function ScrollBoundMarkUpdater:Stop()
|
|
self:Hide();
|
|
end
|
|
|
|
local function UpdateScrollBoundMark(ScrollFrame)
|
|
local scrollValue = ScrollFrame.scrollBar:GetValue();
|
|
local a, b = ScrollFrame.scrollBar:GetMinMaxValues();
|
|
local isTop = scrollValue <= 0.1;
|
|
local isBottom = scrollValue + 0.1 >= b;
|
|
local numButtons = NUM_ACTIVE_BUTTONS or 0;
|
|
ScrollFrame.BoundTop:SetShown(not isTop);
|
|
ScrollFrame.BoundBottom:SetShown(not isBottom);
|
|
|
|
ScrollFrame.BoundTop:SetAlpha(0);
|
|
ScrollFrame.BoundBottom:SetAlpha(0);
|
|
|
|
ScrollBoundMarkUpdater:Start();
|
|
end
|
|
|
|
local function UpdateScrollRange(initialOffset)
|
|
local scrollFrame = ScrollModelFrame;
|
|
|
|
local range;
|
|
local numButtons = NUM_ACTIVE_BUTTONS;
|
|
if numButtons == 0 then
|
|
range = 0;
|
|
else
|
|
range = (64 + 16) * numButtons -16 - scrollFrame:GetHeight() + 14; --the active sex is not neccessarily male, just use the male buttons for height referencing
|
|
if range < 0 then
|
|
range = 0;
|
|
end
|
|
end
|
|
|
|
local scrollBar = scrollFrame.scrollBar;
|
|
scrollBar:SetMinMaxValues(0, range);
|
|
scrollFrame.range = range;
|
|
scrollBar:SetShown(range ~= 0);
|
|
|
|
ScrollModelFrame:SnapToOffset(initialOffset or 0);
|
|
|
|
UpdateScrollButtonAlpha(ScrollButtonAlphaUpdater.activeButtons);
|
|
UpdateScrollBoundMark(scrollFrame);
|
|
|
|
if numButtons >= MAX_SAVES then
|
|
PlusButton:SetCase(3);
|
|
end
|
|
PlusButton.numSaves = numButtons;
|
|
end
|
|
|
|
local function CreateSavedLooksButton(scrollFrame, sex, isAlternateForm)
|
|
local button;
|
|
local buttons = {};
|
|
local scrollChild = scrollFrame.ScrollChild;
|
|
local buttonHeight = 64;
|
|
local frameHeight = 4 * (buttonHeight + 16) - 2;
|
|
scrollFrame:SetSize(280, frameHeight);
|
|
scrollChild:SetSize(280, frameHeight);
|
|
|
|
for i = 1, MAX_SAVES do
|
|
button = CreateFrame("Button", nil, scrollFrame.ClipFrame, "NarciBarberShopSavedLooksTemplate");
|
|
tinsert(buttons, button);
|
|
button:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -8 + (buttonHeight + 16)*(1 - i));
|
|
button.order = i;
|
|
button:Hide();
|
|
end
|
|
|
|
local deltaRatio = 1;
|
|
local speedRatio = 0.14;
|
|
local range = buttons[1]:GetTop() - buttons[MAX_SAVES]:GetBottom() - scrollFrame:GetHeight() + 14;
|
|
local parentScrollFunc;
|
|
local positionFunc = function(endValue, delta, scrollBar, isTop, isBottom)
|
|
ScrollButtonAlphaUpdater:Start();
|
|
scrollFrame.BoundTop:SetShown(not isTop);
|
|
scrollFrame.BoundBottom:SetShown(not isBottom);
|
|
ScrollBoundMarkUpdater:Stop();
|
|
scrollFrame.BoundTop:SetAlpha(0.0);
|
|
scrollFrame.BoundBottom:SetAlpha(0.0);
|
|
scrollFrame.BoundTop:StopAnimating();
|
|
scrollFrame.BoundBottom:StopAnimating();
|
|
end;
|
|
|
|
local onScrollFinishedFunc = function()
|
|
ScrollButtonAlphaUpdater:Stop();
|
|
ScrollBoundMarkUpdater:Start();
|
|
scrollFrame.BoundTop.BoundTopArrow.spring:Play();
|
|
scrollFrame.BoundBottom.BoundBottomArrow.spring:Play();
|
|
end
|
|
|
|
ScrollBoundMarkUpdater.object1 = scrollFrame.BoundTop;
|
|
ScrollBoundMarkUpdater.object2 = scrollFrame.BoundBottom;
|
|
|
|
NarciAPI_ApplySmoothScrollToScrollFrame(scrollFrame, deltaRatio, speedRatio, positionFunc, (buttonHeight + 16), range, parentScrollFunc, onScrollFinishedFunc);
|
|
|
|
SavedLookButtons = buttons;
|
|
ScrollButtonAlphaUpdater.activeButtons = buttons;
|
|
end
|
|
|
|
|
|
local DataProvider = {};
|
|
DataProvider.maleButtonOrder = {};
|
|
DataProvider.femaleButtonOrder = {};
|
|
DataProvider.alternateMaleButtonOrder = {};
|
|
DataProvider.alternateFemaleButtonOrder = {};
|
|
|
|
function DataProvider:GetCurrentSelection(customizationData, generateDescription)
|
|
customizationData = customizationData or C_BarberShop.GetAvailableCustomizations();
|
|
if not customizationData then
|
|
return
|
|
end
|
|
local numCatetroy = #customizationData;
|
|
local options, optionName, optionID, cuurentChoiceIndex, choice, choiceName, choiceID;
|
|
local selectedOptions = {};
|
|
local description = "";
|
|
local addComma = false;
|
|
|
|
local total = 0;
|
|
|
|
for i = 1, numCatetroy do
|
|
options = customizationData[i].options;
|
|
local numOptions = #options;
|
|
for j = 1, numOptions do
|
|
optionName = options[j].name;
|
|
optionID = options[j].id;
|
|
cuurentChoiceIndex = options[j].currentChoiceIndex or 1;
|
|
choice = options[j].choices[cuurentChoiceIndex];
|
|
choiceName = choice.name or "";
|
|
choiceID = choice.id;
|
|
tinsert(selectedOptions, {optionID, choiceID} );
|
|
total = total + 1;
|
|
if generateDescription then
|
|
if choiceName ~= "" and choiceName ~= "None" then
|
|
if addComma then
|
|
description = description..", ";
|
|
else
|
|
addComma = true;
|
|
end
|
|
description = description.. choiceName.." "..optionName;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return selectedOptions, description
|
|
end
|
|
|
|
--sex 0 - Male 1- Female C_BarberShop.SetSelectedSex;
|
|
|
|
local RaceAtlas = {};
|
|
|
|
RaceAtlas.fixedRaceAtlasNames = {
|
|
["highmountaintauren"] = "highmountain",
|
|
["lightforgeddraenei"] = "lightforged",
|
|
["scourge"] = "undead",
|
|
["zandalaritroll"] = "zandalari",
|
|
};
|
|
|
|
RaceAtlas.alternateFormAtlasNames = {
|
|
["dracthyr"] = "dracthyrvisage", --visage
|
|
["worgen"] = "human",
|
|
};
|
|
|
|
RaceAtlas.fixedModelAtlasNames = {
|
|
--chrModelID
|
|
[124] = "dragonriding-barbershop-icon-protodrake",
|
|
[129] = "dragonriding-barbershop-icon-pterrodax",
|
|
[123] = "dragonriding-barbershop-icon-drake",
|
|
[126] = "dragonriding-barbershop-icon-wyvernspirit",
|
|
--10.1.0
|
|
[125] = "dragonriding-barbershop-icon-slitherdrake",
|
|
--10.2.0
|
|
[149] = "dragonriding-barbershop-icon-netherwingdrake",
|
|
[188] = "dragonriding-barbershop-icon-faeriedragon",
|
|
};
|
|
|
|
function RaceAtlas:GetAtlas(raceName, gender, alternateForm)
|
|
if self.fixedModelAtlasNames[raceName] then
|
|
return self.fixedModelAtlasNames[raceName]
|
|
end
|
|
|
|
if alternateForm and self.alternateFormAtlasNames[raceName] then
|
|
raceName = self.alternateFormAtlasNames[raceName];
|
|
end
|
|
|
|
if (self.fixedRaceAtlasNames[raceName]) then
|
|
raceName = self.fixedRaceAtlasNames[raceName];
|
|
end
|
|
|
|
if not raceName then
|
|
raceName = "human";
|
|
end
|
|
|
|
gender = gender or "none";
|
|
|
|
local formatingString = "raceicon128-%s-%s"; --"raceicon-%s-%s"
|
|
return formatingString:format(raceName, gender);
|
|
end
|
|
|
|
--[[
|
|
local f = CreateFrame("Frame");
|
|
f:SetSize(96, 96);
|
|
f:SetPoint("CENTER", 0, 0);
|
|
local tex = f:CreateTexture(nil, "OVERLAY");
|
|
tex:SetAllPoints(true);
|
|
tex:SetAtlas( RaceAtlas:GetAtlas("dracthyr", "male", true, true) )
|
|
--]]
|
|
|
|
|
|
local function SetUpSavedLooksButton(dataSource, atlas)
|
|
local numActiveButtons = #dataSource;
|
|
local numVisibleButtons = math.min(4, numActiveButtons);
|
|
for i, button in ipairs(SavedLookButtons) do
|
|
if i <= numVisibleButtons then
|
|
button:Show();
|
|
else
|
|
button:Hide();
|
|
end
|
|
button:SetInfo(dataSource[i]);
|
|
button.Portrait:SetAtlas(atlas);
|
|
if button:IsPortraitLoaded() then
|
|
button.Portrait:Hide();
|
|
else
|
|
button.Portrait:Show();
|
|
end
|
|
end
|
|
end
|
|
|
|
function DataProvider:SetActiveDatabase(key, sex)
|
|
if not key then
|
|
key = self.raceID;
|
|
end
|
|
|
|
if not self.playerAppearanceDB[key] then
|
|
self.playerAppearanceDB[key] = {};
|
|
end
|
|
|
|
if sex then
|
|
if not self.playerAppearanceDB[key][sex] then
|
|
self.playerAppearanceDB[key][sex] = {};
|
|
end
|
|
self.activeDB = self.playerAppearanceDB[key][sex]
|
|
else
|
|
self.activeDB = self.playerAppearanceDB[key]
|
|
end
|
|
return self.activeDB
|
|
end
|
|
|
|
function DataProvider:GetActiveDatabase()
|
|
return self.activeDB
|
|
end
|
|
|
|
function DataProvider:GetActiveNumSaves()
|
|
if self.activeDB then
|
|
return #self.activeDB;
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
local function GetRaceFileName(characterData)
|
|
local fileName;
|
|
if characterData then
|
|
if characterData.raceData then
|
|
fileName = characterData.raceData.fileName;
|
|
else
|
|
fileName = characterData.fileName;
|
|
end
|
|
end
|
|
return fileName or "human";
|
|
end
|
|
|
|
function DataProvider:LoadData()
|
|
local raceID = API.GetPlayerRaceID();
|
|
self.raceID = raceID or 1;
|
|
|
|
if not NarciBarberShopDB then
|
|
NarciBarberShopDB = {};
|
|
end
|
|
|
|
local DB = NarciBarberShopDB;
|
|
|
|
--wipe(DB) --!!TEST
|
|
|
|
if not DB.PlayerData then
|
|
DB.PlayerData = {};
|
|
end
|
|
|
|
local unitType, realmID, playerID = string.split("-", UnitGUID("player"));
|
|
if not DB.PlayerData[playerID] then
|
|
local playerName = UnitName("player");
|
|
local realmName = GetRealmName();
|
|
DB.PlayerData[playerID] = { SavedLooks = {} , realmID = realmID, playerName = playerName, realmName = realmName};
|
|
end
|
|
|
|
local playerAppearanceDB = DB.PlayerData[playerID].SavedLooks;
|
|
self.playerAppearanceDB = playerAppearanceDB;
|
|
|
|
if not playerAppearanceDB[raceID] then
|
|
playerAppearanceDB[raceID] = {male = {}, female = {}};
|
|
end
|
|
self.savedLooksByRace = playerAppearanceDB[raceID];
|
|
|
|
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
|
|
local raceName = GetRaceFileName(currentCharacterData);
|
|
raceName = string.lower(raceName);
|
|
|
|
CreateSavedLooksButton(ScrollModelFrame, "male");
|
|
|
|
|
|
--Migrate Old Saves
|
|
if playerAppearanceDB[220] then
|
|
local function CopyTable(tbl)
|
|
local copy = {};
|
|
for k, v in pairs(tbl) do
|
|
if type(v) == "table" then
|
|
copy[k] = CopyTable(v);
|
|
else
|
|
copy[k] = v;
|
|
end
|
|
end
|
|
return copy;
|
|
end
|
|
playerAppearanceDB[ALTERNATE_FORM_SAVED_ID] = CopyTable(playerAppearanceDB[220]);
|
|
playerAppearanceDB[220] = nil;
|
|
end
|
|
|
|
|
|
--Worgen in human form. Dracthyr in visage form.
|
|
if RACE_WITH_ALTERNATE_FORM[raceID] then
|
|
HAS_ALTERNATE_FORM = true;
|
|
local id = ALTERNATE_FORM_SAVED_ID;
|
|
|
|
if not playerAppearanceDB[id] then
|
|
playerAppearanceDB[id] = { male = {}, female = {} };
|
|
end
|
|
self.savedLooksInAlternateForm = playerAppearanceDB[id];
|
|
end
|
|
|
|
for i = 1, MAX_SAVES do
|
|
self.maleButtonOrder[i] = i;
|
|
self.femaleButtonOrder[i] = i;
|
|
self.alternateMaleButtonOrder[i] = i;
|
|
self.alternateFemaleButtonOrder[i] = i;
|
|
end
|
|
end
|
|
|
|
function DataProvider:GetRandomAppearance() --Unused
|
|
local customizationData = C_BarberShop.GetAvailableCustomizations();
|
|
if not customizationData then --Not at the Barber
|
|
return
|
|
end
|
|
|
|
local random = math.random;
|
|
local selectedOptions = {};
|
|
|
|
local option, options, optionName, optionID, cuurentChoiceIndex, choice, choiceName, choiceID;
|
|
local numCatetroy = #customizationData;
|
|
for i = 1, numCatetroy do
|
|
options = customizationData[i].options;
|
|
local numOptions = #options;
|
|
for j = 1, numOptions do
|
|
option = options[j];
|
|
optionName = option.name;
|
|
optionID = option.id;
|
|
local numChoices = #option.choices;
|
|
choice = option.choices[ random(numChoices) ]
|
|
choiceID = choice.id;
|
|
tinsert(selectedOptions, {optionID, choiceID} );
|
|
end
|
|
end
|
|
|
|
return selectedOptions
|
|
end
|
|
|
|
function DataProvider:IsNewLooksUnique()
|
|
local newLooks, generatedDescription = DataProvider:GetCurrentSelection();
|
|
if not newLooks then
|
|
return
|
|
end
|
|
local checkOnly = true;
|
|
local isUnique = self:CheckAndSaveLooks(newLooks, nil, nil, checkOnly);
|
|
return isUnique
|
|
end
|
|
|
|
function DataProvider:IsCharacterDataUnique(customizationData)
|
|
local newLooks = self:GetCurrentSelection(customizationData);
|
|
local savedLooks = self:GetActiveDatabase();
|
|
|
|
local isUnique = true;
|
|
local tempTable = {};
|
|
local numLooks = #savedLooks;
|
|
local data;
|
|
local matchID;
|
|
local profileName;
|
|
|
|
for i = 1, numLooks do
|
|
wipe(tempTable);
|
|
data = savedLooks[i].data;
|
|
local numData = #data;
|
|
for j = 1, numData do
|
|
tempTable[ data[j][1] ] = data[j][2];
|
|
end
|
|
|
|
local numSame = 0;
|
|
for j = 1, #newLooks do
|
|
if tempTable[ newLooks[j][1] ] == newLooks[j][2] then
|
|
numSame = numSame + 1;
|
|
end
|
|
end
|
|
|
|
if numSame == numData then
|
|
isUnique = false;
|
|
matchID = i;
|
|
profileName = savedLooks[i].name;
|
|
break
|
|
end
|
|
end
|
|
|
|
if IS_SAVE_SUPPORTED then
|
|
if isUnique then
|
|
if numLooks < MAX_SAVES then
|
|
PlusButton:SetCase(1);
|
|
else
|
|
PlusButton:SetCase(3);
|
|
end
|
|
else
|
|
PlusButton:SetCase(2);
|
|
end
|
|
end
|
|
|
|
PlusButton.numSaves = numLooks;
|
|
|
|
if SavedLookButtons then
|
|
for i, portraitButton in ipairs(SavedLookButtons) do
|
|
portraitButton:SetSelection(i == matchID);
|
|
end
|
|
end
|
|
|
|
API.SetActiveAppearanceName(profileName);
|
|
end
|
|
|
|
|
|
function DataProvider:CheckAndSaveLooks(newLooks, generatedDescription, customName, checkOnly)
|
|
if not newLooks then return false end;
|
|
|
|
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
|
|
if not currentCharacterData then return false end;
|
|
|
|
local targetDB = self:GetActiveDatabase();
|
|
|
|
local isUnique = true;
|
|
local data;
|
|
|
|
local tempTable = {};
|
|
local numLooks = #targetDB;
|
|
for i = 1, numLooks do
|
|
wipe(tempTable);
|
|
data = targetDB[i].data;
|
|
local numData = #data;
|
|
for j = 1, numData do
|
|
tempTable[ data[j][1] ] = data[j][2];
|
|
end
|
|
|
|
local numSame = 0;
|
|
for j = 1, #newLooks do
|
|
if tempTable[ newLooks[j][1] ] == newLooks[j][2] then
|
|
numSame = numSame + 1;
|
|
end
|
|
end
|
|
|
|
if numSame == numData then
|
|
isUnique = false;
|
|
break
|
|
end
|
|
end
|
|
|
|
wipe(tempTable);
|
|
numLooks = numLooks + 1;
|
|
|
|
if numLooks > MAX_SAVES then
|
|
return false
|
|
end
|
|
|
|
local looksName = customName or ("New Look #"..(numLooks));
|
|
if isUnique then
|
|
if checkOnly then
|
|
return true;
|
|
else
|
|
if numLooks < MAX_SAVES then
|
|
PlusButton:SetCase(2);
|
|
else
|
|
PlusButton:SetCase(3);
|
|
end
|
|
local currentTime = time();
|
|
tinsert(targetDB, 1, {name = looksName , description = generatedDescription, data = newLooks, timeCreated = currentTime});
|
|
return targetDB[1], numLooks
|
|
end
|
|
else
|
|
PlusButton:SetCase(2);
|
|
end
|
|
PlusButton.numSaves = numLooks;
|
|
end
|
|
|
|
function DataProvider:SaveNewLooks(customName)
|
|
if NUM_ACTIVE_BUTTONS >= MAX_SAVES then
|
|
return
|
|
end
|
|
local generateDescription = true;
|
|
local newLooks, generatedDescription = DataProvider:GetCurrentSelection(nil, generateDescription);
|
|
local data, numLooks = self:CheckAndSaveLooks(newLooks, generatedDescription, customName);
|
|
if data then
|
|
NUM_ACTIVE_BUTTONS = numLooks;
|
|
if numLooks >= 4 then
|
|
ScrollBoundMarkUpdater:Start();
|
|
end
|
|
|
|
return data
|
|
else
|
|
|
|
end
|
|
end
|
|
|
|
local function RepositionButtons(buttonPool)
|
|
local _, relativeTo = buttonPool[1]:GetPoint();
|
|
local buttonHeight = 64;
|
|
local button;
|
|
for i = 1, MAX_SAVES do
|
|
button = buttonPool[i];
|
|
button:ClearAllPoints();
|
|
button:SetPoint("TOPLEFT", relativeTo, "TOPLEFT", 0, -8 + (buttonHeight + 16)*(1 - i));
|
|
button.order = i;
|
|
end
|
|
end
|
|
|
|
local function InsertButtonToTop(buttonPool, position)
|
|
local removedButton = tremove(buttonPool, position);
|
|
if removedButton then
|
|
for i = #buttonPool, 1, -1 do
|
|
buttonPool[i + 1] = buttonPool[i];
|
|
end
|
|
buttonPool[1] = removedButton;
|
|
--RepositionButtons(buttonPool);
|
|
end
|
|
end
|
|
|
|
function DataProvider:DeleteLooks(dataSource)
|
|
if not dataSource then return end;
|
|
|
|
local savedLooks = self:GetActiveDatabase();
|
|
local numLooks = #savedLooks;
|
|
local position;
|
|
for i = 1, numLooks do
|
|
if savedLooks[i] == dataSource then
|
|
position = i;
|
|
break
|
|
end
|
|
end
|
|
if position then
|
|
for i = position, numLooks do
|
|
savedLooks[i] = savedLooks[i + 1];
|
|
end
|
|
|
|
local removedButton = tremove(SavedLookButtons, position);
|
|
removedButton:RemovePortrait();
|
|
removedButton.appearanceData = nil;
|
|
tinsert(SavedLookButtons, removedButton);
|
|
NUM_ACTIVE_BUTTONS = NUM_ACTIVE_BUTTONS - 1;
|
|
|
|
local buttonPool = SavedLookButtons;
|
|
return buttonPool, removedButton, position
|
|
end
|
|
end
|
|
|
|
function DataProvider:GetButton()
|
|
local numSaves = self:GetActiveNumSaves();
|
|
local numNewSaves = numSaves + 1;
|
|
if numNewSaves > MAX_SAVES then
|
|
numNewSaves = MAX_SAVES;
|
|
end
|
|
InsertButtonToTop(SavedLookButtons, numNewSaves);
|
|
return SavedLookButtons[1]
|
|
end
|
|
|
|
|
|
local function SetFontStringShadow(fontString)
|
|
fontString:SetShadowColor(0, 0, 0);
|
|
fontString:SetShadowOffset(1, -1);
|
|
end
|
|
|
|
-------------------------------------------------------------
|
|
|
|
local CustomizationUtil = {};
|
|
CustomizationUtil.f = CreateFrame("Frame");
|
|
|
|
function CustomizationUtil.repeater_OnUpdate(f, elapsed)
|
|
--Dracthyr Notes:
|
|
--some options are only valid when certain options are selected
|
|
--so we need to apply the same appearance profile again to ensure everything we need is selected
|
|
--Arbitrarily use a 2-frame delay
|
|
|
|
f.t = f.t + elapsed;
|
|
|
|
if f.t > 0.033 then
|
|
f:SetScript("OnUpdate", nil);
|
|
for i = 1, #CustomizationUtil.appearanceData do
|
|
local optionID, choiceID = unpack(CustomizationUtil.appearanceData[i]);
|
|
SetCustomizationChoice(optionID, choiceID);
|
|
end
|
|
BarberShopUI:UpdateCharCustomizationFrame();
|
|
end
|
|
end
|
|
|
|
function CustomizationUtil:UseCustomization(appearanceData)
|
|
--appearanceData consisted of formated optionID-choiceID pairs
|
|
if not appearanceData then return end;
|
|
|
|
self.f:SetScript("OnUpdate", nil);
|
|
self.appearanceData = appearanceData;
|
|
|
|
local optionID, choiceID;
|
|
for i = 1, #appearanceData do
|
|
optionID, choiceID = unpack(appearanceData[i]);
|
|
SetCustomizationChoice(optionID, choiceID);
|
|
end
|
|
|
|
self.f.t = 0;
|
|
self.f:SetScript("OnUpdate", self.repeater_OnUpdate);
|
|
end
|
|
|
|
function CustomizationUtil:ApplyCustomizationCategoryData(customizationCategoryData, firstCall)
|
|
--customizationCategoryData is the raw payload from C_BarberShop.GetAvailableCustomizations()
|
|
local optionID, cuurentChoiceIndex, choice, choiceID;
|
|
for i, data in ipairs(customizationCategoryData) do
|
|
for j, option in ipairs(data.options) do
|
|
optionID = option.id;
|
|
cuurentChoiceIndex = option.currentChoiceIndex or 1;
|
|
choice = option.choices[cuurentChoiceIndex];
|
|
choiceID = choice.id;
|
|
SetCustomizationChoice(optionID, choiceID);
|
|
end
|
|
end
|
|
|
|
if firstCall then
|
|
After(0.033, function()
|
|
self:ApplyCustomizationCategoryData(customizationCategoryData);
|
|
DataProvider:IsCharacterDataUnique();
|
|
end);
|
|
end
|
|
end
|
|
|
|
|
|
NarciBarberShopSavedLooksMixin = {};
|
|
|
|
|
|
function NarciBarberShopSavedLooksMixin:OnLoad()
|
|
self.Portrait:SetVertexColor(0.5, 0.5, 0.5);
|
|
self.Portrait:SetDesaturation(0.6);
|
|
SetFontStringShadow(self.Description);
|
|
self:OnLeave();
|
|
end
|
|
|
|
|
|
function NarciBarberShopSavedLooksMixin:RefreshPortrait(forcedRefresh)
|
|
if (not self:IsPortraitLoaded()) or (forcedRefresh) then
|
|
self.Model:Show();
|
|
self.Portrait:Hide();
|
|
self.PortraitText:Hide();
|
|
self.isPortraitLoaded = true;
|
|
self.Model:SetUnit("player");
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:UpdateText()
|
|
local textHeight = self.Name:GetHeight() + self.Description:GetHeight() + 6;
|
|
self.Reference:SetHeight(textHeight);
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:SetInfo(dataSource)
|
|
self.dataSource = dataSource;
|
|
if dataSource then
|
|
ModelPool:AssignModelToButton(self, tostring(dataSource.timeCreated));
|
|
self.Name:SetText(dataSource.name);
|
|
self.Description:SetText(dataSource.description);
|
|
self.appearanceData = dataSource.data;
|
|
self:UpdateText();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:OnEnter()
|
|
self.Name:SetAlpha(1);
|
|
self.Description:SetAlpha(1);
|
|
FadeFrame(self.BorderHighlight, 0.15, 1);
|
|
MainFrame:FadeIn(0.2);
|
|
--self.Model:SetPaused(false); --Playing character idle animation seems distractive, disabled
|
|
|
|
EditButton:SetParentObject(self);
|
|
DeleteButton:SetParentObject(self);
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:OnLeave()
|
|
if self:IsMouseOver() and IsWidgetFocused(self) then
|
|
return
|
|
end
|
|
self.Name:SetAlpha(0.66);
|
|
self.Description:SetAlpha(0.66);
|
|
FadeFrame(self.BorderHighlight, 0.25, 0);
|
|
MainFrame:OnLeave();
|
|
|
|
EditButton:Hide();
|
|
DeleteButton:Hide();
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:OnClick()
|
|
--self:UseCustomization();
|
|
CustomizationUtil:UseCustomization(self.appearanceData);
|
|
|
|
if not self:IsPortraitLoaded() then
|
|
After(UPDATE_PORTRAIT_DELAY, function()
|
|
self:RefreshPortrait();
|
|
end)
|
|
end
|
|
|
|
PlaySound(856); --SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:RemovePortrait()
|
|
if self.Model then
|
|
self.Model.isModelLoaded = nil;
|
|
self.Model:ClearModel();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:IsPortraitLoaded()
|
|
if self.Model then
|
|
return self.Model.isModelLoaded
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:LoadPortrait()
|
|
self:UseCustomization(true);
|
|
if not self:IsPortraitLoaded() then
|
|
After(UPDATE_PORTRAIT_DELAY, function()
|
|
self:RefreshPortrait();
|
|
end)
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:UseCustomization(dontUpdateButton)
|
|
if not self.appearanceData then return end
|
|
|
|
for i = 1, #self.appearanceData do
|
|
local optionID, choiceID = unpack(self.appearanceData[i]);
|
|
SetCustomizationChoice(optionID, choiceID);
|
|
--C_BarberShop.PreviewCustomizationChoice(optionID, choiceID);
|
|
end
|
|
|
|
if not dontUpdateButton then
|
|
--determine if it should update the option buttons on the right side of the screen
|
|
BarberShopUI:UpdateCharCustomizationFrame();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSavedLooksMixin:SetSelection(state)
|
|
if state then
|
|
if not self.isSelected then
|
|
self.isSelected = true;
|
|
self.Border:SetTexCoord(0.5, 1, 0, 1);
|
|
end
|
|
else
|
|
if self.isSelected then
|
|
self.isSelected = nil;
|
|
self.Border:SetTexCoord(0, 0.5, 0, 1);
|
|
end
|
|
end
|
|
end
|
|
|
|
if addon.IsDragonflight() then
|
|
function NarciBarberShopSavedLooksMixin:SetButtonAlpha(alpha)
|
|
--Dragonflight Beta: Model no longer inherts parent alpha.
|
|
--Probably a driver issue that only took place in beta but still
|
|
self:SetAlpha(alpha);
|
|
if self.Model then
|
|
self.Model:SetModelAlpha(alpha); --SetAlpha caused the model to flicker
|
|
end
|
|
self.buttonAlpha = alpha;
|
|
end
|
|
else
|
|
function NarciBarberShopSavedLooksMixin:SetButtonAlpha(alpha)
|
|
self:SetAlpha(alpha);
|
|
end
|
|
end
|
|
|
|
|
|
----------------------------------
|
|
local DURATION_FADE_OUT = 1.5;
|
|
|
|
local autoHideTimer = NarciAPI_CreateAnimationFrame(4);
|
|
autoHideTimer:SetScript("OnUpdate", function(self, elapsed)
|
|
self.total = self.total + elapsed;
|
|
if self.total >= self.duration then
|
|
self.total = 0;
|
|
if MainFrame:IsVisible() then
|
|
if not MainFrame:IsMouseOver() then
|
|
self:Hide();
|
|
MainFrame:FadeOut(DURATION_FADE_OUT);
|
|
end
|
|
else
|
|
self:Hide();
|
|
end
|
|
end
|
|
end)
|
|
|
|
local animScrollFrame = NarciAPI_CreateAnimationFrame(0.25);
|
|
animScrollFrame:SetScript("OnUpdate", function(self, elapsed)
|
|
self.total = self.total + elapsed;
|
|
local offsetY = linear(self.total, self.fromY, 0, self.duration);
|
|
if self.total >= self.duration then
|
|
self:Hide();
|
|
offsetY = 0;
|
|
ScrollButtonAlphaUpdater:Stop();
|
|
if self.onFinishedFunc then
|
|
self.onFinishedFunc();
|
|
self.onFinishedFunc = nil;
|
|
end
|
|
end
|
|
self.parentScrollBar:SetValue(offsetY);
|
|
end);
|
|
|
|
function animScrollFrame:ScrollToTop(ScrollFrame)
|
|
self:Hide();
|
|
local value = ScrollFrame:GetVerticalScroll();
|
|
if value == 0 then
|
|
return
|
|
end
|
|
self.parentScrollBar = ScrollFrame.scrollBar;
|
|
self.fromY = value;
|
|
local duration = sqrt( value/ 400) * 0.25;
|
|
self.duration = duration;
|
|
ScrollButtonAlphaUpdater:Start();
|
|
self:Show();
|
|
end
|
|
|
|
|
|
local animScrollButtons = NarciAPI_CreateAnimationFrame(0.4);
|
|
|
|
animScrollButtons:SetScript("OnUpdate", function(self, elapsed)
|
|
self.total = self.total + elapsed;
|
|
local offsetY = outSine(self.total, self.fromY, self.toY, self.duration);
|
|
|
|
if self.newButton then
|
|
local alpha = self.total/0.35;
|
|
if alpha > 1 then
|
|
alpha = 1;
|
|
end
|
|
local offsetX = inOutSine(self.total, -32, 0, self.duration);
|
|
self.newButton:Show();
|
|
self.newButton:SetAlpha(alpha);
|
|
if self.total >= self.duration then
|
|
offsetX = 0;
|
|
offsetY = self.toY;
|
|
end
|
|
self.newButton:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", offsetX, -8);
|
|
end
|
|
|
|
if self.oldButton then
|
|
local alpha = 1 - self.total/0.35;
|
|
|
|
if alpha < 0 then
|
|
alpha = 0;
|
|
self.oldButton:Hide();
|
|
end
|
|
local offsetX = outSine(self.total, 0, -120, self.duration);
|
|
self.oldButton:SetAlpha(alpha);
|
|
if self.total >= self.duration then
|
|
offsetX = -64;
|
|
end
|
|
self.oldButton:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", offsetX, self.oldButtonPosY);
|
|
end
|
|
|
|
if self.forthButton then
|
|
local alpha = self.fromAlpha - self.total/0.25;
|
|
if alpha < 0 then
|
|
alpha = 0;
|
|
end
|
|
self.forthButton:SetAlpha(alpha);
|
|
if alpha == 0 then
|
|
self.forthButton:Hide();
|
|
end
|
|
end
|
|
|
|
if self.total >= self.duration then
|
|
offsetY = self.toY;
|
|
self:Hide();
|
|
MainFrame.ScrollBlocker:Hide();
|
|
RepositionButtons(self.buttonPool);
|
|
UpdateScrollRange();
|
|
ScrollButtonAlphaUpdater:Stop();
|
|
end
|
|
|
|
for i = self.buttonIndex, self.numButtons do
|
|
self.buttonPool[i]:SetPoint("TOPLEFT", self.relativeTo, "TOPLEFT", 0, -8 + 80*(1 - i) + offsetY);
|
|
end
|
|
end)
|
|
|
|
function animScrollButtons:InsertNewButton(buttonPool, newButton)
|
|
self:Hide();
|
|
local _, ScrollChild = buttonPool[1]:GetPoint();
|
|
self.relativeTo = ScrollChild;
|
|
self.buttonPool = buttonPool;
|
|
self.numButtons = #buttonPool;
|
|
self.buttonIndex = 2;
|
|
self.newButton = newButton;
|
|
self.forthButton = buttonPool[5];
|
|
self.oldButton = nil;
|
|
self.fromAlpha = self.forthButton:GetAlpha();
|
|
self.fromY = 80;
|
|
self.toY = 0;
|
|
|
|
local ScrollFrame = ScrollChild:GetParent();
|
|
if ScrollFrame:GetVerticalScroll() > 0.1 then
|
|
--ScrollFrame.scrollBar:SetValue(0);
|
|
animScrollFrame.onFinishedFunc = function()
|
|
self:Show();
|
|
EditBox:SetParentObject(newButton, true);
|
|
end
|
|
animScrollFrame:ScrollToTop(ScrollFrame);
|
|
else
|
|
self:Show();
|
|
end
|
|
MainFrame.ScrollBlocker:Show();
|
|
end
|
|
|
|
function animScrollButtons:RemoveOldButton(buttonPool, button)
|
|
self:Hide();
|
|
self.forthButton = nil;
|
|
self.newButton = nil;
|
|
self.oldButton = button;
|
|
local _, ScrollChild, _, _, posY = button:GetPoint();
|
|
self.oldButtonPosY = posY;
|
|
self.buttonIndex = button.order;
|
|
self.relativeTo = ScrollChild;
|
|
self.buttonPool = buttonPool;
|
|
self.numButtons = #buttonPool - 1;
|
|
self.fromY = -80;
|
|
self.toY = 0;
|
|
self:Show();
|
|
ScrollButtonAlphaUpdater:Start();
|
|
MainFrame.ScrollBlocker:Show();
|
|
end
|
|
|
|
|
|
--Click to save new looks
|
|
NarciBarberShopPlusButtonMixin = {};
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnLoad()
|
|
PlusButton = self;
|
|
self:OnLeave();
|
|
self.tooltipDefault = L["Save New Look"];
|
|
self.tooltipReachMax = L["No Available Slot"];
|
|
self.tooltipSaved = L["Look Saved"];
|
|
self.tooltipShapeShifted = L["Cannot Save Forms"];
|
|
self:SetCase(1);
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnMouseDown()
|
|
if self:IsEnabled() then
|
|
self.Background:SetTexCoord(0.25, 0.5, 0, 1);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnMouseUp()
|
|
if self:IsEnabled() then
|
|
self.Background:SetTexCoord(0, 0.25, 0, 1);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnEnable()
|
|
self.Background:SetTexCoord(0, 0.25, 0, 1);
|
|
self.Label:SetTextColor(1, 1, 1);
|
|
self.Label:SetAlpha(0.66);
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnDisable()
|
|
self.Background:SetTexCoord(0.5, 0.75, 0, 1);
|
|
self.Label:SetTextColor(0.5, 0.5, 0.5);
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:SetCase(caseID)
|
|
if caseID == 1 then
|
|
--Can be added
|
|
self.Label:SetText(self.tooltipDefault);
|
|
self:Enable();
|
|
elseif caseID == 2 then
|
|
--Already saved
|
|
self.Label:SetText(self.tooltipSaved);
|
|
self:Disable();
|
|
elseif caseID == 3 then
|
|
--Cannot save more
|
|
self.Label:SetText(self.tooltipReachMax);
|
|
self:Disable();
|
|
elseif caseID == 4 then
|
|
--Cannot add shapes
|
|
self.Label:SetText(self.tooltipShapeShifted);
|
|
self:Disable();
|
|
end
|
|
|
|
self.caseID = caseID;
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:GetCase()
|
|
return self.caseID
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnEnter()
|
|
self.Label:SetAlpha(1);
|
|
MainFrame:OnEnter();
|
|
EditButton:Hide();
|
|
DeleteButton:Hide();
|
|
|
|
local labelWidth = self.Label:GetWrappedWidth();
|
|
self.Count:SetPoint("LEFT", self.Label, "LEFT", labelWidth + 8, 0);
|
|
|
|
if IS_SAVE_SUPPORTED then
|
|
if self.numSaves then
|
|
self.Count:SetText(self.numSaves.." / "..MAX_SAVES);
|
|
self.Count:Show();
|
|
else
|
|
self.Count:Hide();
|
|
end
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnLeave()
|
|
self.Label:SetAlpha(0.66);
|
|
self.Count:Hide();
|
|
end
|
|
|
|
local function SaveCurrentAppearance(customName)
|
|
if not PlusButton:IsEnabled() then return end;
|
|
|
|
local data = DataProvider:SaveNewLooks(customName);
|
|
if data then
|
|
local button = DataProvider:GetButton();
|
|
if button then
|
|
animScrollButtons:InsertNewButton(SavedLookButtons, button);
|
|
button:SetInfo(data);
|
|
button:Show();
|
|
button.Portrait:Show();
|
|
EditBox:SetParentObject(button, true);
|
|
After(UPDATE_PORTRAIT_DELAY, function()
|
|
button:RefreshPortrait(true);
|
|
button:SetSelection(true);
|
|
end);
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
|
|
API.SaveCurrentAppearance = SaveCurrentAppearance;
|
|
|
|
function NarciBarberShopPlusButtonMixin:OnClick()
|
|
--Save new Looks
|
|
SaveCurrentAppearance();
|
|
PlaySound(856);
|
|
end
|
|
|
|
function NarciBarberShopPlusButtonMixin:Glow()
|
|
self.GlowTexture.AnimGlow:Play();
|
|
self.GlowTexture:Show();
|
|
PlaySound(23404)
|
|
end
|
|
|
|
|
|
NarciBarberShopEditButtonMixin = {};
|
|
|
|
function NarciBarberShopEditButtonMixin:OnLoad()
|
|
EditButton = self;
|
|
self.Icon:SetTexCoord(0.25, 0.5, 0, 1);
|
|
self.Icon:SetVertexColor(0.8, 0.8, 0.8);
|
|
self.Ring:SetVertexColor(0.8, 0.8, 0.8);
|
|
self.Tooltip:SetText(L["Edit Name"]);
|
|
SetFontStringShadow(self.Tooltip);
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:SetParentObject(object)
|
|
self:ClearAllPoints();
|
|
self:SetParent(object);
|
|
self:SetPoint("BOTTOMRIGHT", object, "RIGHT", 0, 0);
|
|
self:Show();
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:EditName()
|
|
EditBox:SetParentObject(self:GetParent());
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnClick()
|
|
self:EditName();
|
|
PlaySound(856);
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnEnter()
|
|
self:GetParent():OnEnter();
|
|
self.Tooltip:Show();
|
|
self.Ring:Show();
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnLeave()
|
|
MainFrame:OnLeave();
|
|
self:GetParent():OnLeave();
|
|
self.Tooltip:Hide();
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnHide()
|
|
self:Hide();
|
|
self:OnMouseUp();
|
|
self.Tooltip:Hide();
|
|
self:UnlockHighlight();
|
|
self.Ring:Hide();
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnMouseDown()
|
|
self.Icon:SetSize(16, 16);
|
|
end
|
|
|
|
function NarciBarberShopEditButtonMixin:OnMouseUp()
|
|
self.Icon:SetSize(20, 20);
|
|
end
|
|
|
|
|
|
NarciBarberShopDeleteButtonMixin = {};
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnLoad()
|
|
DeleteButton = self;
|
|
self.Icon:SetTexCoord(0, 0.25, 0, 1);
|
|
self.Ring:SetTexCoord(0.25, 0.5, 0, 1);
|
|
self.Ring:SetVertexColor(0.85, 0, 0);
|
|
self.SemiCircleRight:SetVertexColor(0.85, 0, 0);
|
|
self.SemiCircleLeft:SetVertexColor(0.85, 0, 0);
|
|
self.Tooltip:SetText(L["Delete Look"]);
|
|
self.Tooltip:SetTextColor(1, 0.31, 0.31);
|
|
SetFontStringShadow(self.Tooltip);
|
|
|
|
--self.Ring:SetDrawLayer("BORDER");
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:SetParentObject(object)
|
|
self:SetParent(object);
|
|
self:Show();
|
|
self:OnMouseUp();
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnClick()
|
|
PlaySound(856);
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnLongClick()
|
|
local buttonPool, removedButton = DataProvider:DeleteLooks(self:GetParent().dataSource);
|
|
if buttonPool then
|
|
DataProvider:IsCharacterDataUnique();
|
|
animScrollButtons:RemoveOldButton(buttonPool, removedButton);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnEnter()
|
|
self:GetParent():OnEnter();
|
|
self.Tooltip:Show();
|
|
self.Ring:Show();
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnLeave()
|
|
MainFrame:OnLeave();
|
|
self:GetParent():OnLeave();
|
|
self.Tooltip:Hide();
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnHide()
|
|
self:Hide();
|
|
self:OnMouseUp();
|
|
self.Tooltip:Hide();
|
|
self.Ring:Hide();
|
|
self:UnlockHighlight();
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnMouseDown()
|
|
self.Icon:SetSize(14, 14);
|
|
self:LockHighlight();
|
|
self.SemiCircleLeft:Show();
|
|
self.SemiCircleRight:Show();
|
|
self.SemiCircleLeft.rotation:Play();
|
|
self.SemiCircleRight.rotation:Play();
|
|
self.Ring:SetVertexColor(0.25, 0, 0);
|
|
end
|
|
|
|
function NarciBarberShopDeleteButtonMixin:OnMouseUp()
|
|
self.Icon:SetSize(20, 20);
|
|
self:UnlockHighlight();
|
|
self.SemiCircleRight:Hide();
|
|
self.SemiCircleLeft:Hide();
|
|
self:StopAnimating();
|
|
self.Ring:SetVertexColor(0.85, 0, 0);
|
|
end
|
|
|
|
|
|
NarciBarberShopEditBoxMixin = {};
|
|
|
|
function NarciBarberShopEditBoxMixin:OnLoad()
|
|
EditBox = self;
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:SetParentObject(object, alsoHighlightText)
|
|
if self.parentObject then
|
|
self.parentObject.Name:Show();
|
|
self.parentObject:OnLeave();
|
|
end
|
|
self:ClearAllPoints();
|
|
self:SetParent(object);
|
|
self:SetPoint("LEFT", object.Name, "LEFT", 0, 0);
|
|
self:SetText(object.Name:GetText());
|
|
self:Show();
|
|
self.parentObject = object;
|
|
object.Name:Hide();
|
|
if alsoHighlightText then
|
|
After(0, function()
|
|
self:HighlightText();
|
|
end)
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnEscapePressed()
|
|
self.exitByPressingEscape = true;
|
|
self:DiscardChanges();
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnEnterPressed()
|
|
self:ConfirmChanges();
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnTextChanged()
|
|
local remainingLetters = 36 - self:GetNumLetters(true);
|
|
self.LetterCount:SetText(remainingLetters);
|
|
if remainingLetters == 0 then
|
|
self.LetterCount:SetTextColor(0.85, 0, 0);
|
|
elseif remainingLetters <= 12 then
|
|
self.LetterCount:SetTextColor(0.96, 0.64, 0.13);
|
|
else
|
|
self.LetterCount:SetTextColor(0.66, 0.66, 0.66);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:DiscardChanges()
|
|
self:Hide();
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:ConfirmChanges()
|
|
local text = strtrim(self:GetText() or "");
|
|
if text ~= "" then
|
|
self.parentObject.Name:SetText(text);
|
|
self.parentObject:UpdateText();
|
|
self.parentObject.dataSource.name = text;
|
|
end
|
|
self:Hide();
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnShow()
|
|
self:SetFocus();
|
|
self:SetCursorPosition(100);
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnHide()
|
|
self:HighlightText(0, 0);
|
|
self:ClearFocus();
|
|
self:Hide();
|
|
if self.parentObject then
|
|
self.parentObject.Name:Show();
|
|
self.parentObject:OnLeave();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnEditFocusGained()
|
|
autoHideTimer:Hide();
|
|
end
|
|
|
|
function NarciBarberShopEditBoxMixin:OnEditFocusLost()
|
|
if self.exitByPressingEscape then
|
|
self.exitByPressingEscape = nil;
|
|
self:Hide();
|
|
else
|
|
self:ConfirmChanges();
|
|
end
|
|
autoHideTimer:Show();
|
|
end
|
|
|
|
----------------------------------
|
|
|
|
NarciBarberShopMixin = {};
|
|
|
|
function NarciBarberShopMixin:OnLoad()
|
|
MainFrame = self;
|
|
ScrollModelFrame = self.SavedLooksFrame.ScrollModelFrame;
|
|
ScrollBoundMarkUpdater.object1 = ScrollModelFrame.BoundTop;
|
|
ScrollBoundMarkUpdater.object2 = ScrollModelFrame.BoundBottom;
|
|
self.fadeController = CreateFrame("Frame", nil, self);
|
|
end
|
|
|
|
local function FadeController_OnUpdate(self, elapsed)
|
|
self.alpha = self.alpha + self.fadeSpeed*elapsed;
|
|
if self.alpha >= 1 then
|
|
self.alpha = 1;
|
|
self:SetScript("OnUpdate", nil);
|
|
elseif self.alpha <= 0 then
|
|
self.alpha = 0;
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
MainFrame:SetFrameAlpha(self.alpha);
|
|
end
|
|
|
|
function NarciBarberShopMixin:SetFrameAlpha(alpha)
|
|
--temp fix for "Model Widgets Not Inherit Parent's Alpha"
|
|
self:SetAlpha(alpha);
|
|
ScrollButtonAlphaUpdater:SetActiveButtonAlpha(alpha);
|
|
end
|
|
|
|
function NarciBarberShopMixin:FadeIn(fullDuration)
|
|
local alpha = self:GetAlpha();
|
|
if alpha == 1 then
|
|
self.fadeController:SetScript("OnUpdate", nil);
|
|
return
|
|
end
|
|
self.fadeController.fadeSpeed = 1/fullDuration;
|
|
self.fadeController.alpha = alpha;
|
|
self.fadeController:SetScript("OnUpdate", FadeController_OnUpdate);
|
|
end
|
|
|
|
function NarciBarberShopMixin:FadeOut(fullDuration)
|
|
local alpha = self:GetAlpha();
|
|
if alpha == 0 then
|
|
self.fadeController:SetScript("OnUpdate", nil);
|
|
return
|
|
end
|
|
self.fadeController.fadeSpeed = -1/fullDuration;
|
|
self.fadeController.alpha = alpha;
|
|
self.fadeController:SetScript("OnUpdate", FadeController_OnUpdate);
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnKeyDown(key)
|
|
if HotkeyManager:RunCommandByKeyState(key, true) then
|
|
self:SetPropagateKeyboardInput(false);
|
|
else
|
|
self:SetPropagateKeyboardInput(true);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:ToggleNotification(state)
|
|
self.checkUniqueness = state;
|
|
end
|
|
|
|
function NarciBarberShopMixin:ToggleRandomizeAppearanceButton(visible)
|
|
--Deprecated
|
|
--"Random" button is enabled by Blizzard
|
|
local button = CharCustomizeFrame.RandomizeAppearanceButton;
|
|
if button then
|
|
button:SetShown(visible);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnKeyUp(key)
|
|
if HotkeyManager:RunCommandByKeyState(key, false) then
|
|
self:SetPropagateKeyboardInput(false);
|
|
else
|
|
self:SetPropagateKeyboardInput(true);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnShow()
|
|
local _;
|
|
_, SCROLLFRAME_CENTER_Y = ScrollModelFrame:GetCenter();
|
|
UpdateScrollButtonAlpha(ScrollButtonAlphaUpdater.activeButtons);
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnHide()
|
|
ScrollButtonAlphaUpdater:Stop();
|
|
HotkeyManager:StopMovingCamera();
|
|
autoHideTimer:Hide();
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnEnter()
|
|
self:FadeIn(0.2);
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnLeave()
|
|
if not self:IsMouseOver() and not IsMouseButtonDown() then
|
|
autoHideTimer:Show();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:ToggleSaves(savable)
|
|
--For Shapeshifter
|
|
if savable then
|
|
self.SavedLooksFrame:Show();
|
|
self:FadeIn(0.2);
|
|
else
|
|
PlusButton:SetCase(4);
|
|
self.SavedLooksFrame:Hide();
|
|
self:SetAlpha(0);
|
|
end
|
|
|
|
IS_SAVE_SUPPORTED = savable;
|
|
end
|
|
|
|
local SCROLL_OFFSETS = {}; --Used to preserve the scroll offset of the old category
|
|
|
|
function NarciBarberShopMixin:UpdateCategory(sex, raceName)
|
|
self:FadeIn(0.2);
|
|
autoHideTimer:Hide();
|
|
autoHideTimer:Show();
|
|
|
|
local modelPoolID;
|
|
local databaseKey, sexKey;
|
|
|
|
local chrModelID = C_BarberShop.GetViewingChrModel();
|
|
|
|
if chrModelID then
|
|
--Dragonriding / Druid Forms
|
|
modelPoolID = chrModelID;
|
|
raceName = chrModelID;
|
|
databaseKey = "chrModel"..chrModelID;
|
|
else
|
|
if not (sex and raceName) then
|
|
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
|
|
if currentCharacterData then
|
|
sex = currentCharacterData.sex;
|
|
raceName = GetRaceFileName(currentCharacterData);
|
|
else
|
|
print("Error: No Character Data");
|
|
return
|
|
end
|
|
end
|
|
raceName = string.lower(raceName);
|
|
|
|
if HAS_ALTERNATE_FORM then
|
|
IN_ALTERNATE_FORM = C_BarberShop.IsViewingAlteredForm();
|
|
else
|
|
IN_ALTERNATE_FORM = false;
|
|
end
|
|
if sex == 0 then
|
|
sexKey = "male";
|
|
if HAS_ALTERNATE_FORM then
|
|
if IN_ALTERNATE_FORM then --alternate male
|
|
databaseKey = ALTERNATE_FORM_SAVED_ID;
|
|
modelPoolID = 3;
|
|
else --male
|
|
modelPoolID = 1;
|
|
end
|
|
else --male
|
|
modelPoolID = 1;
|
|
end
|
|
else
|
|
sexKey = "female";
|
|
if HAS_ALTERNATE_FORM then
|
|
if IN_ALTERNATE_FORM then --alternate female
|
|
databaseKey = ALTERNATE_FORM_SAVED_ID;
|
|
modelPoolID = 4;
|
|
else --female
|
|
modelPoolID = 2;
|
|
end
|
|
else --female
|
|
modelPoolID = 2;
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.modelPoolID then
|
|
SCROLL_OFFSETS[self.modelPoolID] = ScrollModelFrame:GetEndPosition(); --save current offset
|
|
end
|
|
self.modelPoolID = modelPoolID;
|
|
|
|
ScrollBoundMarkUpdater:Hide();
|
|
|
|
ModelPool:SetActiveModelPool(modelPoolID);
|
|
|
|
local data = DataProvider:SetActiveDatabase(databaseKey, sexKey);
|
|
NUM_ACTIVE_BUTTONS = #data;
|
|
local raceTex = RaceAtlas:GetAtlas(raceName, sexKey, IN_ALTERNATE_FORM);
|
|
SetUpSavedLooksButton(data, raceTex);
|
|
UpdateScrollRange( SCROLL_OFFSETS[modelPoolID] );
|
|
LoadingFrame:LoadPortraits();
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnBarberShopOpen()
|
|
self.initialCustomizationData = C_BarberShop.GetAvailableCustomizations();
|
|
|
|
local isDragonriding;
|
|
|
|
if self.initialCustomizationData then
|
|
for _, categoryData in ipairs(self.initialCustomizationData) do
|
|
if categoryData.chrModelID then
|
|
isDragonriding = API.IsDragonridingChrModel(categoryData.chrModelID);
|
|
break
|
|
end
|
|
end
|
|
end
|
|
self.isDragonriding = isDragonriding;
|
|
|
|
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
|
|
local sex, raceName;
|
|
if currentCharacterData then
|
|
sex = currentCharacterData.sex;
|
|
self.initialIconAtlas = currentCharacterData.raceData and currentCharacterData.raceData.createScreenIconAtlas;
|
|
raceName = GetRaceFileName(currentCharacterData);
|
|
end
|
|
|
|
IS_SAVE_SUPPORTED = true; --Reset druid form flag
|
|
self:UpdateCategory(sex, raceName);
|
|
StatManager:OnBarberShopOpen();
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnBarberShopClose()
|
|
self.initialIconAtlas = nil;
|
|
self.initialCustomizationData = nil;
|
|
self.fadeController:SetScript("OnUpdate", nil);
|
|
StatManager:OnBarberShopClose();
|
|
end
|
|
|
|
function NarciBarberShopMixin:ResetCustomizationInternally()
|
|
if self.isDragonriding then
|
|
C_BarberShop.ResetCustomizationChoices();
|
|
else
|
|
if self.initialCustomizationData then
|
|
CustomizationUtil:ApplyCustomizationCategoryData(self.initialCustomizationData, true);
|
|
end
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:IsCharacterCategoryChanged()
|
|
--true if player is viewing a different category - i.g. was type1 but currently viewing type2
|
|
local chrModelID = C_BarberShop.GetViewingChrModel();
|
|
if chrModelID and chrModelID ~= 0 then
|
|
return false
|
|
end
|
|
|
|
local currentCharacterData = C_BarberShop.GetCurrentCharacterData();
|
|
if currentCharacterData then
|
|
if currentCharacterData.raceData then
|
|
return self.initialIconAtlas ~= currentCharacterData.raceData.createScreenIconAtlas;
|
|
else
|
|
return true
|
|
end
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopMixin:OnViewingModelChanged(chrModelID)
|
|
local effectiveChrModelID = C_BarberShop.GetViewingChrModel();
|
|
self:UpdateCategory();
|
|
--print("chrModelID", effectiveChrModelID)
|
|
end
|
|
|
|
-----------------------------------------------------------------
|
|
local function InitializeBarberShopFrame()
|
|
local frame = Narci_BarbershopFrame;
|
|
frame:ClearAllPoints();
|
|
frame:SetParent(BarberShopUI);
|
|
frame:SetPoint("TOPLEFT", BarberShopUI, "TOPLEFT", 0, -95);
|
|
frame:Show();
|
|
|
|
--The WoW default action is automatically closing the BarberShopUI
|
|
--But here we want to check if the newly applied appearance is unique and notifiy user to save it
|
|
BarberShopUI:UnregisterEvent("BARBER_SHOP_APPEARANCE_APPLIED");
|
|
SettingFrame:Initialize();
|
|
|
|
ModelPool:Init();
|
|
end
|
|
|
|
--/run TestPlayerModel:SetZoomDistance()
|
|
|
|
|
|
local function HookMixin()
|
|
--[[
|
|
hooksecurefunc(CharCustomizeFrame, "SetCustomizationChoice", function(self, optionID, choiceID)
|
|
print("Set ",optionID, choiceID)
|
|
end)
|
|
hooksecurefunc(CharCustomizeFrame, "PreviewCustomizationChoice", function(self, optionID, choiceID)
|
|
print("Preview ", optionID, choiceID)
|
|
end)
|
|
--]]
|
|
|
|
hooksecurefunc(C_BarberShop, "SetSelectedSex", function(sexID)
|
|
MainFrame:UpdateCategory(sexID);
|
|
end);
|
|
|
|
hooksecurefunc(C_BarberShop, "SetViewingShapeshiftForm", function(formID)
|
|
MainFrame:UpdateCategory();
|
|
if API.IsFormSavable(formID) then
|
|
MainFrame:ToggleSaves(true);
|
|
else
|
|
MainFrame:ToggleSaves(false);
|
|
end
|
|
end);
|
|
|
|
if HAS_ALTERNATE_FORM then
|
|
hooksecurefunc(C_BarberShop, "SetViewingAlteredForm", function(viewingAlteredForm)
|
|
MainFrame:UpdateCategory();
|
|
end);
|
|
end
|
|
|
|
if C_BarberShop.SetViewingChrModel then
|
|
hooksecurefunc(C_BarberShop, "SetViewingChrModel", function(chrModelID)
|
|
MainFrame:OnViewingModelChanged();
|
|
end);
|
|
end
|
|
|
|
--Override the default method to:
|
|
--1. Add looks uniqueness check
|
|
--Constantly monitor this mixin!!
|
|
|
|
if true then
|
|
function BarberShopUI:UpdateCharCustomizationFrame(alsoReset)
|
|
local customizationCategoryData = C_BarberShop.GetAvailableCustomizations();
|
|
if not customizationCategoryData then
|
|
return;
|
|
end
|
|
|
|
DataProvider:IsCharacterDataUnique(customizationCategoryData);
|
|
|
|
if alsoReset then
|
|
CharCustomizeFrame:Reset();
|
|
end
|
|
|
|
CharCustomizeFrame:SetCustomizations(customizationCategoryData);
|
|
|
|
if self.UpdatePrice then
|
|
--TransitionAPI *barbershop is free in Dragonflight
|
|
self:UpdatePrice();
|
|
end
|
|
|
|
if self.UpdateButtons then
|
|
self:UpdateButtons();
|
|
end
|
|
--ExportEditBox.profileString = nil; --It'll be updated when that editbox becomes visible
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
local EventListener = CreateFrame("Frame");
|
|
local events = {"BARBER_SHOP_COST_UPDATE", "BARBER_SHOP_FORCE_CUSTOMIZATIONS_UPDATE", "BARBER_SHOP_RESULT", "BARBER_SHOP_OPEN", "BARBER_SHOP_CLOSE", "BARBER_SHOP_APPEARANCE_APPLIED", "ADDON_LOADED"}; --"UNIT_MODEL_CHANGED"
|
|
for i = 1, #events do
|
|
EventListener:RegisterEvent(events[i])
|
|
end
|
|
|
|
|
|
EventListener:SetScript("OnEvent", function(self, event, ...)
|
|
if event == "ADDON_LOADED" then
|
|
local name = ...;
|
|
--Blizzard_CharacterCustomize
|
|
--Blizzard_BarbershopUI
|
|
if name == "Narcissus_Barbershop" then --Narcissus_Barbershop
|
|
self:UnregisterEvent(event);
|
|
if not (IsAddOnLoaded("Blizzard_BarbershopUI") and BarberShopFrame) then
|
|
print("Narcissus Error: Blizzard_BarbershopUI not loaded!");
|
|
self:UnregisterAllEvents();
|
|
return
|
|
end
|
|
BarberShopUI = BarberShopFrame;
|
|
DataProvider:LoadData();
|
|
HotkeyManager:LoadHotkeys();
|
|
StatManager:LoadData();
|
|
HookMixin();
|
|
InitializeBarberShopFrame();
|
|
MainFrame:UpdateCategory();
|
|
MainFrame:OnBarberShopOpen();
|
|
|
|
--[[
|
|
if false then
|
|
C_Timer.After(0.5 , function()
|
|
BarberShopUI:SetPropagateKeyboardInput(true); --DEBUG
|
|
end)
|
|
end
|
|
--]]
|
|
end
|
|
elseif event == "BARBER_SHOP_OPEN" then
|
|
MainFrame:OnBarberShopOpen();
|
|
|
|
elseif event == "BARBER_SHOP_CLOSE" then
|
|
MainFrame:OnBarberShopClose();
|
|
|
|
elseif event == "BARBER_SHOP_RESULT" then
|
|
if BarberShopUI.UpdateButtons then
|
|
BarberShopUI:UpdateButtons();
|
|
end
|
|
elseif event == "BARBER_SHOP_APPEARANCE_APPLIED" then
|
|
if MainFrame.checkUniqueness and DataProvider:IsNewLooksUnique() then
|
|
BarberShopUI:UpdateCharCustomizationFrame();
|
|
PlusButton:Glow();
|
|
else
|
|
BarberShopUI:Cancel();
|
|
end
|
|
--StatManager:UpdateMoney();
|
|
end
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
-------------------------------------------------------
|
|
--Settings
|
|
local TabButtons = {};
|
|
|
|
NarciBarberShopSettingTabButtonMixin = {};
|
|
|
|
function NarciBarberShopSettingTabButtonMixin:OnLoad()
|
|
tinsert(TabButtons, self);
|
|
end
|
|
|
|
function NarciBarberShopSettingTabButtonMixin:OnEnter()
|
|
if not self.isSelected then
|
|
self.ButtonText:SetTextColor(1, 1, 1);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingTabButtonMixin:OnLeave()
|
|
if not self.isSelected then
|
|
self.ButtonText:SetTextColor(0.5, 0.5, 0.5);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingTabButtonMixin:SetSelection(isSelected)
|
|
self.isSelected = isSelected;
|
|
SettingFrame.ScrollFrame:SetOffset(0);
|
|
if isSelected then
|
|
self.ButtonText:SetTextColor(1, 0.82, 0);
|
|
SettingFrame:SelectTab(self.Tab);
|
|
else
|
|
self:OnLeave();
|
|
if self.Tab then
|
|
self.Tab:Hide();
|
|
end
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingTabButtonMixin:OnClick()
|
|
if self.isSelected then return end;
|
|
|
|
for i = 1, #TabButtons do
|
|
TabButtons[i]:SetSelection( TabButtons[i] == self );
|
|
end
|
|
|
|
PlaySound(856);
|
|
end
|
|
|
|
|
|
NarciBarberShopSettingCheckBoxMixin = {};
|
|
|
|
function NarciBarberShopSettingCheckBoxMixin:OnLoad()
|
|
self.Box:SetVertexColor(0.8, 0.8, 0.8);
|
|
self.Highlight:SetVertexColor(0.5, 0.5, 1);
|
|
end
|
|
|
|
function NarciBarberShopSettingCheckBoxMixin:SetChecked(state)
|
|
self.isOn = state;
|
|
self.Check:SetShown(state);
|
|
if self.onClickFunc then
|
|
self.onClickFunc(self.isOn);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingCheckBoxMixin:OnClick()
|
|
self.isOn = not self.isOn;
|
|
self:SetChecked(self.isOn);
|
|
if self.name then
|
|
NarciBarberShopDB[self.name] = self.isOn;
|
|
end
|
|
|
|
if self.isOn then
|
|
PlaySound(856);
|
|
else
|
|
PlaySound(857); --SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF
|
|
end
|
|
end
|
|
|
|
|
|
local function ProfilesTab_Setup(tab)
|
|
tab:SetScript("OnShow", API.ShowAppearanceList);
|
|
tab:SetScript("OnHide", API.HideAppearanceList);
|
|
end
|
|
|
|
|
|
local TabData = {
|
|
{ name= "General", order = 1, localizedName = GENERAL,
|
|
layout = {
|
|
{ name = "ToggleNotification", type = "checkbox", localizedName = L["Save Notify"], defaultState = true,
|
|
onClickFunc = function(state) MainFrame:ToggleNotification(state) end,
|
|
tooltip = L["Save Notify Tooltip"];
|
|
},
|
|
--{ name = "ToggleRandomAppearance", type = "checkbox", localizedName = L["Show Randomize Button"], defaultState = false, onClickFunc = function(state) MainFrame:ToggleRandomizeAppearanceButton(state) end }, --RANDOMIZE_APPEARANCE
|
|
},
|
|
},
|
|
|
|
{ name = "Shortcuts", order = 2, localizedName = L["Hotkey"],
|
|
layout = {
|
|
{ name = "Camera", type = "header", localizedName = CAMERA_LABEL},
|
|
{ name = "RotateLeft", type = "keybinding", localizedName = ROTATE_LEFT},
|
|
{ name = "RotateRight", type = "keybinding", localizedName = ROTATE_RIGHT},
|
|
{ name = "ZoomIn", type = "keybinding", localizedName = ZOOM_IN},
|
|
{ name = "ZoomOut", type = "keybinding", localizedName = ZOOM_OUT},
|
|
},
|
|
},
|
|
|
|
{ name = "Profiles", order = 3, localizedName = L["Profiles"],
|
|
manuallyCreated = true,
|
|
setupFunc = ProfilesTab_Setup,
|
|
},
|
|
|
|
{ name = "Statistics", order = 0, localizedName = STATISTICS,
|
|
layout = {
|
|
--Barbershop service is free now. Remove money stats
|
|
--{ name = "Money", type = "header", localizedName = L["Coins Spent"] },
|
|
--{ name = "CoinsSpentSinceShadowlands", type="money", localizedName = "9.0+", tooltip = "Coins spent since 9.0"},
|
|
--{ name = "CoinsSpentLifetime", type="money", localizedName = HONOR_LIFETIME, tooltip = "Coins spent during lifetime"},
|
|
--{ name = "Blank", type="header", localizedName=" ",},
|
|
{ name = "LocationHeader", type = "location", localizedName = L["Locations"] },
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
local function CreateTabs(frame)
|
|
local sidePadding = 8;
|
|
local tabWidth, tabHeight = 312, 200;
|
|
|
|
for i, data in ipairs(TabData) do
|
|
local button = CreateFrame("Button", nil, frame, "NarciBarberShopSettingTabButtonTemplate");
|
|
local order = data.order;
|
|
button.order = order;
|
|
if order ~= 0 then
|
|
button:SetPoint("TOPLEFT", frame, "TOPLEFT", sidePadding, -sidePadding + 16 *(1 - i));
|
|
else
|
|
button:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", sidePadding, sidePadding);
|
|
end
|
|
button:SetText(data.localizedName);
|
|
|
|
if data.layout then
|
|
local totalHeight = 8;
|
|
local objects = {};
|
|
local ScrollFrame = frame.ScrollFrame;
|
|
local Tab = CreateFrame("Frame", nil, ScrollFrame);
|
|
button.Tab = Tab;
|
|
if order == 0 then
|
|
StatManager.StatFrame = Tab;
|
|
end
|
|
Tab:SetSize(tabWidth, tabHeight);
|
|
Tab:SetPoint("TOPLEFT", frame.ScrollFrame.ScrollChild, "TOPLEFT", 0, 0);
|
|
for j, objectData in ipairs(data.layout) do
|
|
local type = objectData.type;
|
|
local object;
|
|
if type == "checkbox" then
|
|
object = CreateFrame("Button", nil, Tab, "NarciBarberShopSettingCheckBoxTemplate");
|
|
object.onClickFunc = objectData.onClickFunc;
|
|
object.Label:SetText(objectData.localizedName);
|
|
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
|
|
local textHeight = object.Label:GetHeight() or 12;
|
|
object:SetHeight(textHeight + 2);
|
|
totalHeight = totalHeight + textHeight + 12;
|
|
--Load settings
|
|
local dbName = objectData.name;
|
|
object.name = dbName;
|
|
if NarciBarberShopDB[dbName] == nil then
|
|
NarciBarberShopDB[dbName] = objectData.defaultState;
|
|
end
|
|
object:SetChecked(NarciBarberShopDB[dbName]);
|
|
if objectData.tooltip then
|
|
local infoButton = CreateFrame("Frame", nil, object, "NarciGenericInfoButtonTemplate");
|
|
infoButton:SetPoint("LEFT", object, "RIGHT", 12, 0);
|
|
infoButton.tooltipText = objectData.tooltip;
|
|
infoButton.tooltipName = "CharCustomizeNoHeaderTooltip";
|
|
objectData.tooltip = nil;
|
|
end
|
|
elseif type == "keybinding" then
|
|
object = CreateFrame("Button", nil, Tab, "NarciBarberShopSettingKeyBindingButtonTemplate");
|
|
object.Label:SetText(objectData.localizedName);
|
|
object.command = objectData.name;
|
|
object:SetPoint("TOPRIGHT", Tab, "TOPRIGHT", -60, -totalHeight);
|
|
local textHeight = object.Label:GetHeight() or 12;
|
|
totalHeight = totalHeight + textHeight + 12;
|
|
object:SetText(HotkeyManager:GetHotkey(object.command));
|
|
|
|
elseif type == "header" then
|
|
object = Tab:CreateFontString(nil, "OVERLAY", "SystemFont_Tiny");
|
|
object:SetText(objectData.localizedName);
|
|
if objectData.anchor then
|
|
object:SetJustifyH("LEFT");
|
|
else
|
|
object:SetJustifyH("CENTER");
|
|
end
|
|
object:SetSpacing(2);
|
|
object:SetJustifyV("TOP");
|
|
object:SetPoint("TOP", Tab, "TOP", 0, -totalHeight);
|
|
object:SetTextColor(0.5, 0.5, 0.5);
|
|
object:SetWidth(270);
|
|
totalHeight = totalHeight + 16;
|
|
|
|
elseif type == "money" then
|
|
object = CreateFrame("Frame", nil, Tab, "NarciBarberShopStatsMoneyFrameTemplate");
|
|
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
|
|
object:SetLabel(objectData.localizedName);
|
|
local textHeight = object.Label:GetHeight() or 12;
|
|
totalHeight = totalHeight + textHeight + 8;
|
|
|
|
StatManager.widgets[objectData.name] = object;
|
|
elseif type == "location" then
|
|
object = CreateFrame("Frame", nil, Tab, "NarciBarberShopStatsLocationFrameTemplate");
|
|
object:SetPoint("TOPLEFT", Tab, "TOPLEFT", 8, -totalHeight);
|
|
object:SetHeader();
|
|
totalHeight = totalHeight + 16;
|
|
StatManager.widgets[objectData.name] = object;
|
|
|
|
end
|
|
end
|
|
|
|
Tab.tabHeight = totalHeight;
|
|
Tab.basicHeight = totalHeight;
|
|
|
|
elseif data.manuallyCreated then
|
|
local Tab = frame[data.name.."Tab"];
|
|
if Tab then
|
|
button.Tab = Tab;
|
|
Tab:ClearAllPoints();
|
|
Tab:SetPoint("TOPLEFT", frame.ScrollFrame, "TOPLEFT", 0, 0);
|
|
if data.setupFunc then
|
|
data.setupFunc(Tab);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
wipe(TabData);
|
|
end
|
|
|
|
NarciBarberShopSettingsMixin = CreateFromMixins(NarciChamferedFrameMixin);
|
|
|
|
function NarciBarberShopSettingsMixin:OnLoad()
|
|
self:CreateBackground();
|
|
|
|
SettingFrame = self;
|
|
StatManager.SettingFrame = self;
|
|
ExportEditBox = self.ProfilesTab.ExportEditBox;
|
|
|
|
local v = 0.2;
|
|
self:SetBorderColor(v, v, v, 1);
|
|
self:SetBackgroundColor(0, 0, 0, 1);
|
|
self.Divider:SetVertexColor(v, v, v);
|
|
self:SetBorderOffset(0);
|
|
|
|
self.ScrollFrame.ScrollBar.Background:SetVertexColor(0.5, 0.5, 0.5);
|
|
|
|
NarciAPI.CreateSmoothScroll(self.ScrollFrame);
|
|
self.ScrollFrame:SetStepSize(40);
|
|
|
|
self:SetScript("OnMouseWheel", function()
|
|
end);
|
|
end
|
|
|
|
function API.GetSettingsFrame()
|
|
return SettingFrame
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:AddChildFrame(child)
|
|
if not self.childFrames then
|
|
self.childFrames = {};
|
|
end
|
|
|
|
for i, f in ipairs(self.childFrames) do
|
|
if f == child then
|
|
return
|
|
end
|
|
end
|
|
|
|
table.insert(self.childFrames, child);
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:Initialize()
|
|
CreateTabs(self);
|
|
TabButtons[3]:Click(); --Open Share (import/export)
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:IsFocused()
|
|
if self:IsMouseOver(0, 0, 0, 16) then
|
|
return true
|
|
elseif self.childFrames then
|
|
for i, f in ipairs(self.childFrames) do
|
|
if f:IsVisible() and f:IsMouseOver() then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:OnEvent(event)
|
|
--GLOBAL_MOUSE_DOWN
|
|
if not self:IsFocused() and not SettingButton:IsMouseOver() then
|
|
self:Hide();
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:OnShow()
|
|
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:OnHide()
|
|
self:Hide();
|
|
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
|
|
|
|
autoHideTimer:Show();
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:Toggle()
|
|
self:SetShown(not self:IsShown());
|
|
end
|
|
|
|
function NarciBarberShopSettingsMixin:SelectTab(tab)
|
|
--Update Scroll Range
|
|
local frameHeight = math.floor(self.ScrollFrame:GetHeight() + 0.5);
|
|
local range;
|
|
if tab then
|
|
tab:Show();
|
|
if tab.tabHeight then
|
|
range = tab.tabHeight - frameHeight;
|
|
if range < 4 then
|
|
range = 0;
|
|
end
|
|
else
|
|
range = 0;
|
|
end
|
|
self.ScrollFrame:SetScrollRange(range);
|
|
end
|
|
end
|
|
|
|
--Click to open Settings
|
|
NarciBarberShopSettingButtonMixin = {};
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnLoad()
|
|
SettingButton = self;
|
|
self.Label:SetText(L["Settings And Share"]);
|
|
end
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnMouseDown()
|
|
self.Background:SetTexCoord(0.25, 0.5, 0, 1);
|
|
end
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnMouseUp()
|
|
self.Background:SetTexCoord(0, 0.25, 0, 1);
|
|
end
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnEnter()
|
|
self.Label:Show();
|
|
EditButton:Hide();
|
|
DeleteButton:Hide();
|
|
end
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnLeave()
|
|
self.Label:Hide();
|
|
end
|
|
|
|
function NarciBarberShopSettingButtonMixin:OnClick()
|
|
SettingFrame:Toggle();
|
|
PlaySound(856);
|
|
end
|
|
|
|
-----------------------------------------------
|
|
--Dev Tool
|
|
local function round(number, digit)
|
|
digit = digit or 0;
|
|
local fold = 10^digit;
|
|
return math.floor((number * fold + 0.5))/fold
|
|
end
|
|
|
|
NarciDevToolPortraitMixin = {};
|
|
|
|
function NarciDevToolPortraitMixin:OnLoad()
|
|
if false then return end;
|
|
|
|
local model = self.Model;
|
|
model:SetUnit("player");
|
|
model:SetKeepModelOnHide(true);
|
|
model:SetDoBlend(true);
|
|
model:SetFacing(0);
|
|
TransitionAPI.SetModelLight(model, true, false, cos(pi/4)*sin(-pi/4) , cos(pi/4)*cos(-pi/4) , -cos(pi/4), 1, 0.5, 0.5, 0.5, 1, 0.9, 0.9, 0.9);
|
|
model:SetCamera(0);
|
|
model:SetPortraitZoom(1);
|
|
model:SetAnimation(0, 0);
|
|
model:SetPaused(true);
|
|
self.facing = 0;
|
|
self.cameraDistance = 1;
|
|
self.cameraPitch = pi/2;
|
|
self.translationX, self.translationY = 0, 0;
|
|
|
|
self.FacingButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "LeftButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 4 * delta;
|
|
end
|
|
self.facing = model:GetFacing() + delta;
|
|
model:SetFacing(self.facing);
|
|
frame.Value:SetText( round(self.facing, 2) );
|
|
end)
|
|
|
|
--[[
|
|
self.CameraPitchButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "RightButton" then
|
|
delta = - delta;
|
|
end
|
|
local cameraPitch = self.cameraPitch + delta;
|
|
self.cameraPitch = cameraPitch;
|
|
TransitionAPI.SetCameraPosition(model, self.cameraDistance*sin(cameraPitch), 0, self.cameraDistance*cos(cameraPitch) + 0.8);
|
|
frame.Value:SetText(cameraPitch);
|
|
end)
|
|
--]]
|
|
|
|
|
|
|
|
self.ModelXButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "RightButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 16 * delta;
|
|
end
|
|
local x, y, z = model:GetPosition();
|
|
model:SetPosition(x + delta, y, z);
|
|
frame.Value:SetText( round(x + delta, 2) );
|
|
end)
|
|
|
|
self.ModelYButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "RightButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 16 * delta;
|
|
end
|
|
local x, y, z = model:GetPosition();
|
|
model:SetPosition(x, y + delta, z);
|
|
frame.Value:SetText( round(y + delta, 2) );
|
|
end)
|
|
|
|
self.ModelZButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "RightButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 16 * delta;
|
|
end
|
|
local x, y, z = model:GetPosition();
|
|
model:SetPosition(x, y, z + delta);
|
|
frame.Value:SetText( round(z + delta, 2) );
|
|
end)
|
|
|
|
self.DistanceButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "LeftButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 4 * delta;
|
|
end
|
|
local cameraDistance = self.cameraDistance + delta;
|
|
self.cameraDistance = cameraDistance;
|
|
TransitionAPI.SetCameraPosition(model, cameraDistance*sin(self.cameraPitch), 0, cameraDistance*cos(self.cameraPitch) + 0.8);
|
|
frame.Value:SetText( round(cameraDistance, 4) );
|
|
end)
|
|
|
|
self.OffsetXButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "LeftButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 4 * delta;
|
|
end
|
|
local x, y = model:GetViewTranslation();
|
|
model:SetViewTranslation(x + delta, y);
|
|
frame.Value:SetText( round(x + delta) );
|
|
end)
|
|
|
|
self.OffsetYButton:SetScript("OnClick", function(frame, button)
|
|
local delta = frame.delta;
|
|
if button == "RightButton" then
|
|
delta = - delta;
|
|
end
|
|
if IsShiftKeyDown() then
|
|
delta = 4 * delta;
|
|
end
|
|
local x, y = model:GetViewTranslation();
|
|
model:SetViewTranslation(x, y + delta);
|
|
frame.Value:SetText( round(y + delta) );
|
|
end)
|
|
|
|
self.ReloadButton:SetScript("OnClick", function()
|
|
self:LoadProfile();
|
|
end)
|
|
|
|
self.Model:SetScript("OnModelLoaded", function(self)
|
|
print("ModelFileID:", self:GetModelFileID())
|
|
end);
|
|
end
|
|
|
|
function NarciDevToolPortraitMixin:OnShow()
|
|
local model = self.Model;
|
|
model:MakeCurrentCameraCustom();
|
|
self.cameraDistance = model:GetCameraDistance();
|
|
self.cameraPitch = pi/2;
|
|
model:SetPosition(0, 0, 0);
|
|
self.FacingButton.Value:SetText(model:GetFacing());
|
|
self.DistanceButton.Value:SetText(self.cameraDistance);
|
|
local x, y = model:GetViewTranslation();
|
|
self.OffsetXButton.Value:SetText(x);
|
|
self.OffsetYButton.Value:SetText(y);
|
|
end
|
|
|
|
function NarciDevToolPortraitMixin:LoadProfile(race, sex)
|
|
local model = self.Model;
|
|
model:RefreshUnit();
|
|
model:SetAnimation(0, 0);
|
|
model:SetPaused(true);
|
|
model:MakeCurrentCameraCustom();
|
|
UpdatePortraitCamera(model);
|
|
local cameraX, cameraY, cameraZ = TransitionAPI.TransformCameraSpaceToModelSpace(model, 4, 0, 0);
|
|
local targetX, targetY, targetZ = TransitionAPI.TransformCameraSpaceToModelSpace(model, 0, 0, 0);
|
|
TransitionAPI.SetCameraTarget(model, targetX, targetY, targetZ);
|
|
TransitionAPI.SetCameraPosition(model, cameraX, cameraY, cameraZ);
|
|
local modelFacing = model:GetFacing();
|
|
local modelPosX, modelPosY, modelPosZ = model:GetPosition();
|
|
self.ModelXButton.Value:SetText(modelPosX);
|
|
self.ModelYButton.Value:SetText(modelPosY);
|
|
self.ModelZButton.Value:SetText(modelPosZ);
|
|
self.FacingButton.Value:SetText(modelFacing);
|
|
--/dump NarciDevToolPortraitFrame.Model:GetModelFileID()
|
|
end
|
|
|
|
--[[
|
|
Statistics
|
|
Gold spent at barber shops GetStatistic(1147)
|
|
C_MapExplorationInfo.GetExploredAreaIDsAtPosition(109, C_Map.GetPlayerMapPosition(109, "player"))
|
|
C_Map.GetMapInfoAtPosition(109, C_Map.GetPlayerMapPosition(109, "player"):GetXY())
|
|
New Look #10: Q.0.52k.i.5.c.1h.6.7.g.1.a.4.p.2.5.7.9.2.7.4.2.8.2g1.2.nD.J.9.B.16.7.7.c.f.w.3.5.4.5.C
|
|
Dracthyr Male: Q.0.52E.3.d.1i.4.9.g.3.6.3.j.9.6.3.3.8.3.4.8.1.6.1Th.g.mw.1.3.nV.p.9.J.19.3.b.1.O.1.8.5.C.aQ
|
|
Dracthyr Male: Q.0.52E.3.d.1i.4.9.g.3.6.3.j.9.6.3.3.8.3.4.8.1.6.1Th.h.P.lG.1.3.nV.p.9.J.19.3.b.1.O.1.8.5.C.aQ
|
|
--]]
|
|
|
|
local PORTRAIT_LOAD_DELAY = 0.1;
|
|
NarciBarberShopLoadingFrameMixin = {};
|
|
|
|
local function LoadingFrame_UpdatePortraitDelay(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t > PORTRAIT_LOAD_DELAY then
|
|
--self:SetScript("OnUpdate", nil);
|
|
self.t = 0;
|
|
self.button:RefreshPortrait(true);
|
|
end
|
|
end
|
|
|
|
local function LoadingFrame_InitiateLoadingDelay(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
if self.t > 0.2 then
|
|
self.t = 0;
|
|
self:LoadNextPortrait(self.current);
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopLoadingFrameMixin:OnLoad()
|
|
LoadingFrame = self;
|
|
|
|
self.Name:SetText(Narci.L["Loading Portraits"] .."...");
|
|
self.Name:SetTextColor(1, 1, 1);
|
|
self.Progress:SetTextColor(0.67, 0.67, 0.67);
|
|
end
|
|
|
|
function NarciBarberShopLoadingFrameMixin:LoadPortraits()
|
|
local fromID;
|
|
local total = 0;
|
|
if SavedLookButtons then
|
|
for i = 1, #SavedLookButtons do
|
|
if (not SavedLookButtons[i]:IsPortraitLoaded()) and SavedLookButtons[i].appearanceData then
|
|
total = total + 1;
|
|
if not fromID then
|
|
fromID = i;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if total == 0 then
|
|
self:Hide();
|
|
self:SetScript("OnUpdate", nil);
|
|
return
|
|
else
|
|
self.total = total;
|
|
end
|
|
|
|
MainFrame.initialCustomizationData = C_BarberShop.GetAvailableCustomizations();
|
|
|
|
self.Name:SetText(Narci.L["Loading Portraits"] .."...");
|
|
self.current = fromID - 1;
|
|
self.Ring.AnimSpin:Play();
|
|
self.t = 0;
|
|
self:SetScript("OnUpdate", LoadingFrame_InitiateLoadingDelay);
|
|
|
|
FadeFrame(self, 0.25, 1, 0);
|
|
end
|
|
|
|
function NarciBarberShopLoadingFrameMixin:OnHide()
|
|
self:SetScript("OnUpdate", nil);
|
|
end
|
|
|
|
function NarciBarberShopLoadingFrameMixin:LoadNextPortrait(buttonID)
|
|
if buttonID and buttonID ~= self.current then
|
|
return
|
|
end
|
|
|
|
self.current = self.current + 1;
|
|
if self.current > self.total then
|
|
--complete
|
|
if self.isLoading then
|
|
self:OnLoadingComplete();
|
|
end
|
|
else
|
|
local button = SavedLookButtons[self.current];
|
|
if button then
|
|
button:UseCustomization(true);
|
|
self.t = 0;
|
|
self.button = button;
|
|
self:SetScript("OnUpdate", LoadingFrame_UpdatePortraitDelay);
|
|
self.isLoading = true;
|
|
self.Progress:SetText(self.current .. " / " ..self.total);
|
|
else
|
|
self:OnLoadingComplete();
|
|
end
|
|
end
|
|
end
|
|
|
|
function NarciBarberShopLoadingFrameMixin:OnLoadingComplete()
|
|
--self:StopAnimating();
|
|
self:SetScript("OnUpdate", nil);
|
|
self.isLoading = false;
|
|
--self:Hide();
|
|
FadeFrame(self, 0.5, 0);
|
|
|
|
MainFrame:ResetCustomizationInternally();
|
|
|
|
if MainFrame:IsCharacterCategoryChanged() then
|
|
|
|
else
|
|
|
|
end
|
|
end
|