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.

638 lines
18 KiB

--/run NarciOutfitShowcase.BackdropSelect:Open()
local _, addon = ...
local NUM_ROW = 6;
local NUM_COL = 4;
local NUM_BUTTONS = NUM_ROW * NUM_COL;
local modf = math.modf;
local pow = math.pow;
local sin = math.sin;
local pi = math.pi;
local function outQuart(t, b, e, d)
t = t / d - 1;
return (b - e) * (pow(t, 4) - 1) + b
end
local function outSine(t, b, e, d)
return (e - b) * sin(t / d * (pi / 2)) + b
end
local MainFrame, BackdropContainer, FocusedButton, SelectionFrame, HighlightFrame;
local SELECTED_INDEX, PREVIEW_INDEX;
local AreaData = {
--[index] = {fileName, areaID}, --see https://wow.tools/dbc/?dbc=areatable
--/script local s=7900;local n;for i = s, s+100 do n=C_Map.GetAreaInfo(i) if n then print(i.. " "..n) end end
{"stormwind_cathedral", 5151},
{"ironforge", 809},
{"darnassus", 1658},
{"new_tinkertown", 6457},
{"ammen_vale", 3526},
{"gilneas_city", 4755},
{"the_jade_forest", 5975},
{"telogrus_rift", 9415},
{"vindicaar", 9359},
{"blackrock_depths", 10028},
{"boralus", 8568},
{"mechagon", 12825},
{"valley_of_trials", 363},
{"tirisfal_glades", 85},
{"mulgore", 1638},
{"darkspear_hold", 4866},
{"sunstrider_isle", 3431},
{"kezan", 4737},
{"suramar", 8148},
{"thunder_totem", 7731},
{"valley_of_honor", 5168},
{"dazaralor", 8670},
{"voldun", 8854},
{"halls_of_valor", 7672},
{"trueshot_lodge", 7877},
{"dalaran", 7502},
{"black_rook_hold", 7780},
{"netherlight_temple", 7834},
{"edge_of_reality", 7519},
{"sanctum_of_light", 8347},
{"dreamgrove", 7979},
{"throne_of_elements", 7280},
{"peak_of_serenity", 6081},
{"mardum", 7705},
{"frozen_throne", 4859},
{"elysian_hold", 11012},
{"seat_of_the_primus", 12876},
{"heart_of_the_forest", 12858},
{"sinfall", 10986},
{"torghast", 10472},
{"oribos", 10565},
{"stormwind_rain", 5151},
{"undercity", 1497},
{"silvermoon_city", 3487},
{"broken_shore", 7543},
{"bladespire_grounds", 3931},
{"netherstorm", 3523},
{"zulgurub", 19},
{"zulaman", 3805},
{"valley_of_kings", 924},
{"twilight_citidel", 5473},
{"marris_stead", 2260},
{"gorgrond", 6721},
{"deadwind_pass", 41},
{"tanaris", 440},
{"the_crucible", 13655},
{"provis_fauna", 13706},
{"akstad", 8279},
{"black_tooth_hovel", 5652},
{"bradensbrook", 7642},
{"burning_breach", 9145},
{"chapel_gardens", 6386},
{"embaari_village", 6923},
{"emerald_nightmare", 8026},
{"feast_of_arrogance", 10980},
{"glutharns_decay", 12805},
{"halls_of_atonement", 10995},
{"hellfire_peninsula", 3483},
{"korthia", 13570},
{"lake_elrendar", 3473},
{"lunarfall", 6790},
{"outrigger_post", 9582},
{"skettis", 3679},
{"talador", 6662},
{"thastalah_basin", 7668},
{"the_cracking_plains", 6774},
{"the_lost_isles", 4720},
{"the_shadow_vault", 4477},
{"the_tremaculum", 13216},
{"tomb_of_the_old_kings", 7744},
{"uldum", 5034},
{"underrot", 9391},
{"wakeners_enclave", 8946},
{"wardens_redoubt", 8371},
{"waycrest_manor", 9561},
{"winterspring", 618},
{"zangarmarsh", 3521},
{"moonbrook", 20},
{"crapopolis", 11455},
{"the_heartland", 5992},
{"queens_court", 10425},
{"nyalotha", 12877},
};
local MAX_INDEX = #AreaData;
local MAX_PAGE = math.ceil(MAX_INDEX/NUM_BUTTONS);
local RaceImage = {
--[raceID] = imageIndex
[1] = 1, --Human
[2] = 13, --Orc
[3] = 2, --Dwarf
[4] = 3, --NE
[5] = 14, --UD
[6] = 15, --Tauren
[7] = 4, --Gnome
[8] = 16, --Troll
[9] = 18, --Goblin
[10]= 17, --BE
[11]= 5, --Draenei
[22]= 6, --Worgen
[24]= 7, --Pandaren
[25]= 7,
[26]= 7,
[27]= 19, --Suramar
[28]= 20, --Highmountain
[29]= 8, --VE
[30]= 9, --Lightforged
[31]= 22, --Zandalari
[32]= 11, --Kul Tiran
[34]= 10, --Dark Iron
[35]= 23, --Vulpera
[36]= 21, --Maghar
[37]= 12, --Mechagnome
};
local ClassImage = {
--[classID] = imageIndex
[1] = 24, --Warrior
[2] = 30, --Paladin
[3] = 25, --Hunter
[4] = 27, --Rogue
[5] = 28, --Priest
[6] = 35, --DK
[7] = 32, --Shaman
[8] = 26, --Mage
[9] = 29, --Warlock
[10] = 33, --Monk
[11] = 31, --Druid
[12] = 34, --DH
};
local Buttons = {};
local function SetupThumbnail(texture, index, inset)
--"inset" is used to compensate the resampling issue (nicer edge)
if index > MAX_INDEX then
return false
else
local row = modf((index - 1) * 0.125);
local col = index - row * 8 - 1;
texture:SetTexCoord(col*0.125 + inset, (col+1)*0.125 - inset, row*0.0625 + inset, (row+1)*0.0625 - inset);
return true
end
end
local function SetupSelection(button)
SelectionFrame:ClearAllPoints();
SelectionFrame.AnimShrink:Stop();
if button then
SelectionFrame:SetPoint("CENTER", button, "CENTER", 0, 0);
SelectionFrame:Show();
SelectionFrame.AnimShrink:Play();
SelectionFrame:SetParent(button);
else
SelectionFrame:Hide();
SelectionFrame:SetParent(MainFrame);
end
end
local function SetPreviewImage(index, forceReload)
if index ~= PREVIEW_INDEX or forceReload then
PREVIEW_INDEX = index;
SetupThumbnail(BackdropContainer.BackdropPreview, index, 0);
BackdropContainer.BackdropPreview.FadeOut:Stop();
BackdropContainer.BackdropPreview:Show();
BackdropContainer.BackdropPreview.FadeOut:Play();
end
BackdropContainer.Backdrop:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\Backdrops\\"..AreaData[index][1]);
end
local function CalculateSize(a, pixel)
return math.floor(a/pixel + 0.5)*pixel
end
local function ShowFrame_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
local width = outQuart(self.t, self.fromWidth, self.toWidth, self.duration);
if self.t >= self.duration then
width = self.toWidth;
end
local bt, alpha, offsetY;
alpha = self.t * 4;
if alpha > 1 then
alpha = 1;
end
self.PageText:SetAlpha(alpha);
self.Title:SetAlpha(alpha);
for i = 1, NUM_BUTTONS do
bt = self.t - Buttons[i].row * 0.08;
if bt > 0 then
alpha = bt * 4;
if alpha > 1 then
alpha = 1;
end
offsetY = outQuart(bt, self.buttonOffsetY, 0, 0.5);
if bt >= 0.5 then
offsetY = 0;
alpha = 1;
--[[
if (not self.pageTurned) and Buttons[i].index == SELECTED_INDEX then
self.pageTurned = true;
SetupSelection(Buttons[i]);
end
--]]
end
else
alpha = 0;
offsetY = self.buttonOffsetY;
end
Buttons[i]:SetAlpha(alpha);
Buttons[i]:SetOffsetY(offsetY);
end
if bt >= 0.5 then
self:SetScript("OnUpdate", nil);
end
self:SetWidth(width);
end
local function CloseNoChange_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
local width = outSine(self.t, self.fromWidth, 4, 0.5);
local alpha = 1 - 4*self.t;
if alpha < 0 then
alpha = 0;
end
if self.t >= 0.5 then
width = 4;
alpha = 0;
self:Hide();
end
for i = 1, NUM_BUTTONS do
Buttons[i]:SetAlpha(alpha);
end
self.PageText:SetAlpha(alpha);
self.Title:SetAlpha(alpha);
self:SetWidth(width);
end
local function SelectAndClose_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
local wT = self.t - 0.5;
local width;
if wT > 0 then
width = outSine(wT, self.fromWidth, 4, 0.5);
self:SetWidth(width);
end
local alpha = 1 - 4*self.t;
if alpha < 0.2 then
alpha = 0.2;
end
if wT >= 0.5 then
width = 4;
alpha = 0;
self:Hide();
end
for i = 1, NUM_BUTTONS do
if Buttons[i].index ~= SELECTED_INDEX then
Buttons[i]:SetAlpha(alpha);
end
end
self.PageText:SetAlpha(alpha);
self.Title:SetAlpha(alpha);
end
local function UseCurrentClassBackground()
local _, _, id = UnitClass("player");
SetPreviewImage((id and ClassImage[id]) or 34);
end
local function UseCurrentRaceBackground()
local _, _, id = UnitRace("player");
SetPreviewImage((id and RaceImage[id]) or 1);
end
local function UseModelBackgroundImage()
local index = NarciTurntableOptions.BackgroundImageID;
if not (index and AreaData[index]) then
local _, _, id = UnitClass("player");
index = (id and ClassImage[id]) or 34;
end
SELECTED_INDEX = index;
SetPreviewImage(index);
MainFrame.swtich.ValueText:SetText( C_Map.GetAreaInfo(AreaData[index][2]) );
end
local function SetTextureCurrentClass(texture)
local _, _, id = UnitClass("player");
local index = (id and ClassImage[id]) or 34;
texture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Modules\\Showcase\\Backdrops\\"..AreaData[index][1]);
end
addon.UseCurrentClassBackground = UseCurrentClassBackground;
addon.UseCurrentRaceBackground = UseCurrentRaceBackground;
addon.UseModelBackgroundImage = UseModelBackgroundImage;
addon.SetTextureCurrentClass = SetTextureCurrentClass;
local function AbandonChangeAndClose()
if SELECTED_INDEX then
SetPreviewImage(SELECTED_INDEX);
MainFrame:SetZoneName(AreaData[SELECTED_INDEX][2]);
end
MainFrame:Close();
end
NarciShowcaseThumbnailButtonMixin = {};
function NarciShowcaseThumbnailButtonMixin:OnClick(button)
if button == "LeftButton" then
SELECTED_INDEX = self.index;
SetPreviewImage(self.index);
SetupSelection(self);
MainFrame.pageTurned = true;
MainFrame:Close(true);
NarciTurntableOptions.BackgroundImageID = self.index;
UseModelBackgroundImage();
else
AbandonChangeAndClose();
end
end
function NarciShowcaseThumbnailButtonMixin:OnEnter()
HighlightFrame:ClearAllPoints();
HighlightFrame:SetPoint("CENTER", self, "CENTER", 0, 0);
HighlightFrame.FadeIn:Stop();
if self.index then
SetPreviewImage(self.index);
FocusedButton = self;
MainFrame:SetZoneName(AreaData[self.index][2]);
HighlightFrame:Show();
HighlightFrame.FadeIn:Play();
else
FocusedButton = nil;
HighlightFrame:Hide();
end
end
function NarciShowcaseThumbnailButtonMixin:OnLeave()
if not self:IsMouseOver() then
HighlightFrame:Hide();
end
if SELECTED_INDEX then
SetPreviewImage(SELECTED_INDEX);
MainFrame:SetZoneName(AreaData[SELECTED_INDEX][2]);
end
end
function NarciShowcaseThumbnailButtonMixin:OnMouseDown()
HighlightFrame.Highlight:SetColorTexture(1, 1, 1, 0.14);
end
function NarciShowcaseThumbnailButtonMixin:OnMouseUp()
HighlightFrame.Highlight:SetColorTexture(1, 1, 1, 0.1);
end
function NarciShowcaseThumbnailButtonMixin:SetData(index)
if SetupThumbnail(self.Texture, index, 0.001) then
self:Show();
self.index = index;
else
self:Hide();
self.index = nil;
end
end
function NarciShowcaseThumbnailButtonMixin:SetButtonSize(side, inset)
self:SetSize(side, side);
self:SetHitRectInsets(-inset, -inset, -inset, -inset);
end
function NarciShowcaseThumbnailButtonMixin:SetFinalPosition(x, y)
self:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", x, y);
self.toX = x;
self.toY = y;
end
function NarciShowcaseThumbnailButtonMixin:SetOffsetY(dy)
self:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", self.toX, self.toY + dy);
end
function NarciShowcaseThumbnailButtonMixin:ClearTemps()
self.toX, self.toY = nil, nil;
end
NarciShowcaseBackdropSelectMixin = {};
function NarciShowcaseBackdropSelectMixin:OnLoad()
self.sizeChanged = true;
self.rootFrame = self:GetParent();
MainFrame = self;
BackdropContainer = self:GetParent().ModelScene;
SelectionFrame = self.SelectionFrame;
HighlightFrame = self.HighlightFrame;
end
function NarciShowcaseBackdropSelectMixin:OnShow()
self:CreateThumbnails();
if not self.page then
self.page = 1;
self:SetPage(self.page);
end
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
end
function NarciShowcaseBackdropSelectMixin:OnHide()
FocusedButton = nil;
self:Hide();
self.CursorBlock:Hide();
HighlightFrame:Hide();
self.t = nil;
self.isActive = nil;
self.pageTurned = nil;
self:SetScript("OnUpdate", nil);
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
self:StopAnimating();
for _, button in pairs(Buttons) do
button:ClearTemps();
end
end
function NarciShowcaseBackdropSelectMixin:OnEvent(event, key)
if not (self:IsMouseOver() or self.swtich:IsMouseOver() or self.rootFrame:IsMouseOver()) then
if key ~= "MiddleButton" then
self:Close();
end
end
end
function NarciShowcaseBackdropSelectMixin:OnMouseDown(button)
if button == "RightButton" then
AbandonChangeAndClose();
end
end
function NarciShowcaseBackdropSelectMixin:CreateThumbnails()
local level = self:GetFrameLevel() + 2;
self.CursorBlock:SetFrameLevel(level + 10);
local pixel, multipler = self:GetParent():GetPixelSize();
local spanX = self.fullWidth - math.floor(multipler * 48 + 0.5) * pixel;
spanX = CalculateSize(spanX, pixel);
local spacing = math.floor(6 * multipler + 0.5) * pixel;
local buttonHitRectInset = spacing * 0.6;
local frameWidth = self.fullWidth;
local frameHeight = self:GetHeight();
local side = (spanX - (NUM_COL - 1) * spacing) / NUM_COL;
side = CalculateSize(side, pixel);
local frameLeft = self:GetLeft();
local offsetX = CalculateSize((frameWidth - spanX) * 0.5, pixel);
local spanY = (side + spacing) * NUM_ROW - spacing;
local offsetY = CalculateSize(-(frameHeight - spanY) * 0.5, pixel);
local distance = side + spacing;
local col, row = 0, 0;
local button;
for i = 1, 24 do
button = Buttons[i];
if not button then
Buttons[i] = CreateFrame("Button", nil, self, "NarciShowcaseThumbnailButtonTemplate");
button = Buttons[i];
button.row = row;
button.col = col;
end
button:SetButtonSize(side, buttonHitRectInset);
button:SetFinalPosition( CalculateSize(offsetX + col * distance, pixel), CalculateSize(offsetY - row * distance, pixel));
button:SetFrameLevel(level);
col = col + 1;
if col >= NUM_COL then
col = 0;
row = row + 1;
end
end
self.buttonOffsetY = side * -0.25;
self.Title:ClearAllPoints();
self.Title:SetPoint("BOTTOMLEFT", self, "TOPLEFT", offsetX, offsetY + 2*spacing);
self.Title:SetWidth(spanX);
if multipler > 1 then
self.Title:SetFontObject("NarciFontUniversal12");
else
self.Title:SetFontObject("NarciFontUniversal9");
end
self.Title:SetTextColor(0.8, 0.8, 0.8);
self.PageText:ClearAllPoints();
self.PageText:SetPoint("TOPRIGHT", self, "TOPLEFT", offsetX + NUM_COL * distance - spacing, offsetY - NUM_ROW*distance - spacing);
HighlightFrame:SetSize(side, side);
HighlightFrame:SetFrameLevel(level + 1);
SelectionFrame:SetSize(side, side);
SelectionFrame.BorderOutter:SetSize(side + 6*pixel, side + 6*pixel);
SelectionFrame.Exclusion:SetSize(side - 4*pixel, side - 4*pixel);
SelectionFrame:SetFrameLevel(level + 2);
end
function NarciShowcaseBackdropSelectMixin:SetPage(page)
page = page or 1;
local offset = (page - 1)*24;
local id;
SetupSelection(nil);
for i = 1, 24 do
id = i + offset;
Buttons[i]:SetData(id);
if id == SELECTED_INDEX then
SetupSelection(Buttons[i]);
end
end
self.PageText:SetText(string.format(COLLECTION_PAGE_NUMBER, self.page, MAX_PAGE));
if FocusedButton then
FocusedButton:OnEnter();
end
end
function NarciShowcaseBackdropSelectMixin:OnMouseWheel(delta)
if delta < 0 and self.page < MAX_PAGE then
self.page = self.page + 1;
self:SetPage(self.page);
self.pageTurned = true;
elseif delta > 0 and self.page > 1 then
self.page = self.page - 1;
self:SetPage(self.page);
self.pageTurned = true;
end
end
function NarciShowcaseBackdropSelectMixin:SetZoneName(id)
if id then
self.Title:SetText( C_Map.GetAreaInfo(id) );
end
end
function NarciShowcaseBackdropSelectMixin:HasFocus()
return self:IsVisible() and self:IsMouseOver();
end
function NarciShowcaseBackdropSelectMixin:SetFrameWidth(width)
self.toWidth = width;
self.fullWidth = width;
self:SetWidth(width);
self.CursorBlock:SetWidth(width);
end
function NarciShowcaseBackdropSelectMixin:Open()
if not self.isActive then
self.isActive = true;
--SelectionFrame:Hide();
self.fromWidth = 4;
self.t = 0;
self.duration = 0.6;
self:SetScript("OnUpdate", ShowFrame_OnUpdate);
self:Show();
self.CursorBlock:Hide();
end
end
function NarciShowcaseBackdropSelectMixin:Close(anyChange)
if self.isActive then
self.isActive = nil;
self.pageTurned = nil;
self.fromWidth = self:GetWidth();
self.t = 0;
if anyChange then
self.duration = 0.6;
self:SetScript("OnUpdate", SelectAndClose_OnUpdate);
else
self.duration = 0.6;
self:SetScript("OnUpdate", CloseNoChange_OnUpdate);
end
self.CursorBlock:Show();
end
end
function NarciShowcaseBackdropSelectMixin:Toggle()
if self.isActive then
self:Close();
else
self:Open();
end
end
--texture:IsObjectLoaded()