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.
2912 lines
96 KiB
2912 lines
96 KiB
local _, addon = ...
|
|
local L = addon.L;
|
|
local API = addon.API;
|
|
local CallbackRegistry = addon.CallbackRegistry;
|
|
local CameraUtil = addon.CameraUtil;
|
|
local ThemeUtil = addon.ThemeUtil;
|
|
local TooltipFrame = addon.SharedTooltip;
|
|
local KeyboardControl = addon.KeyboardControl;
|
|
local NameplateGossip = addon.NameplateGossip;
|
|
local AlertFrame = addon.AlertFrame; --top right of the screen
|
|
local ExperienceBar = addon.CreateStatusBar(nil, "xp");
|
|
local ChatFrame = addon.ChatFrame;
|
|
local FriendshipBar = addon.FriendshipBar;
|
|
local PlaySound = addon.PlaySound;
|
|
local IsAutoSelectOption = addon.IsAutoSelectOption;
|
|
local IS_MODERN_WOW = not addon.IS_CLASSIC;
|
|
|
|
local FadeFrame = API.UIFrameFade;
|
|
local CloseGossipInteraction = API.CloseGossipInteraction;
|
|
local IsPlayingCutscene = API.IsPlayingCutscene;
|
|
|
|
-- User Settings
|
|
local ALWAYS_GOSSIP = false;
|
|
local FRAME_SIZE_MULTIPLIER = 1.1; --Default: 1.1
|
|
local SCROLLDOWN_THEN_ACCEPT_QUEST = false;
|
|
local AUTO_SELECT_GOSSIP = false;
|
|
local INPUT_DEVICE_GAME_PAD = false;
|
|
local SHOW_NPC_NAME = false;
|
|
local MARK_HIGHEST_SELL_PRICE = false;
|
|
------------------
|
|
|
|
local PADDING_H = 26.0;
|
|
local PADDING_TOP = 48.0;
|
|
local PADDING_BOTTOM = 36.0;
|
|
local BUTTON_HORIZONTAL_GAP = 8.0;
|
|
local FRAME_OFFSET_RATIO = 3/4; --Center align to 1/4 of the WorldFrame width (to the right)
|
|
|
|
local FONT_SIZE = 12;
|
|
local TEXT_SPACING = FONT_SIZE*0.35; --Font Size /3
|
|
local PARAGRAPH_SPACING = 4*TEXT_SPACING; --4 * TEXT_SPACING
|
|
local PARAGRAPH_BUTTON_SPACING = 2*FONT_SIZE; --Font Size * 2
|
|
|
|
local CreateFrame = CreateFrame;
|
|
local C_CampaignInfo = C_CampaignInfo;
|
|
local C_GossipInfo = C_GossipInfo;
|
|
local GetGossipText = API.GetGossipText;
|
|
local CloseQuest = CloseQuest;
|
|
local GetOptions = C_GossipInfo.GetOptions;
|
|
local GetAvailableQuests = C_GossipInfo.GetAvailableQuests;
|
|
local GetActiveQuests = C_GossipInfo.GetActiveQuests;
|
|
local ForceGossip = C_GossipInfo.ForceGossip;
|
|
|
|
|
|
local QuestIsFromAreaTrigger = API.QuestIsFromAreaTrigger;
|
|
local GetQuestText = API.GetQuestText; --usage GetQuestText("type") type: Detail, Progress, Complete, Greeting
|
|
local GetQuestTitle = GetTitleText;
|
|
local GetObjectiveText = GetObjectiveText;
|
|
local GetNumQuestItems = GetNumQuestItems;
|
|
local GetNumQuestCurrencies = GetNumQuestCurrencies;
|
|
local GetQuestID = GetQuestID;
|
|
local IsQuestCompletable = IsQuestCompletable;
|
|
local IsQuestItemHidden = IsQuestItemHidden;
|
|
local GetQuestMoneyToGet = GetQuestMoneyToGet;
|
|
local GetMoney = GetMoney;
|
|
local GetNumAvailableQuests = GetNumAvailableQuests;
|
|
local GetAvailableTitle = GetAvailableTitle;
|
|
local GetNumActiveQuests = GetNumActiveQuests;
|
|
local GetAvailableQuestInfo = API.GetAvailableQuestInfo;
|
|
local GetActiveQuestID = API.GetActiveQuestID;
|
|
local GetActiveTitle = GetActiveTitle;
|
|
local GetSuggestedGroupSize = API.GetSuggestedGroupSize;
|
|
local UnitExists = UnitExists;
|
|
local UnitName = UnitName;
|
|
local SetPortraitTexture = SetPortraitTexture;
|
|
local AcceptQuest = AcceptQuest;
|
|
local GetQuestPortraitGiver = GetQuestPortraitGiver;
|
|
local GetNumQuestChoices = GetNumQuestChoices;
|
|
local AcknowledgeAutoAcceptQuest = AcknowledgeAutoAcceptQuest;
|
|
|
|
|
|
local After = C_Timer.After;
|
|
local tinsert = table.insert;
|
|
local tsort = table.sort;
|
|
local find = string.find;
|
|
|
|
local Esaing_OutSine = addon.EasingFunctions.outSine;
|
|
local Round = API.Round;
|
|
|
|
local DeltaLerp = API.DeltaLerp;
|
|
local SCROLL_BLEND_SPEED = 0.15; --0.2
|
|
|
|
local MainFrame;
|
|
|
|
local SETTINGS_UI_VISIBLE = false;
|
|
|
|
local function ScrollFrame_Easing(self, elapsed)
|
|
self.value = DeltaLerp(self.value, self.scrollTarget, SCROLL_BLEND_SPEED, elapsed);
|
|
|
|
if (self.value - self.scrollTarget) > -0.4 and (self.value - self.scrollTarget) < 0.4 then
|
|
--complete
|
|
self.value = self.scrollTarget;
|
|
self:SetScript("OnUpdate", nil);
|
|
|
|
if self.value == 0 then
|
|
--at top
|
|
--self.borderTop:Hide();
|
|
--FadeFrame(self.borderTop, 0.25, 0);
|
|
elseif self.value == self.range then
|
|
--at bottom
|
|
--self.borderBottom:Hide();
|
|
--FadeFrame(self.borderBottom, 0.25, 0);
|
|
end
|
|
end
|
|
|
|
self.topDividerAlpha = self.value/24;
|
|
if self.topDividerAlpha > 1 then
|
|
self.topDividerAlpha = 1;
|
|
elseif self.topDividerAlpha < 0 then
|
|
self.topDividerAlpha = 0;
|
|
end
|
|
self.borderTop:SetAlpha(self.topDividerAlpha);
|
|
|
|
self.BottomDividerAlpha = (self.range - self.value)/24;
|
|
if self.BottomDividerAlpha > 1 then
|
|
self.BottomDividerAlpha = 1;
|
|
elseif self.BottomDividerAlpha < 0 then
|
|
self.BottomDividerAlpha = 0;
|
|
end
|
|
self.borderBottom:SetAlpha(self.BottomDividerAlpha);
|
|
|
|
self:SetVerticalScroll(self.value);
|
|
end
|
|
|
|
|
|
DUIDialogBaseMixin = {};
|
|
|
|
function DUIDialogBaseMixin:CalculateBestFrameHeight()
|
|
local viewportWidth, viewportHeight = WorldFrame:GetSize(); --height unaffected by screen resolution
|
|
|
|
local heightRatio = 0.618;
|
|
local frameHeight = heightRatio * viewportHeight;
|
|
local heightInPixel = API.GetSizeInPixel(self:GetEffectiveScale(), frameHeight);
|
|
|
|
if heightInPixel < 640 then
|
|
--Switch to low resolution textures?
|
|
end
|
|
|
|
return frameHeight
|
|
end
|
|
|
|
local Schematic = {
|
|
["BackgroundFrame.ClipFrame.BackgroundDecor"] = {width = 360, height = 360},
|
|
["FrontFrame.FooterDivider"] = {width = 392, height = 34},
|
|
["FrontFrame.HeaderDivider"] = {width = 392, height = 34},
|
|
["FrontFrame.Header"] = {width = 358, height = 51, point = "TOP", relativePoint = "TOP", x = 0, y = -28},
|
|
["FrontFrame.Header.Portrait"] = {width = 34, height = 34, point = "CENTER", relativePoint = "TOPLEFT", x = 23, y = -23},
|
|
["FrontFrame.Header.Divider"] = {width = 358, height = 51},
|
|
["FrontFrame.Header.Title"] = {point = "LEFT", relativePoint = "LEFT", x = 53, y = 2},
|
|
["FrontFrame.Header.TopLight"] = {width = 358, height = 34},
|
|
};
|
|
|
|
local function SetupObjectSize(root, key, data)
|
|
local obj = root;
|
|
|
|
for k in string.gmatch(key, "%a+") do
|
|
obj = obj[k];
|
|
end
|
|
|
|
if data.width then
|
|
obj:SetSize(data.width * FRAME_SIZE_MULTIPLIER, data.height * FRAME_SIZE_MULTIPLIER);
|
|
end
|
|
|
|
if data.point then
|
|
obj:SetPoint(data.point, obj:GetParent(), data.relativePoint, data.x * FRAME_SIZE_MULTIPLIER, data.y * FRAME_SIZE_MULTIPLIER);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:UpdateFrameSize()
|
|
local viewportWidth, viewportHeight = WorldFrame:GetSize(); --height unaffected by screen resolution
|
|
viewportWidth = math.min(viewportWidth, viewportHeight * 16/9);
|
|
|
|
AlertFrame:ClearAllPoints();
|
|
local alertFrameOffset = 36;
|
|
AlertFrame:SetPoint("TOPRIGHT", nil, "CENTER", 0.5*viewportWidth - alertFrameOffset, 0.5*viewportHeight - alertFrameOffset);
|
|
|
|
ExperienceBar:SetPoint("BOTTOM", nil, "BOTTOM", 0, -2);
|
|
ExperienceBar:SetBarWidth(viewportWidth);
|
|
ExperienceBar:SetHeight(8);
|
|
ExperienceBar:SetNumCompartment(20);
|
|
|
|
ChatFrame:ClearAllPoints();
|
|
ChatFrame:SetPoint("BOTTOMLEFT", ExperienceBar, "TOPLEFT", 8, 8);
|
|
|
|
FriendshipBar:ClearAllPoints();
|
|
FriendshipBar:SetPoint("CENTER", self, "TOP", 0, 0);
|
|
|
|
local frameRatio = 0.85;
|
|
local frameHeight = self:CalculateBestFrameHeight() * FRAME_SIZE_MULTIPLIER;
|
|
local frameWidth = API.Round(frameHeight * frameRatio);
|
|
frameHeight = API.Round(frameHeight);
|
|
self:SetSize(frameWidth, frameHeight);
|
|
|
|
local paddingH = PADDING_H * FRAME_SIZE_MULTIPLIER;
|
|
local paddingTop = PADDING_TOP * FRAME_SIZE_MULTIPLIER;
|
|
local paddingBottom = PADDING_BOTTOM * FRAME_SIZE_MULTIPLIER;
|
|
|
|
self.frameWidth = frameWidth;
|
|
self.frameHeight = frameHeight;
|
|
self.halfFrameWidth = Round(0.5* (frameWidth - 2*paddingH - BUTTON_HORIZONTAL_GAP));
|
|
self.quarterFrameWidth = Round(0.25* (frameWidth - 2*paddingH - 3*BUTTON_HORIZONTAL_GAP));
|
|
|
|
local offsetRatio = FRAME_OFFSET_RATIO;
|
|
local frameOffsetX = Round(viewportWidth*(offsetRatio - 0.5));
|
|
self.frameOffsetX = frameOffsetX;
|
|
self:ClearAllPoints();
|
|
self:SetPoint("CENTER", nil, "CENTER", frameOffsetX, 0);
|
|
|
|
self.FrontFrame:SetPoint("TOPLEFT", self, "TOPLEFT", paddingH, 0);
|
|
self.FrontFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -paddingH, 0);
|
|
|
|
local parchmentWidth = 546.13 * FRAME_SIZE_MULTIPLIER; --API.GetPixelForScale(1, 1024);
|
|
local parchmentheight = 136.53 * FRAME_SIZE_MULTIPLIER; --API.GetPixelForScale(1, 256);
|
|
|
|
self.Parchments[1]:SetSize(parchmentWidth, parchmentheight);
|
|
self.Parchments[3]:SetSize(parchmentWidth, parchmentheight);
|
|
|
|
for key, data in pairs(Schematic) do
|
|
SetupObjectSize(self, key, data);
|
|
end
|
|
|
|
local AcceptButton = self:AcquireAcceptButton();
|
|
AcceptButton:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", paddingH, paddingBottom);
|
|
AcceptButton:SetButtonWidth(self.halfFrameWidth);
|
|
|
|
local GoodbyeButton = self:AcquireExitButton();
|
|
GoodbyeButton:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -paddingH, paddingBottom);
|
|
GoodbyeButton:SetButtonWidth(self.halfFrameWidth);
|
|
|
|
--Resize Footer
|
|
local footerButtonHeight = GoodbyeButton:GetHeight();
|
|
local footerOffset = Round(footerButtonHeight + paddingBottom + BUTTON_HORIZONTAL_GAP*2); --Default: 96 Affected by GoddbyeButton height
|
|
|
|
self.FrontFrame.FooterDivider:ClearAllPoints();
|
|
self.FrontFrame.FooterDivider:SetPoint("CENTER", self.FrontFrame, "BOTTOM", 0, footerOffset);
|
|
self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", paddingH, -42);
|
|
self.ScrollFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -paddingH, footerOffset);
|
|
|
|
local scrollFrameBaseHeight = self.ScrollFrame:GetHeight();
|
|
self.ScrollFrame.range = 0;
|
|
self.scrollFrameBaseHeight = scrollFrameBaseHeight;
|
|
self.scrollViewHeight = scrollFrameBaseHeight;
|
|
|
|
local contentWidth = frameWidth - 2*paddingH;
|
|
local contentHeight = Round(scrollFrameBaseHeight);
|
|
self.ContentFrame:SetWidth(Round(contentWidth));
|
|
self.ContentFrame:SetHeight(contentHeight); --Irrelevant
|
|
self.ContentFrame:SetPoint("TOPLEFT", self.ScrollFrame, "TOPLEFT", 0, 0);
|
|
self.ContentFrame:SetPoint("BOTTOMRIGHT", self.ScrollFrame, "BOTTOMRIGHT", 0, 0);
|
|
self.contentWidth = contentWidth;
|
|
|
|
self.InputBox:ClearAllPoints();
|
|
self.InputBox:SetPoint("LEFT", self, "LEFT", PADDING_H, 0);
|
|
self.InputBox:SetPoint("RIGHT", self, "RIGHT", -PADDING_H, 0);
|
|
|
|
if self.optionButtonPool then
|
|
local buttonWidth = self.frameWidth - 2*PADDING_H*FRAME_SIZE_MULTIPLIER;
|
|
local function UpdateButtonWidth(button)
|
|
button:SetButtonWidth(buttonWidth);
|
|
end
|
|
self.optionButtonPool:ProcessAllObjects(UpdateButtonWidth);
|
|
end
|
|
|
|
if self.itemButtonPool then
|
|
local buttonWidth = self.halfFrameWidth;
|
|
local function UpdateButtonWidth(button)
|
|
button:SetButtonWidth(buttonWidth);
|
|
end
|
|
self.itemButtonPool:ProcessAllObjects(UpdateButtonWidth);
|
|
end
|
|
|
|
if self.smallItemButtonPool then
|
|
local buttonWidth = self.quarterFrameWidth;
|
|
local function UpdateButtonWidth(button)
|
|
button:SetButtonWidth(buttonWidth);
|
|
end
|
|
self.smallItemButtonPool:ProcessAllObjects(UpdateButtonWidth);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnLoad()
|
|
--table.insert(UISpecialFrames, self:GetName());
|
|
MainFrame = self;
|
|
addon.DialogueUI = self;
|
|
|
|
TooltipFrame:SetParent(self);
|
|
TooltipFrame:SetShowDelay(0.25);
|
|
|
|
AlertFrame:SetParent(self);
|
|
ChatFrame:SetParent(self);
|
|
FriendshipBar:SetParent(self);
|
|
|
|
ExperienceBar:SetParent(self);
|
|
ExperienceBar:OnLoad();
|
|
ExperienceBar:Show();
|
|
ExperienceBar:SetFrameStrata("BACKGROUND");
|
|
ExperienceBar:SetFixedFrameStrata(true);
|
|
|
|
addon.Banner:SetParent(self);
|
|
|
|
self.ButtonHighlight = self.ContentFrame.ButtonHighlight;
|
|
self.RewardSelection = self.ContentFrame.RewardSelection;
|
|
self.GamePadFocusIndicator = CreateFrame("Frame", nil, self.FrontFrame, "DUIDialogHotkeyTemplate");
|
|
self.GamePadFocusIndicator:SetIgnoreParentAlpha(true);
|
|
|
|
API.DisableSharpening(self.ButtonHighlight.BackTexture);
|
|
|
|
--Frame Background
|
|
self.Parchments = {};
|
|
|
|
for i = 1, 3 do
|
|
local piece = self.BackgroundFrame:CreateTexture(nil, "BACKGROUND", nil, -1);
|
|
self.Parchments[i] = piece;
|
|
end
|
|
|
|
self.Parchments[1]:SetTexCoord(0, 1, 0, 256/2048);
|
|
self.Parchments[1]:SetPoint("CENTER", self, "TOP", 0, 0);
|
|
|
|
self.Parchments[3]:SetTexCoord(0, 1, 896/2048, 1152/2048);
|
|
self.Parchments[3]:SetPoint("CENTER", self, "BOTTOM", 0, 0);
|
|
|
|
self.Parchments[2]:SetTexCoord(0, 1, 256/2048, 896/2048);
|
|
self.Parchments[2]:SetPoint("TOPLEFT", self.Parchments[1], "BOTTOMLEFT", 0, 0);
|
|
self.Parchments[2]:SetPoint("BOTTOMRIGHT", self.Parchments[3], "TOPRIGHT", 0, 0);
|
|
|
|
self.BackgroundDecor = self.BackgroundFrame.ClipFrame.BackgroundDecor;
|
|
|
|
do
|
|
self.ScrollFrame.borderTop = self.FrontFrame.HeaderDivider;
|
|
self.ScrollFrame.borderBottom = self.FrontFrame.FooterDivider;
|
|
end
|
|
|
|
self:ResetScroll();
|
|
|
|
local offsetPerScroll = 96;
|
|
|
|
local function ScrollFrame_OnMouseWheel(f, delta)
|
|
if delta > 0 then
|
|
self:ScrollBy(-offsetPerScroll);
|
|
else
|
|
self:ScrollBy(offsetPerScroll);
|
|
end
|
|
end
|
|
|
|
self.ScrollFrame:SetScript("OnMouseWheel", ScrollFrame_OnMouseWheel);
|
|
self.ScrollFrame.OnMouseWheel = ScrollFrame_OnMouseWheel;
|
|
|
|
local function CreateFontString()
|
|
local fontString = self.ContentFrame:CreateFontString(nil, "ARTWORK", "DUIFont_Quest_Paragraph");
|
|
fontString:SetSpacing(TEXT_SPACING);
|
|
return fontString
|
|
end
|
|
|
|
local function RemoveFontString(fontString)
|
|
fontString:SetText(nil);
|
|
fontString:Hide();
|
|
fontString:ClearAllPoints();
|
|
end
|
|
|
|
self.fontStringPool = API.CreateObjectPool(CreateFontString, RemoveFontString);
|
|
|
|
|
|
local function CreateOptionButton()
|
|
local button = CreateFrame("Button", nil, self.ContentFrame, "DUIDialogOptionButtonTemplate");
|
|
button:SetButtonWidth(self.frameWidth - 2*PADDING_H*FRAME_SIZE_MULTIPLIER);
|
|
button:SetOwner(self);
|
|
return button
|
|
end
|
|
|
|
local function RemoveOptionButton(button)
|
|
button:Hide();
|
|
button:ClearAllPoints();
|
|
button.HotkeyFrame = nil;
|
|
end
|
|
|
|
local function OnAcquireOptionButton(button)
|
|
button:ResetVisual();
|
|
end
|
|
|
|
self.optionButtonPool = API.CreateObjectPool(CreateOptionButton, RemoveOptionButton, OnAcquireOptionButton);
|
|
|
|
|
|
local function CreateTextBackground()
|
|
local texture = self.ContentFrame:CreateTexture(nil, "BORDER");
|
|
local corner = 8;
|
|
texture:SetTextureSliceMargins(corner, corner, corner, corner);
|
|
texture:SetTextureSliceMode(1);
|
|
texture:SetTexture(ThemeUtil:GetTextureFile("SubHeaderBackground.png"));
|
|
texture:SetSize(36, 36);
|
|
return texture
|
|
end
|
|
|
|
local function RemoveTextBackground(texture)
|
|
texture:ClearAllPoints();
|
|
texture:Hide();
|
|
end
|
|
|
|
self.textBackgroundPool = API.CreateObjectPool(CreateTextBackground, RemoveTextBackground);
|
|
|
|
|
|
local function CreateItemButton()
|
|
local button = CreateFrame("Button", nil, self.ContentFrame, "DUIDialogItemButtonTemplate");
|
|
button:SetButtonWidth(self.halfFrameWidth);
|
|
return button
|
|
end
|
|
|
|
local function RemoveItemButton(itemButton)
|
|
itemButton:OnRelease();
|
|
end
|
|
|
|
local function OnAcquireItemButton(itemButton)
|
|
itemButton:SetAlpha(1);
|
|
itemButton:SetBackgroundTexture(1);
|
|
end
|
|
|
|
self.itemButtonPool = API.CreateObjectPool(CreateItemButton, RemoveItemButton, OnAcquireItemButton);
|
|
|
|
|
|
local function CreateSmallItemButton()
|
|
local button = CreateFrame("Button", nil, self.ContentFrame, "DUIDialogSmallItemButtonTemplate");
|
|
button:SetButtonWidth(self.quarterFrameWidth);
|
|
return button
|
|
end
|
|
|
|
local function RemoveSmallItemButton(itemButton)
|
|
itemButton:OnRelease();
|
|
end
|
|
|
|
self.smallItemButtonPool = API.CreateObjectPool(CreateSmallItemButton, RemoveSmallItemButton);
|
|
|
|
|
|
local function CreateQuestTypeFrame()
|
|
local f = CreateFrame("Frame", nil, self, "DUIDialogQuestTypeFrameTemplate");
|
|
return f
|
|
end
|
|
|
|
local function RemoveFrame(f)
|
|
f:Remove();
|
|
f:SetParent(self);
|
|
end
|
|
|
|
self.questTypeFramePool = API.CreateObjectPool(CreateQuestTypeFrame, RemoveFrame);
|
|
|
|
|
|
local function CreateIconFrame()
|
|
local f = CreateFrame("Frame", nil, self, "DUIDialogIconFrameTemplate");
|
|
return f
|
|
end
|
|
|
|
self.iconFramePool = API.CreateObjectPool(CreateIconFrame, RemoveFrame);
|
|
|
|
|
|
local function CreateHotkeyFrame()
|
|
local f = CreateFrame("Frame", nil, self, "DUIDialogHotkeyTemplate");
|
|
return f
|
|
end
|
|
|
|
local function RemoveHotkeyFrame(f)
|
|
f:Hide();
|
|
f:ClearAllPoints();
|
|
f:SetParent(self);
|
|
end
|
|
|
|
self.hotkeyFramePool = API.CreateObjectPool(CreateHotkeyFrame, RemoveHotkeyFrame);
|
|
|
|
if not self.Vignette then
|
|
self.Vignette = CreateFrame("Frame", nil);
|
|
self.Vignette:SetFrameStrata("BACKGROUND");
|
|
self.Vignette:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 0, 0);
|
|
self.Vignette:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", 0, 0);
|
|
self.Vignette:SetAlpha(0);
|
|
self.Vignette:Hide();
|
|
local texture = self.Vignette:CreateTexture(nil, "BACKGROUND");
|
|
texture:SetAllPoints(true);
|
|
texture:SetTexture("Interface/AddOns/DialogueUI/Art/Theme_Shared/ScreenVignette.png");
|
|
end
|
|
|
|
self:UpdateFrameSize();
|
|
|
|
API.SetPlayCutsceneCallback(function()
|
|
self:HideUI();
|
|
end);
|
|
|
|
|
|
self.OnLoad = nil;
|
|
self:SetScript("OnLoad", nil);
|
|
|
|
self.isGameLoading = true;
|
|
self:RegisterEvent("LOADING_SCREEN_DISABLED");
|
|
end
|
|
|
|
function DUIDialogBaseMixin:LoadTheme()
|
|
local prefix = ThemeUtil:GetTexturePath();
|
|
local parchmentFile = prefix.."Parchment.png";
|
|
local themeID = ThemeUtil:GetThemeID();
|
|
|
|
for _, piece in ipairs(self.Parchments) do
|
|
piece:SetTexture(parchmentFile);
|
|
end
|
|
|
|
self.FrontFrame.Header.Divider:SetTexture(parchmentFile);
|
|
self.FrontFrame.Header.Divider:SetTexCoord(0, 0.65625, 0.56640625, 0.61328125);
|
|
|
|
self.FrontFrame.Header.TopLight:SetTexture(parchmentFile);
|
|
self.FrontFrame.Header.TopLight:SetTexCoord(0, 0.65625, 0.65234375, 0.68359375);
|
|
|
|
self.FrontFrame.FooterDivider:SetTexture(parchmentFile);
|
|
self.FrontFrame.FooterDivider:SetTexCoord(0, 0.71875, 0.6875, 0.71875); --0, 0.65625, 0.6171875, 0.6484375
|
|
|
|
self.FrontFrame.HeaderDivider:SetTexture(parchmentFile);
|
|
self.FrontFrame.HeaderDivider:SetTexCoord(0, 0.71875, 0.72265625, 0.75390625); --0, 0.65625, 0.6484375, 0.6171875
|
|
|
|
self.RewardSelection.FrontTexture:SetTexture(prefix.."RewardChoice-Highlight.png");
|
|
self.RewardSelection.BackTexture:SetTexture(prefix.."RewardChoice-Highlight-Back.png");
|
|
self.RewardSelection.BackTexture:SetVertexColor(0.65, 0, 0);
|
|
|
|
if self.CopyTextButton then
|
|
self.CopyTextButton:SetTheme(themeID);
|
|
end
|
|
|
|
if self.TTSButton then
|
|
self.TTSButton:SetTheme(themeID);
|
|
end
|
|
|
|
if self.textBackgroundPool then
|
|
local bgFile = ThemeUtil:GetTextureFile("SubHeaderBackground.png");
|
|
local function SetBackGround(texture)
|
|
texture:SetTexture(bgFile);
|
|
end
|
|
self.textBackgroundPool:ProcessAllObjects(SetBackGround);
|
|
end
|
|
|
|
if self.optionButtonPool then
|
|
local method = "LoadTheme";
|
|
self.optionButtonPool:CallAllObjects(method);
|
|
end
|
|
|
|
if self.itemButtonPool then
|
|
local method = "LoadTheme";
|
|
self.itemButtonPool:CallAllObjects(method);
|
|
end
|
|
|
|
if self.hotkeyFramePool then
|
|
local method = "LoadTheme";
|
|
self.hotkeyFramePool:CallAllObjects(method);
|
|
end
|
|
|
|
self.GamePadFocusIndicator:LoadTheme();
|
|
|
|
if self.AcceptButton then
|
|
self.AcceptButton:LoadTheme();
|
|
end
|
|
|
|
if self.ExitButton then
|
|
self.ExitButton:LoadTheme();
|
|
end
|
|
|
|
FriendshipBar:LoadTheme();
|
|
TooltipFrame:LoadTheme();
|
|
|
|
self.ButtonHighlight.artID = nil;
|
|
|
|
self:OnSettingsChanged();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ReleaseAllObjects()
|
|
self.textHistory = {};
|
|
self.highlightedButton = nil;
|
|
self.fontStringPool:Release();
|
|
self.optionButtonPool:Release();
|
|
self.textBackgroundPool:Release();
|
|
self.itemButtonPool:Release();
|
|
self.smallItemButtonPool:Release();
|
|
self.questTypeFramePool:Release();
|
|
self.iconFramePool:Release();
|
|
self.hotkeyFramePool:Release();
|
|
|
|
self:ResetScroll();
|
|
self:HighlightButton(nil);
|
|
self:HighlightRewardChoice(nil);
|
|
self:ResetGamePadObjects();
|
|
|
|
KeyboardControl:ResetKeyActions();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireFontString()
|
|
return self.fontStringPool:Acquire();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireAcceptButton(enableHotkey)
|
|
if not self.AcceptButton then
|
|
self.AcceptButton = CreateFrame("Button", nil, self, "DUIDialogOptionButtonTemplate"); --self.FrontFrame
|
|
self.AcceptButton.HotkeyFrame = CreateFrame("Frame", nil, self.AcceptButton, "DUIDialogHotkeyTemplate");
|
|
self.AcceptButton:SetOwner(self);
|
|
self.AcceptButton:SetButtonAcceptQuest();
|
|
self.AcceptButtonLock = CreateFrame("Frame", nil, self.AcceptButton, "DUIDialogOptionButtonLockTemplate");
|
|
self.AcceptButton.ButtonLock = self.AcceptButtonLock;
|
|
self.AcceptButton:SetButtonWidth(self.halfFrameWidth);
|
|
end
|
|
|
|
if not self.AcceptButton:IsMouseOver() then
|
|
self.AcceptButton:ResetVisual();
|
|
end
|
|
|
|
self.AcceptButton:Hide(); --Trigger new OnEnter
|
|
self.AcceptButton:Show();
|
|
|
|
if enableHotkey then
|
|
KeyboardControl:SetKeyButton("PRIMARY", self.AcceptButton);
|
|
end
|
|
|
|
return self.AcceptButton
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireExitButton()
|
|
if not self.ExitButton then
|
|
self.ExitButton = CreateFrame("Button", nil, self, "DUIDialogOptionButtonTemplate"); --self.FrontFrame
|
|
self.ExitButton.HotkeyFrame = CreateFrame("Frame", nil, self.ExitButton, "DUIDialogHotkeyTemplate");
|
|
self.ExitButton:SetOwner(self);
|
|
self.ExitButton:SetButtonExitGossip();
|
|
self.ExitButton:SetButtonWidth(self.halfFrameWidth);
|
|
end
|
|
|
|
self.ExitButton:ResetVisual();
|
|
self.ExitButton:Hide();
|
|
self.ExitButton:Show();
|
|
|
|
KeyboardControl:SetKeyButton("ESCAPE", self.ExitButton);
|
|
|
|
return self.ExitButton
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireOptionButton()
|
|
return self.optionButtonPool:Acquire();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetSelectedGossipIndex(gossipOrderIndex)
|
|
self.selectedGossipIndex = gossipOrderIndex;
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetAcceptCurrentQuest()
|
|
self:SetConsumeGossipClose(false);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FlagPreviousGossipButtons()
|
|
self:HighlightButton(nil);
|
|
|
|
local index = self.selectedGossipIndex;
|
|
|
|
self.optionButtonPool:ProcessActiveObjects(
|
|
function(optionButton)
|
|
if optionButton.type == "gossip" then
|
|
optionButton:FlagAsPreviousGossip(index);
|
|
else
|
|
optionButton:Disable();
|
|
end
|
|
end
|
|
);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireLeftFontString()
|
|
local fs = self:AcquireFontString();
|
|
fs:SetFontObject("DUIFont_Quest_Paragraph");
|
|
fs:SetJustifyV("TOP");
|
|
fs:SetJustifyH("LEFT");
|
|
return fs
|
|
end
|
|
|
|
function DUIDialogBaseMixin:AcquireAndSetSubHeader(text)
|
|
local background = self.textBackgroundPool:Acquire();
|
|
local fs = self:AcquireFontString();
|
|
fs:SetFontObject("DUIFont_Quest_SubHeader");
|
|
fs:SetJustifyV("TOP");
|
|
fs:SetJustifyH("LEFT");
|
|
fs:SetText(text);
|
|
|
|
local width = fs:GetWrappedWidth();
|
|
local paddingH = 8;
|
|
local paddingV = 4;
|
|
|
|
local backgroundWidth = Round(width + 2*paddingH);
|
|
local backgroudHeight = 12 + 2*paddingV;
|
|
background:SetSize(backgroundWidth, backgroudHeight);
|
|
background.size = backgroudHeight + paddingV + TEXT_SPACING;
|
|
|
|
fs:SetPoint("LEFT", background, "LEFT", paddingH, 0);
|
|
|
|
return background
|
|
end
|
|
|
|
function DUIDialogBaseMixin:UseQuestLayout(state)
|
|
local forceUpdate = SETTINGS_UI_VISIBLE == true;
|
|
|
|
if state then
|
|
if (not self.questLayout) or forceUpdate then
|
|
self.questLayout = true;
|
|
local topOffset = (28 + 40) * FRAME_SIZE_MULTIPLIER;
|
|
self.scrollViewHeight = self.scrollFrameBaseHeight - 40 * FRAME_SIZE_MULTIPLIER;
|
|
--self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H, -PADDING_TOP + topOffset);
|
|
self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H * FRAME_SIZE_MULTIPLIER, -topOffset);
|
|
self.FrontFrame.Header:Show();
|
|
self.FrontFrame.HeaderDivider:Hide();
|
|
FriendshipBar:Hide();
|
|
end
|
|
|
|
local unit = UnitExists("npc") and "npc" or "player";
|
|
SetPortraitTexture(self.FrontFrame.Header.Portrait, unit);
|
|
|
|
if ThemeUtil:IsDarkMode() then
|
|
self.FrontFrame.Header.Portrait:SetVertexColor(1, 1, 1);
|
|
else
|
|
self.FrontFrame.Header.Portrait:SetVertexColor(1, 0.9, 0.78);
|
|
end
|
|
|
|
self.keepGossipHistory = false;
|
|
self.hasActiveGossipQuests = false;
|
|
self.activeQuestButtons = {};
|
|
elseif self.questLayout or forceUpdate then
|
|
self.questLayout = nil;
|
|
self.scrollViewHeight = self.scrollFrameBaseHeight;
|
|
--self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H, -PADDING_TOP);
|
|
self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H * FRAME_SIZE_MULTIPLIER, -42);
|
|
self.FrontFrame.Header:Hide();
|
|
self.BackgroundDecor:Hide();
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
function DUIDialogBaseMixin:UpdateQuestTitle()
|
|
local text = GetQuestTitle();
|
|
|
|
local headerFrame = self.FrontFrame.Header;
|
|
local title = headerFrame.Title;
|
|
local subtitle = headerFrame.Subtitle;
|
|
local subtitleFrame = headerFrame.SubtitleMouseOverFrame;
|
|
|
|
subtitle:SetText(nil);
|
|
subtitleFrame:Hide();
|
|
|
|
title:SetFontObject("DUIFont_Quest_Title_18");
|
|
title:SetJustifyV("BOTTOM");
|
|
title:SetJustifyH("LEFT");
|
|
title:SetText(text);
|
|
|
|
local numLines = title:GetNumLines();
|
|
if numLines > 1 then
|
|
title:SetFontObject("DUIFont_Quest_Title_16");
|
|
numLines = title:GetNumLines();
|
|
if numLines > 1 then
|
|
title:SetFontObject("DUIFont_Quest_Paragraph");
|
|
end
|
|
end
|
|
|
|
local questID = GetQuestID();
|
|
local campaignID = C_CampaignInfo and C_CampaignInfo.GetCampaignID(questID);
|
|
|
|
if campaignID and campaignID ~= 0 then
|
|
local campaignInfo = C_CampaignInfo.GetCampaignInfo(campaignID);
|
|
if campaignInfo then
|
|
local questTypeFrame = self.questTypeFramePool:Acquire();
|
|
questTypeFrame:SetPoint("BOTTOMLEFT", title, "TOPLEFT", 0, 0);
|
|
questTypeFrame:SetParent(headerFrame);
|
|
questTypeFrame:SetCampaignNameID(campaignInfo.name, campaignID);
|
|
end
|
|
else
|
|
local questTagID = API.GetQuestTag(questID);
|
|
if questTagID then
|
|
--print("questTagID", questTagID) --debug
|
|
local tagName, tagIcon = API.GetQuestTagNameIcon(questTagID);
|
|
if tagName then
|
|
local questTypeFrame = self.questTypeFramePool:Acquire();
|
|
questTypeFrame:SetPoint("BOTTOMLEFT", title, "TOPLEFT", 0, 0);
|
|
questTypeFrame:SetParent(headerFrame);
|
|
questTypeFrame:SetQuestTagNameAndIcon(tagName, tagIcon);
|
|
end
|
|
end
|
|
end
|
|
|
|
local decor = API.GetQuestBackgroundDecor(questID);
|
|
self.BackgroundDecor:SetTexture(decor);
|
|
self.BackgroundDecor:Show();
|
|
|
|
return 6 * (FRAME_SIZE_MULTIPLIER) --Accounted for Header Size
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ScrollTo(value)
|
|
local f = self.ScrollFrame;
|
|
|
|
value = API.Clamp(value, 0, f.range);
|
|
|
|
if value ~= f.scrollTarget then
|
|
f.scrollTarget = value;
|
|
if not self.questLayout then
|
|
FadeFrame(f.borderTop, 0.25, 1);
|
|
end
|
|
if value < f.range then
|
|
FadeFrame(f.borderBottom, 0.25, 1);
|
|
end
|
|
f:SetScript("OnUpdate", ScrollFrame_Easing);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ScrollBy(offset)
|
|
local f = self.ScrollFrame;
|
|
local value = f.scrollTarget or f:GetVerticalScroll();
|
|
|
|
self:ScrollTo(value + offset);
|
|
|
|
--[[
|
|
if offset > 0 and value < f.range then
|
|
anyChange = true;
|
|
value = value + offset;
|
|
if value > f.range then
|
|
value = f.range;
|
|
end
|
|
elseif offset < 0 and value > 0 then
|
|
anyChange = true;
|
|
value = value + offset;
|
|
if value < 0 then
|
|
value = 0;
|
|
end
|
|
end
|
|
|
|
if anyChange then
|
|
f.scrollTarget = value;
|
|
if not self.questLayout then
|
|
FadeFrame(f.borderTop, 0.25, 1);
|
|
end
|
|
if value < f.range then
|
|
FadeFrame(f.borderBottom, 0.25, 1);
|
|
end
|
|
f:SetScript("OnUpdate", ScrollFrame_Easing);
|
|
end
|
|
--]]
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ScrollToBottom()
|
|
self:ScrollBy(self.ScrollFrame.range);
|
|
FadeFrame(self.ScrollFrame.borderBottom, 0, 0);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:IsScrollAtBottom()
|
|
if not self:IsScrollable() then
|
|
return true
|
|
end
|
|
|
|
local current = self.ScrollFrame.scrollTarget or self.ScrollFrame.value;
|
|
local range = self.ScrollFrame.range;
|
|
return current + 0.5 > range;
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ResetScroll()
|
|
self.ScrollFrame:SetScript("OnUpdate", nil);
|
|
self.ScrollFrame:SetHorizontalScroll(0);
|
|
self.ScrollFrame:SetVerticalScroll(0);
|
|
self.ScrollFrame.value = 0;
|
|
self.ScrollFrame.scrollTarget = 0;
|
|
FadeFrame(self.ScrollFrame.borderTop, 0, 0);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetScrollable(scrollable)
|
|
--Using ClipFrame (clipChildren or ScrollChild) breaks pixel-perfect
|
|
--Setting parent to ScrollChild dynamically, so we can still have good looking stroke
|
|
--Animation: ContentFrame has childChildren = true during unscroll animation
|
|
|
|
local forceUpdate = SETTINGS_UI_VISIBLE == true;
|
|
|
|
if scrollable and ((not self.ContentFrame.scrollable) or forceUpdate) then
|
|
self.ContentFrame.scrollable = true;
|
|
self.ContentFrame:ClearAllPoints();
|
|
self.ContentFrame:SetParent(self.ScrollFrame.ScrollChild);
|
|
self.ContentFrame:SetPoint("TOPLEFT", self.ScrollFrame.ScrollChild, "TOPLEFT", 0, 0);
|
|
self.FrontFrame.FooterDivider:Show();
|
|
|
|
elseif (not scrollable) and (self.ContentFrame.scrollable or forceUpdate) then
|
|
self.ContentFrame.scrollable = false;
|
|
self.ContentFrame:ClearAllPoints();
|
|
self.ContentFrame:SetParent(self);
|
|
self.ContentFrame:SetPoint("TOPLEFT", self.ScrollFrame, "TOPLEFT", 0, 0);
|
|
self.ContentFrame:SetPoint("BOTTOMRIGHT", self.ScrollFrame, "BOTTOMRIGHT", 0, 0);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:IsScrollable()
|
|
return self.ContentFrame.scrollable == true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetScrollRange(contentHeight)
|
|
self.contentHeight = contentHeight;
|
|
|
|
local scrollViewHeight = self.scrollViewHeight; --self.ScrollFrame:GetHeight(); --affected by intro animation!
|
|
local range = contentHeight - scrollViewHeight + PARAGRAPH_SPACING;
|
|
local scrollable;
|
|
|
|
if range > 0 then
|
|
scrollable = true;
|
|
|
|
if range < 12 then
|
|
range = 12;
|
|
end
|
|
|
|
range = range + 36;
|
|
|
|
self.ScrollFrame.range = Round(range);
|
|
self.FrontFrame.FooterDivider:Show();
|
|
self.FrontFrame.FooterDivider:SetAlpha(1);
|
|
else
|
|
scrollable = false;
|
|
self.ScrollFrame.range = 0;
|
|
self.FrontFrame.FooterDivider:Hide();
|
|
self.FrontFrame.HeaderDivider:Hide();
|
|
end
|
|
|
|
self:SetScrollable(scrollable);
|
|
end
|
|
|
|
|
|
local function SortFunc_GossipOrder(a, b)
|
|
return a.orderIndex < b.orderIndex;
|
|
end
|
|
|
|
local GOSSIP_QUEST_LABEL = L["Gossip Quest Option Prepend"] or "(Quest)";
|
|
|
|
local function SortFunc_GossipPrioritizeQuest(a, b)
|
|
if a.flags and b.flags and (a.flags ~= b.flags) then
|
|
return a.flags > b.flags
|
|
end
|
|
|
|
local isQuestA = find(a.name, GOSSIP_QUEST_LABEL);
|
|
local isQuestB = find(b.name, GOSSIP_QUEST_LABEL);
|
|
|
|
if isQuestA ~= nil and isQuestB == nil then
|
|
return true
|
|
elseif isQuestA == nil and isQuestB ~= nil then
|
|
return false
|
|
end
|
|
|
|
return a.orderIndex < b.orderIndex;
|
|
end
|
|
|
|
local function SortFunc_PrioritizeCompleteQuest(a, b)
|
|
if a.isComplete ~= b.isComplete then
|
|
return a.isComplete
|
|
elseif a.isAvailableQuest ~= b.isAvailableQuest then
|
|
return a.isAvailableQuest
|
|
else
|
|
return a.originalOrder < b.originalOrder
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FadeInContentFrame()
|
|
if self:IsShown() and not SETTINGS_UI_VISIBLE then
|
|
FadeFrame(self.ContentFrame, 0.35, 1, 0);
|
|
PlaySound("SOUNDKIT.IG_QUEST_LIST_OPEN");
|
|
else
|
|
self.ContentFrame:SetAlpha(1);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:InsertText(offsetY, text)
|
|
--Add no spacing
|
|
local fs = self:AcquireLeftFontString();
|
|
fs:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
fs:SetPoint("RIGHT", self.ContentFrame, "RIGHT", 0, 0);
|
|
fs:SetText(text);
|
|
offsetY = Round(offsetY + fs:GetHeight());
|
|
return offsetY
|
|
end
|
|
|
|
function DUIDialogBaseMixin:InsertParagraph(offsetY, paragraphText)
|
|
--Add paragrah spacing
|
|
return self:InsertText(offsetY + PARAGRAPH_SPACING, paragraphText);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FormatParagraph(offsetY, text)
|
|
local paragraphs = API.SplitParagraph(text);
|
|
local firstObject, lastObject;
|
|
|
|
for i, paragraphText in ipairs(paragraphs) do
|
|
local fs = self:AcquireLeftFontString();
|
|
if not firstObject then
|
|
firstObject = fs;
|
|
end
|
|
fs:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
fs:SetPoint("RIGHT", self.ContentFrame, "RIGHT", 0, 0);
|
|
fs:SetText(paragraphText);
|
|
offsetY = Round(offsetY + fs:GetHeight() + PARAGRAPH_SPACING);
|
|
lastObject = fs;
|
|
end
|
|
|
|
offsetY = offsetY - PARAGRAPH_SPACING;
|
|
|
|
return offsetY, firstObject, lastObject
|
|
end
|
|
|
|
local function ConcatenateNPCName(text)
|
|
if SHOW_NPC_NAME and UnitExists("npc") then
|
|
local name = UnitName("npc");
|
|
if text and name and name ~= "" then
|
|
return name..": "..text
|
|
end
|
|
end
|
|
|
|
return text
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleInitialLoadingComplete()
|
|
if self.deferredEvent then
|
|
self:ShowUI(self.deferredEvent);
|
|
self.deferredEvent = nil;
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleGossip()
|
|
local availableQuests = GetAvailableQuests();
|
|
local activeQuests = GetActiveQuests();
|
|
|
|
local options = GetOptions();
|
|
tsort(options, SortFunc_GossipPrioritizeQuest);
|
|
|
|
local anyActiveQuest = activeQuests and #activeQuests > 0;
|
|
local anyAvailableQuest = availableQuests and #availableQuests > 0;
|
|
local anyQuest = anyActiveQuest or anyAvailableQuest;
|
|
local anyOption = options and #options > 0;
|
|
|
|
self.hasActiveGossipQuests = anyActiveQuest;
|
|
self.numAvailableQuests = availableQuests and #availableQuests or 0;
|
|
|
|
if (not(anyQuest or anyOption)) and NameplateGossip:ShouldUseNameplate() then
|
|
--debug
|
|
local success = addon.NameplateGossip:RequestDisplayGossip();
|
|
if success then
|
|
self.keepGossipHistory = false;
|
|
return false
|
|
end
|
|
end
|
|
|
|
if (not ALWAYS_GOSSIP) and (not anyQuest) and (#options == 1) and (not ForceGossip()) then
|
|
if options[1].selectOptionWhenOnlyOption then
|
|
C_GossipInfo.SelectOptionByIndex(options[1].orderIndex);
|
|
return false
|
|
end
|
|
|
|
if AUTO_SELECT_GOSSIP and IsAutoSelectOption(options[1].gossipOptionID, true) then
|
|
C_GossipInfo.SelectOption(options[1].gossipOptionID);
|
|
API.PrintMessage(L["Auto Select"], options[1].name);
|
|
return false
|
|
end
|
|
end
|
|
|
|
if AUTO_SELECT_GOSSIP then
|
|
for i, data in ipairs(options) do
|
|
if IsAutoSelectOption(data.gossipOptionID) then
|
|
C_GossipInfo.SelectOption(data.gossipOptionID);
|
|
API.PrintMessage(L["Auto Select"], data.name);
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
local fromOffsetY = 0;
|
|
local hasPreviousGossip = false;
|
|
|
|
if self.questLayout or (not self.keepGossipHistory) then
|
|
self:ReleaseAllObjects();
|
|
else
|
|
self:ResetGamePadObjects();
|
|
KeyboardControl:ResetKeyActions();
|
|
fromOffsetY = self.contentHeight or fromOffsetY;
|
|
if fromOffsetY > 0 then
|
|
--Has previous gossip history
|
|
hasPreviousGossip = true;
|
|
fromOffsetY = fromOffsetY + PADDING_TOP;
|
|
self:FlagPreviousGossipButtons();
|
|
end
|
|
|
|
if fromOffsetY >= 5000 then
|
|
--Clear previous history
|
|
fromOffsetY = 0;
|
|
hasPreviousGossip = false;
|
|
self:ReleaseAllObjects();
|
|
end
|
|
end
|
|
|
|
local offsetY = fromOffsetY;
|
|
|
|
self:UseQuestLayout(false);
|
|
|
|
local firstObject, lastObject;
|
|
local button;
|
|
|
|
--Welcome text
|
|
local gossipText = ConcatenateNPCName(GetGossipText());
|
|
offsetY, firstObject, lastObject = self:FormatParagraph(offsetY, gossipText);
|
|
|
|
|
|
local hotkeyIndex = 0;
|
|
local hotkey;
|
|
|
|
local showGossipFirst = options[1] and options[1].flags == 1;
|
|
|
|
if showGossipFirst then
|
|
--Show gossip first if there is a (Quest) Gossip
|
|
for i, data in ipairs(options) do
|
|
hotkeyIndex = hotkeyIndex + 1;
|
|
button = self:AcquireOptionButton();
|
|
hotkey = KeyboardControl:SetKeyButton(hotkeyIndex, button);
|
|
button:SetGossip(data, hotkey);
|
|
|
|
if i == 1 then
|
|
local spacing = -PARAGRAPH_SPACING;
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, spacing);
|
|
else
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, 0);
|
|
end
|
|
|
|
lastObject = button;
|
|
|
|
self:IndexGamePadObject(button);
|
|
end
|
|
end
|
|
|
|
|
|
--Quest
|
|
local questIndex = 0;
|
|
local quests = {};
|
|
self.activeQuestButtons = {};
|
|
|
|
for i, questInfo in ipairs(availableQuests) do
|
|
questIndex = questIndex + 1;
|
|
questInfo.isOnQuest = false;
|
|
questInfo.isAvailableQuest = true;
|
|
questInfo.originalOrder = questIndex;
|
|
questInfo.index = i;
|
|
quests[questIndex] = questInfo;
|
|
end
|
|
|
|
for i, questInfo in ipairs(activeQuests) do
|
|
questIndex = questIndex + 1;
|
|
questInfo.isOnQuest = true; --there is a delay between C_Gossip and C_QuestLog.IsOnQuest
|
|
questInfo.isAvailableQuest = false;
|
|
questInfo.originalOrder = questIndex;
|
|
questInfo.index = i;
|
|
quests[questIndex] = questInfo;
|
|
end
|
|
|
|
tsort(quests, SortFunc_PrioritizeCompleteQuest);
|
|
|
|
local lastQuestComplete, lastQuestAvailable;
|
|
|
|
for i, questInfo in ipairs(quests) do
|
|
hotkeyIndex = hotkeyIndex + 1;
|
|
button = self:AcquireOptionButton();
|
|
hotkey = KeyboardControl:SetKeyButton(hotkeyIndex, button);
|
|
|
|
if questInfo.isAvailableQuest then
|
|
button:SetAvailableQuest(questInfo, questInfo.index, hotkey);
|
|
else
|
|
button:SetActiveQuest(questInfo, questInfo.index, hotkey);
|
|
tinsert(self.activeQuestButtons, button);
|
|
end
|
|
|
|
if i == 1 or (questInfo.isAvailableQuest ~= lastQuestAvailable) or (questInfo.isComplete ~= lastQuestComplete) then
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, -PARAGRAPH_BUTTON_SPACING);
|
|
lastQuestAvailable = questInfo.isAvailableQuest;
|
|
lastQuestComplete = questInfo.isComplete;
|
|
else
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, -1);
|
|
end
|
|
|
|
lastObject = button;
|
|
|
|
self:IndexGamePadObject(button);
|
|
end
|
|
|
|
|
|
--Options
|
|
if not showGossipFirst then
|
|
for i, data in ipairs(options) do
|
|
hotkeyIndex = hotkeyIndex + 1;
|
|
button = self:AcquireOptionButton();
|
|
hotkey = KeyboardControl:SetKeyButton(hotkeyIndex, button);
|
|
button:SetGossip(data, hotkey);
|
|
|
|
if i == 1 then
|
|
local spacing = (anyQuest and -PARAGRAPH_BUTTON_SPACING) or -PARAGRAPH_SPACING;
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, spacing);
|
|
else
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, 0);
|
|
end
|
|
|
|
lastObject = button;
|
|
|
|
self:IndexGamePadObject(button);
|
|
end
|
|
end
|
|
|
|
|
|
self.AcceptButton:Hide();
|
|
local GoodbyeButton = self:AcquireExitButton();
|
|
GoodbyeButton:SetButtonExitGossip();
|
|
|
|
if not (#options > 0 or anyQuest) then
|
|
--If there is no options, allow pressing SPACE to goodbye
|
|
KeyboardControl:SetKeyButton("PRIMARY", GoodbyeButton);
|
|
end
|
|
|
|
local objectHeight = firstObject:GetTop() - lastObject:GetBottom();
|
|
local contentHeight = fromOffsetY + objectHeight; --self.ContentFrame:GetTop()
|
|
contentHeight = contentHeight + (hasPreviousGossip and PARAGRAPH_SPACING or 0); --Compensate for the top divider
|
|
self:SetScrollRange(contentHeight);
|
|
|
|
if hasPreviousGossip then
|
|
local scrollRangeDiff = objectHeight - self.scrollViewHeight;
|
|
local extraScroll = 0;
|
|
if scrollRangeDiff > 0 then
|
|
extraScroll = scrollRangeDiff + 2*PARAGRAPH_SPACING;
|
|
end
|
|
local actualRange = Round(fromOffsetY - PARAGRAPH_SPACING + extraScroll);
|
|
self.ScrollFrame.range = actualRange;
|
|
self:SetScrollable(true);
|
|
|
|
FadeFrame(self.ContentFrame, 0.35, 1, 0);
|
|
|
|
if extraScroll == 0 then
|
|
self:ScrollToBottom();
|
|
else
|
|
self:ScrollTo(fromOffsetY - PARAGRAPH_SPACING);
|
|
end
|
|
else
|
|
self:FadeInContentFrame();
|
|
end
|
|
|
|
FriendshipBar:RequestUpdate();
|
|
|
|
return true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleQuestDetail()
|
|
self:ReleaseAllObjects();
|
|
self:UseQuestLayout(true);
|
|
|
|
local fs, text;
|
|
|
|
--Title
|
|
local offsetY = self:UpdateQuestTitle();
|
|
|
|
--Detail
|
|
text = ConcatenateNPCName(GetQuestText("Detail"));
|
|
if text then
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
offsetY = self:FormatParagraph(offsetY, text);
|
|
end
|
|
|
|
--Objectives
|
|
local objectiveText = GetObjectiveText();
|
|
if objectiveText then
|
|
--Subtitle: Quest Objectives
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader(L["Quest Objectives"]);
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
|
|
--Objective Texts
|
|
offsetY = self:FormatParagraph(offsetY, objectiveText);
|
|
|
|
local groupNum = GetSuggestedGroupSize();
|
|
if groupNum and groupNum > 0 then
|
|
local groupText = L["Format Suggested Players"]:format(groupNum);
|
|
offsetY = self:InsertParagraph(offsetY, groupText);
|
|
end
|
|
end
|
|
|
|
--Model
|
|
local portraitDisplayID, questPortraitText, questPortraitName, mountPortraitDisplayID, portraitModelSceneID = GetQuestPortraitGiver();
|
|
if portraitDisplayID then
|
|
if portraitDisplayID == -1 then
|
|
--player
|
|
|
|
elseif portraitDisplayID > 0 then
|
|
|
|
end
|
|
|
|
if questPortraitText and questPortraitText ~= "" and questPortraitText ~= objectiveText then
|
|
offsetY = self:InsertParagraph(offsetY, questPortraitText);
|
|
end
|
|
end
|
|
|
|
--Rewards
|
|
local rewardList;
|
|
rewardList, self.chooseItems = addon.BuildRewardList();
|
|
|
|
if rewardList and #rewardList > 0 then
|
|
self:RegisterEvent("QUEST_ITEM_UPDATE");
|
|
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader( (#rewardList == 1 and L["Reward"]) or L["Rewards"] );
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
|
|
offsetY = self:FormatRewards(offsetY, rewardList);
|
|
end
|
|
|
|
self:SetScrollRange(offsetY);
|
|
|
|
local AcceptButton = self:AcquireAcceptButton(true);
|
|
local ExitButton = self:AcquireExitButton();
|
|
|
|
if API.IsQuestAutoAccepted() then
|
|
AcceptButton:SetButtonAlreadyOnQuest();
|
|
ExitButton:SetButtonCloseAutoAcceptQuest();
|
|
self.acknowledgeAutoAcceptQuest = true;
|
|
else
|
|
AcceptButton:SetButtonAcceptQuest();
|
|
ExitButton:SetButtonDeclineQuest(self.questIsFromGossip);
|
|
end
|
|
|
|
self.questIsFromGossip = nil;
|
|
|
|
self:FadeInContentFrame();
|
|
|
|
return true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleQuestAccepted(questID)
|
|
--QUEST_ACCEPTED
|
|
if self.handler == "HandleQuestDetail" then
|
|
local currentQuestID = GetQuestID();
|
|
if currentQuestID and currentQuestID ~= 0 and currentQuestID == questID then
|
|
local AcceptButton = self:AcquireAcceptButton(true);
|
|
local ExitButton = self:AcquireExitButton();
|
|
AcceptButton:SetButtonAlreadyOnQuest();
|
|
ExitButton:SetButtonCloseAutoAcceptQuest();
|
|
|
|
--local title = C_QuestLog.GetTitleForQuestID(questID);
|
|
--print(questID, title)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CalulateLockDuration(rawCopper)
|
|
if (not rawCopper) or (rawCopper <= 0) then
|
|
return 1
|
|
end
|
|
|
|
local playerMoney = GetMoney();
|
|
if playerMoney <= 0 then
|
|
playerMoney = 1
|
|
end
|
|
|
|
if (rawCopper > 5000000) or (rawCopper/playerMoney) > 0.05 then --500G or 5% of max money
|
|
return 4
|
|
else
|
|
return 1
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleQuestProgress()
|
|
self:ReleaseAllObjects();
|
|
self:UseQuestLayout(true);
|
|
|
|
--Title
|
|
local offsetY = self:UpdateQuestTitle();
|
|
|
|
--Progress
|
|
local text = ConcatenateNPCName(GetQuestText("Progress"));
|
|
if text then
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
offsetY = self:FormatParagraph(offsetY, text);
|
|
end
|
|
|
|
--Required Items
|
|
local numRequiredItems = GetNumQuestItems();
|
|
local numRequiredCurrencies = GetNumQuestCurrencies();
|
|
local numRequiredMoney = GetQuestMoneyToGet();
|
|
local lockDuration; --Lock "Continue" if the quest costs gold
|
|
|
|
if numRequiredItems > 0 or numRequiredMoney > 0 or numRequiredCurrencies > 0 then
|
|
|
|
-- If there's money required then anchor and display it
|
|
if numRequiredMoney > 0 then
|
|
lockDuration = CalulateLockDuration(numRequiredMoney);
|
|
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader(L["Costs"]);
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
|
|
local itemList = {
|
|
{"SetRequiredMoney", numRequiredMoney, small = true}
|
|
};
|
|
|
|
offsetY = self:FormatRewards(offsetY, itemList);
|
|
end
|
|
|
|
local itemList = {};
|
|
|
|
local actualNumRequiredItems = 0;
|
|
for index = 1, numRequiredItems do
|
|
local hidden = IsQuestItemHidden(index);
|
|
if hidden == 0 then
|
|
table.insert(itemList, {"SetRequiredItem", index});
|
|
actualNumRequiredItems = actualNumRequiredItems + 1;
|
|
end
|
|
end
|
|
|
|
-- Show the "Required Items" text if needed.
|
|
local anyActualItems = (actualNumRequiredItems + numRequiredCurrencies > 0);
|
|
|
|
if anyActualItems then
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader(L["Requirements"]);
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
end
|
|
|
|
for index = 1, numRequiredCurrencies do
|
|
table.insert(itemList, {"SetRequiredCurrency", index});
|
|
end
|
|
|
|
offsetY = self:FormatRewards(offsetY, itemList);
|
|
end
|
|
|
|
local canComplete = IsQuestCompletable();
|
|
local ContinueButton = self:AcquireAcceptButton(canComplete);
|
|
ContinueButton:SetButtonContinueQuest(canComplete, lockDuration);
|
|
|
|
local CancelButton = self:AcquireExitButton();
|
|
CancelButton:SetButtonCancelQuestProgress(self.questIsFromGossip);
|
|
self.questIsFromGossip = nil;
|
|
|
|
if not canComplete then
|
|
KeyboardControl:SetKeyButton("PRIMARY", CancelButton);
|
|
end
|
|
|
|
self:SetScrollRange(offsetY);
|
|
|
|
self:FadeInContentFrame();
|
|
|
|
return true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:IsRewardChosen()
|
|
local numRewardChoices = GetNumQuestChoices() or 0;
|
|
local choiceID = self.rewardChoiceID;
|
|
return numRewardChoices <= 1 or (choiceID ~= nil);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleQuestComplete()
|
|
self:ReleaseAllObjects();
|
|
self:UseQuestLayout(true);
|
|
|
|
--Title
|
|
local offsetY = self:UpdateQuestTitle();
|
|
|
|
--Progress
|
|
local text = ConcatenateNPCName(GetQuestText("Complete"));
|
|
if text then
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
offsetY = self:FormatParagraph(offsetY, text);
|
|
end
|
|
|
|
--Rewards
|
|
self.rewardChoiceID = nil;
|
|
|
|
local questComplete = true;
|
|
local rewardList;
|
|
rewardList, self.chooseItems = addon.BuildRewardList(questComplete);
|
|
|
|
if rewardList and #rewardList > 0 then
|
|
self:RegisterEvent("QUEST_ITEM_UPDATE");
|
|
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader( (#rewardList == 1 and L["Reward"]) or L["Rewards"] );
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
|
|
offsetY = self:FormatRewards(offsetY, rewardList);
|
|
end
|
|
|
|
local CompleteButton = self:AcquireAcceptButton(true);
|
|
CompleteButton:SetButtonCompleteQuest();
|
|
|
|
local CancelButton = self:AcquireExitButton();
|
|
CancelButton:SetButtonCancelQuestProgress();
|
|
|
|
self:SetScrollRange(offsetY);
|
|
|
|
self:FadeInContentFrame();
|
|
|
|
return true
|
|
end
|
|
|
|
local function SortFunc_QuestGreetingActiveQuests(a, b)
|
|
if a.isComplete == b.isComplete then
|
|
return a.index < b.index
|
|
else
|
|
return a.isComplete
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleQuestGreeting()
|
|
self:ReleaseAllObjects();
|
|
self:UseQuestLayout(false);
|
|
|
|
local offsetY = 0;
|
|
local firstObject, lastObject;
|
|
|
|
--local material = QuestFrame_GetMaterial();
|
|
|
|
local geetingText = ConcatenateNPCName(GetQuestText("Greeting"));
|
|
offsetY, firstObject, lastObject = self:FormatParagraph(offsetY, geetingText);
|
|
|
|
|
|
local questIndex = 0;
|
|
local quests = {};
|
|
self.activeQuestButtons = {};
|
|
|
|
local numAvailableQuests = GetNumAvailableQuests();
|
|
|
|
for i = 1, numAvailableQuests do
|
|
questIndex = questIndex + 1;
|
|
|
|
local title = GetAvailableTitle(i);
|
|
local isTrivial, frequency, isRepeatable, isLegendary, questID = GetAvailableQuestInfo(i);
|
|
|
|
local questInfo = {
|
|
index = i,
|
|
title = title,
|
|
questID = questID,
|
|
isOnQuest = false,
|
|
isTrivial = isTrivial,
|
|
frequency = frequency,
|
|
repeatable = isRepeatable,
|
|
isLegendary = isLegendary,
|
|
isAvailableQuest = true,
|
|
originalOrder = questIndex;
|
|
--isImportant
|
|
};
|
|
|
|
quests[questIndex] = questInfo;
|
|
end
|
|
|
|
|
|
local numActiveQuests = GetNumActiveQuests();
|
|
|
|
for i = 1, numActiveQuests do
|
|
questIndex = questIndex + 1;
|
|
|
|
local title, isComplete = GetActiveTitle(i);
|
|
local questID = GetActiveQuestID(i);
|
|
|
|
local questInfo = {
|
|
index = i,
|
|
title = title,
|
|
isComplete = isComplete,
|
|
questID = questID,
|
|
isAvailableQuest = false,
|
|
isOnQuest = true,
|
|
originalOrder = questIndex,
|
|
};
|
|
|
|
quests[questIndex] = questInfo;
|
|
end
|
|
|
|
tsort(quests, SortFunc_PrioritizeCompleteQuest);
|
|
|
|
|
|
local lastQuestComplete, lastQuestAvailable;
|
|
local hotkeyIndex = 0;
|
|
local hotkey;
|
|
local button;
|
|
|
|
for i, questInfo in ipairs(quests) do
|
|
hotkeyIndex = hotkeyIndex + 1;
|
|
button = self:AcquireOptionButton();
|
|
hotkey = KeyboardControl:SetKeyButton(hotkeyIndex, button);
|
|
|
|
if questInfo.isAvailableQuest then
|
|
button:SetGreetingAvailableQuest(questInfo, questInfo.index, hotkey);
|
|
else
|
|
button:SetGreetingActiveQuest(questInfo, questInfo.index, hotkey);
|
|
tinsert(self.activeQuestButtons, button);
|
|
end
|
|
|
|
if i == 1 or (questInfo.isAvailableQuest ~= lastQuestAvailable) or (questInfo.isComplete ~= lastQuestComplete) then
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, -PARAGRAPH_BUTTON_SPACING);
|
|
lastQuestAvailable = questInfo.isAvailableQuest;
|
|
lastQuestComplete = questInfo.isComplete;
|
|
else
|
|
button:SetPoint("TOPLEFT", lastObject, "BOTTOMLEFT", 0, -1);
|
|
end
|
|
|
|
lastObject = button;
|
|
|
|
self:IndexGamePadObject(button);
|
|
end
|
|
|
|
|
|
self.AcceptButton:Hide();
|
|
local GoodbyeButton = self:AcquireExitButton();
|
|
GoodbyeButton:SetButtonExitGossip();
|
|
|
|
local contentHeight = firstObject:GetTop() - lastObject:GetBottom();
|
|
self:SetScrollRange(contentHeight);
|
|
|
|
self.numAvailableQuests = numAvailableQuests;
|
|
|
|
return true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:GetQuestFinishedDelay()
|
|
if (self.numAvailableQuests and self.numAvailableQuests > 1) or QuestIsFromAreaTrigger() then
|
|
return 0.5
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:UpdateGossipQuests()
|
|
if self.activeQuestButtons then
|
|
local activeQuests = GetActiveQuests();
|
|
|
|
for i, questInfo in ipairs(activeQuests) do
|
|
questInfo.isOnQuest = true;
|
|
questInfo.originalOrder = i;
|
|
end
|
|
|
|
tsort(activeQuests, SortFunc_PrioritizeCompleteQuest);
|
|
|
|
for i, activeQuestButton in ipairs(self.activeQuestButtons) do
|
|
if activeQuests[i] and (activeQuestButton.questID == activeQuests[i].questID) then
|
|
activeQuestButton:SetQuestVisual(activeQuests[i]);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleGossipConfirm(gossipID, warningText, cost)
|
|
self.hasActiveGossipQuests = false;
|
|
self.numAvailableQuests = 0;
|
|
self.keepGossipHistory = false;
|
|
self.requireGossipConfirm = true;
|
|
|
|
self:ReleaseAllObjects();
|
|
self:UseQuestLayout(false);
|
|
|
|
local offsetY = 0;
|
|
|
|
warningText = ThemeUtil:AdjustTextColor(warningText);
|
|
offsetY = self:FormatParagraph(offsetY, warningText);
|
|
|
|
local lockDuration = CalulateLockDuration(cost);
|
|
|
|
if cost and cost > 0 then
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
local subheader = self:AcquireAndSetSubHeader(L["Costs"]);
|
|
subheader:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", 0, -offsetY);
|
|
offsetY = Round(offsetY + subheader.size);
|
|
|
|
local itemList = {
|
|
{"SetRequiredMoney", cost, small = true}
|
|
};
|
|
|
|
offsetY = self:FormatRewards(offsetY, itemList);
|
|
end
|
|
|
|
local AcceptButton = self:AcquireAcceptButton(true);
|
|
AcceptButton:SetButtonConfirmGossip(gossipID, lockDuration);
|
|
|
|
local CancelButton = self:AcquireExitButton();
|
|
CancelButton:SetButtonCancelConfirmGossip();
|
|
|
|
self:SetScrollRange(offsetY);
|
|
|
|
FadeFrame(self.ContentFrame, 0.35, 1, 0);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HideGossipConfirm()
|
|
if self:IsShown() and self.requireGossipConfirm and self.handler == "HandleGossip" then
|
|
self.requireGossipConfirm = false;
|
|
self.keepGossipHistory = false;
|
|
if API.IsInteractingWithGossip() then
|
|
self:HandleGossip();
|
|
FadeFrame(self.ContentFrame, 0.35, 1, 0);
|
|
end
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HandleGossipEnterCode(gossipID)
|
|
self.inputboxShown = true;
|
|
self.InputBox:Show();
|
|
self.InputBox:SetGossipID(gossipID);
|
|
self.InputBox:SetFocus();
|
|
FadeFrame(self.ContentFrame, 0.15, 0.25);
|
|
FadeFrame(self.FrontFrame, 0.15, 0.25);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HideInputBox()
|
|
if self.inputboxShown then
|
|
self.InputBox:Hide();
|
|
FadeFrame(self.ContentFrame, 0.15, 1);
|
|
FadeFrame(self.FrontFrame, 0.15, 1);
|
|
end
|
|
end
|
|
|
|
local function Predicate_ActiveChoiceButton(itemButton)
|
|
return itemButton.type == "choice" and itemButton:IsShown()
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SelectRewardChoice(choiceID)
|
|
if not self.chooseItems then return end; --Handled in Formatter when building reward choices
|
|
|
|
local claimQuestReward;
|
|
if INPUT_DEVICE_GAME_PAD then
|
|
self.GamePadFocusIndicator:Hide();
|
|
if choiceID == self.rewardChoiceID then
|
|
claimQuestReward = true;
|
|
end
|
|
end
|
|
|
|
self.rewardChoiceID = choiceID;
|
|
local CompleteButton = self:AcquireAcceptButton(true);
|
|
CompleteButton:SetButtonCompleteQuest();
|
|
|
|
if claimQuestReward and CompleteButton:IsEnabled() then
|
|
CompleteButton:Click("LeftButton");
|
|
end
|
|
|
|
local buttons = self.itemButtonPool:GetObjectsByPredicate(Predicate_ActiveChoiceButton);
|
|
for i, button in ipairs(buttons) do
|
|
if button.index == choiceID then
|
|
button:SetBackgroundTexture(1);
|
|
FadeFrame(button, 0.15, 1);
|
|
else
|
|
button:SetBackgroundTexture(1);
|
|
FadeFrame(button, 0.15, 0.25);
|
|
end
|
|
button:UpdateNameColor();
|
|
end
|
|
self.RewardSelection.BackTexture:Hide();
|
|
|
|
return true
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HighlightRewardChoice(rewardChoiceButton)
|
|
self.RewardSelection:Hide();
|
|
self.RewardSelection:ClearAllPoints();
|
|
self.GamePadFocusIndicator:Hide();
|
|
|
|
if rewardChoiceButton and self.chooseItems then
|
|
self.RewardSelection:SetPoint("TOPLEFT", rewardChoiceButton, "TOPLEFT", 0, 0);
|
|
self.RewardSelection:SetPoint("BOTTOMRIGHT", rewardChoiceButton, "BOTTOMRIGHT", 0, 0);
|
|
self.RewardSelection:SetParent(rewardChoiceButton);
|
|
self.RewardSelection:SetFrameLevel(rewardChoiceButton:GetFrameLevel());
|
|
self.RewardSelection.BackTexture:SetShown(self.rewardChoiceID == nil);
|
|
self.RewardSelection:Show();
|
|
|
|
self.GamePadFocusIndicator:ClearAllPoints();
|
|
self.GamePadFocusIndicator:SetPoint("CENTER", self.RewardSelection, "LEFT", 0, 0);
|
|
|
|
if INPUT_DEVICE_GAME_PAD then
|
|
self:UpdateCompleteButton(rewardChoiceButton.index == self.rewardChoiceID);
|
|
end
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FlashRewardChoices()
|
|
local buttons = self.itemButtonPool:GetObjectsByPredicate(Predicate_ActiveChoiceButton);
|
|
if buttons then
|
|
for i, button in ipairs(buttons) do
|
|
button:PlaySheen();
|
|
end
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:RequestSellPrice(isRequery)
|
|
if not MARK_HIGHEST_SELL_PRICE then return end;
|
|
|
|
local numRewardChoices = GetNumQuestChoices() or 0;
|
|
if numRewardChoices <= 1 then return end;
|
|
|
|
local maxPrice = 0;
|
|
local price, index;
|
|
local anyZero;
|
|
|
|
for i = 1, numRewardChoices do
|
|
price = API.GetQuestChoiceSellPrice(i);
|
|
|
|
if price == 0 then
|
|
anyZero = true;
|
|
end
|
|
|
|
if price > maxPrice then
|
|
maxPrice = price;
|
|
index = i;
|
|
end
|
|
end
|
|
|
|
if (index and anyZero) or (not index) then
|
|
if not isRequery then
|
|
After(0.8, function()
|
|
self:RequestSellPrice(true);
|
|
end);
|
|
end
|
|
else
|
|
local buttons = self.itemButtonPool:GetObjectsByPredicate(Predicate_ActiveChoiceButton);
|
|
if buttons then
|
|
for i, button in ipairs(buttons) do
|
|
if button.index == index then
|
|
local iconFrame = self.iconFramePool:Acquire();
|
|
iconFrame:SetHighestSellPrice();
|
|
iconFrame:SetParent(button);
|
|
iconFrame:SetPoint("CENTER", button.Icon, "TOPLEFT", 3, -3);
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local ANIM_DURATION_SCROLL_EXPAND = 0.75;
|
|
|
|
local function AnimIntro_SimpleFadeIn_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
local height = self.frameHeight;
|
|
local alpha = 5*self.t;
|
|
|
|
if alpha >= 1 then
|
|
alpha = 1;
|
|
self:SetScript("OnUpdate", nil);
|
|
self.ContentFrame:SetClipsChildren(false);
|
|
end
|
|
|
|
self:SetHeight(height);
|
|
self:SetAlpha(alpha);
|
|
end
|
|
|
|
local function AnimIntro_Unfold_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
local height = Esaing_OutSine(self.t, self.fromHeight, self.frameHeight, ANIM_DURATION_SCROLL_EXPAND);
|
|
local alpha = 4*self.t;
|
|
|
|
if alpha > 1 then
|
|
alpha = 1;
|
|
end
|
|
|
|
if self.t >= ANIM_DURATION_SCROLL_EXPAND then
|
|
height = self.frameHeight;
|
|
self:SetScript("OnUpdate", nil);
|
|
self.ContentFrame:SetClipsChildren(false);
|
|
end
|
|
|
|
self:SetHeight(height);
|
|
self:SetAlpha(alpha);
|
|
end
|
|
|
|
local function AnimIntro_FlyInRight_OnUpdate(self, elapsed)
|
|
self.t = self.t + elapsed;
|
|
local offsetX = Esaing_OutSine(self.t, self.fromOffsetX, self.frameOffsetX, ANIM_DURATION_SCROLL_EXPAND);
|
|
local alpha = 4*self.t;
|
|
local height = self.frameHeight;
|
|
|
|
if alpha > 1 then
|
|
alpha = 1;
|
|
end
|
|
|
|
if self.t >= ANIM_DURATION_SCROLL_EXPAND then
|
|
offsetX = self.frameOffsetX;
|
|
self:SetScript("OnUpdate", nil);
|
|
self.ContentFrame:SetClipsChildren(false);
|
|
end
|
|
|
|
self:SetPoint("CENTER", nil, "CENTER", offsetX, 0);
|
|
self:SetHeight(height);
|
|
self:SetAlpha(alpha);
|
|
end
|
|
|
|
local ActiveAnimIntro = AnimIntro_SimpleFadeIn_OnUpdate;
|
|
|
|
|
|
function DUIDialogBaseMixin:PlayIntroAnimation()
|
|
self.fromHeight = 0.5 * self.frameHeight;
|
|
self.fromOffsetX = self.frameOffsetX + 72;
|
|
self.t = 0;
|
|
self.ContentFrame:SetClipsChildren(true);
|
|
self:SetScript("OnUpdate", ActiveAnimIntro);
|
|
end
|
|
|
|
local Handler = {
|
|
["GOSSIP_SHOW"] = "HandleGossip",
|
|
["QUEST_DETAIL"] = "HandleQuestDetail", --See the details of an available quest
|
|
["QUEST_PROGRESS"] = "HandleQuestProgress", --Show status of a taken quest. "Continue" button
|
|
["QUEST_COMPLETE"] = "HandleQuestComplete", --Show "Complete Quest" button
|
|
["QUEST_GREETING"] = "HandleQuestGreeting", --Similar to GOSSIP_SHOW
|
|
};
|
|
|
|
function DUIDialogBaseMixin:ShowUI(event)
|
|
if self.isGameLoading then
|
|
self.deferredEvent = event;
|
|
return
|
|
end
|
|
|
|
if IsPlayingCutscene() then
|
|
--For case: triggering cutscene when accepting quest and the quest is immediately flagged as complete
|
|
self:CloseDialogInteraction();
|
|
return
|
|
end
|
|
|
|
local shouldShowUI;
|
|
|
|
if Handler[event] then
|
|
self.handler = Handler[event];
|
|
shouldShowUI = self[ Handler[event] ](self);
|
|
end
|
|
|
|
if not shouldShowUI then return end;
|
|
|
|
if not self:IsShown() then
|
|
CameraUtil:InitiateInteraction();
|
|
self:PlayIntroAnimation();
|
|
self:OnEvent(event);
|
|
end
|
|
|
|
self:Show();
|
|
self.hasInteraction = true;
|
|
|
|
CallbackRegistry:Trigger("DialogueUI.HandleEvent", event);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HideUI(cancelPopupFirst)
|
|
if not self:IsShown() then return end;
|
|
|
|
if cancelPopupFirst and self.requireGossipConfirm then
|
|
self:OnEvent("GOSSIP_CONFIRM_CANCEL");
|
|
return
|
|
end
|
|
|
|
self:Hide();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnShow()
|
|
KeyboardControl:SetParentFrame(self);
|
|
|
|
self:RegisterEvent("GOSSIP_SHOW");
|
|
self:RegisterEvent("GOSSIP_CLOSED");
|
|
self:RegisterEvent("GOSSIP_CONFIRM");
|
|
self:RegisterEvent("GOSSIP_ENTER_CODE");
|
|
self:RegisterEvent("QUEST_LOG_UPDATE");
|
|
self:RegisterEvent("QUEST_FINISHED");
|
|
self:RegisterEvent("QUEST_ACCEPTED");
|
|
self:RegisterEvent("PLAYER_REGEN_DISABLED");
|
|
self:RegisterEvent("LOADING_SCREEN_ENABLED");
|
|
self:RegisterEvent("ADVENTURE_MAP_OPEN");
|
|
|
|
if IS_MODERN_WOW then
|
|
self:RegisterEvent("PLAYER_CHOICE_UPDATE"); --Watch TRAIT_SYSTEM_INTERACTION_STARTED
|
|
end
|
|
|
|
FadeFrame(self.Vignette, 0.75, 1);
|
|
|
|
CallbackRegistry:Trigger("DialogueUI.Show");
|
|
end
|
|
|
|
function DUIDialogBaseMixin:CloseDialogInteraction()
|
|
CloseQuest();
|
|
CloseGossipInteraction();
|
|
|
|
--Classic:
|
|
--HideUI will cause ClassTrainerFrame to not processing events (Blizzard_TrainerUI/Blizzard_TrainerUI.lua#72)
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetInteractionIsContinuing(interactionIsContinuing)
|
|
--Not used
|
|
self.interactionIsContinuing = true; --?
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnHide()
|
|
CameraUtil:Restore();
|
|
|
|
self:CloseDialogInteraction();
|
|
self.keepGossipHistory = false;
|
|
self.requireGossipConfirm = false;
|
|
self.selectedGossipIndex = nil;
|
|
self.consumeGossipClose = nil;
|
|
self.questIsFromGossip = nil;
|
|
self.handler = nil;
|
|
self.contentHeight = 0;
|
|
|
|
self:UnregisterEvent("GOSSIP_SHOW");
|
|
self:UnregisterEvent("GOSSIP_CLOSED");
|
|
self:UnregisterEvent("GOSSIP_CONFIRM");
|
|
self:UnregisterEvent("GOSSIP_CONFIRM_CANCEL");
|
|
self:UnregisterEvent("GOSSIP_ENTER_CODE");
|
|
self:UnregisterEvent("QUEST_ITEM_UPDATE");
|
|
self:UnregisterEvent("QUEST_LOG_UPDATE");
|
|
self:UnregisterEvent("QUEST_FINISHED");
|
|
self:UnregisterEvent("QUEST_ACCEPTED");
|
|
self:UnregisterEvent("PLAYER_REGEN_DISABLED");
|
|
self:UnregisterEvent("LOADING_SCREEN_ENABLED");
|
|
self:UnregisterEvent("ADVENTURE_MAP_OPEN");
|
|
|
|
if IS_MODERN_WOW then
|
|
self:UnregisterEvent("PLAYER_CHOICE_UPDATE");
|
|
end
|
|
|
|
self:ReleaseAllObjects();
|
|
self:HideInputBox();
|
|
|
|
FadeFrame(self.Vignette, 0.5, 0);
|
|
TooltipFrame:Hide();
|
|
|
|
CallbackRegistry:Trigger("DialogueUI.Hide");
|
|
|
|
if self.acknowledgeAutoAcceptQuest then
|
|
self.acknowledgeAutoAcceptQuest = nil;
|
|
AcknowledgeAutoAcceptQuest();
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnMouseUp(button)
|
|
if button == "RightButton" then
|
|
self:CloseDialogInteraction();
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnMouseWheel(delta)
|
|
self.ScrollFrame:OnMouseWheel(delta);
|
|
end
|
|
|
|
function DUIDialogBaseMixin:HighlightButton(optionButton)
|
|
if optionButton and optionButton == self.highlightedButton then
|
|
return true
|
|
end
|
|
|
|
self.ButtonHighlight:ClearAllPoints();
|
|
|
|
if optionButton and optionButton:IsEnabled() and (optionButton.artID ~= 3) then -- artID = 3 (Hollow, auto accepted quest)
|
|
optionButton:SetParentHighlightTexture(self.ButtonHighlight);
|
|
else
|
|
self.ButtonHighlight:Hide();
|
|
end
|
|
|
|
self.highlightedButton = optionButton;
|
|
|
|
if optionButton and optionButton.gamepadIndex then
|
|
self:SetGamePadFocusIndex(optionButton.gamepadIndex);
|
|
self.GamePadFocusIndicator:ClearAllPoints();
|
|
self.GamePadFocusIndicator:SetPoint("CENTER", optionButton, "LEFT", 0, 0);
|
|
self.GamePadFocusIndicator:Show();
|
|
else
|
|
self.GamePadFocusIndicator:Hide();
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:UpdateRewards()
|
|
self.itemButtonPool:CallActive("Refresh");
|
|
end
|
|
|
|
function DUIDialogBaseMixin:OnEvent(event, ...)
|
|
if event == "QUEST_ITEM_UPDATE" then
|
|
self:UpdateRewards();
|
|
elseif event == "GOSSIP_SHOW" then
|
|
self.keepGossipHistory = true;
|
|
elseif event == "GOSSIP_CLOSED" then
|
|
self.keepGossipHistory = false;
|
|
self.selectedGossipIndex = nil;
|
|
elseif event == "QUEST_ACCEPTED" then
|
|
local questID = ...
|
|
self:HandleQuestAccepted(questID);
|
|
elseif event == "QUEST_LOG_UPDATE" then
|
|
if self.hasActiveGossipQuests then
|
|
self.keepGossipHistory = false;
|
|
self:UpdateGossipQuests();
|
|
elseif self.handler == "HandleQuestGreeting" then
|
|
self:HandleQuestGreeting();
|
|
end
|
|
elseif event == "QUEST_FINISHED" then
|
|
self.keepGossipHistory = false;
|
|
elseif event == "PLAYER_REGEN_DISABLED" then
|
|
if self:IsShown() then
|
|
CameraUtil:OnEnterCombatDuringInteraction();
|
|
end
|
|
elseif event == "GOSSIP_CONFIRM" then
|
|
local gossipID, text, cost = ...
|
|
self:RegisterEvent("GOSSIP_CONFIRM_CANCEL");
|
|
self:HandleGossipConfirm(gossipID, text, cost);
|
|
elseif event == "GOSSIP_CONFIRM_CANCEL" then
|
|
self:UnregisterEvent(event);
|
|
self:HideGossipConfirm();
|
|
elseif event == "GOSSIP_ENTER_CODE" then
|
|
local gossipID = ...
|
|
self:HandleGossipEnterCode(gossipID);
|
|
elseif event == "LOADING_SCREEN_ENABLED" then
|
|
self:HideUI();
|
|
elseif event == "ADVENTURE_MAP_OPEN" then
|
|
CallbackRegistry:Trigger("PlayerInteraction.ShowUI", true);
|
|
elseif event == "LOADING_SCREEN_DISABLED" then --not reliable on the intial login
|
|
self:UnregisterEvent(event);
|
|
C_Timer.After(4, function()
|
|
self.isGameLoading = nil;
|
|
self:HandleInitialLoadingComplete();
|
|
end);
|
|
elseif event == "PLAYER_CHOICE_UPDATE" then
|
|
--TWW: Show Weekly Quest Selection
|
|
self:UnregisterEvent(event);
|
|
self:CloseDialogInteraction();
|
|
self:HideUI();
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetConsumeGossipClose(state)
|
|
--Event Sequence when selecting a quest from GossipFrame
|
|
--1.GOSSIP_CLOSE
|
|
--2.QUEST_DETAIL
|
|
|
|
if state then
|
|
if not self.consumeGossipClose then
|
|
self.consumeGossipClose = true;
|
|
After(0.8, function()
|
|
self.consumeGossipClose = nil;
|
|
end);
|
|
end
|
|
else
|
|
self.consumeGossipClose = nil;
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:MarkQuestIsFromGossip()
|
|
--if the quest is from gossip, clicking Decline button will return user to previous dialog
|
|
self.questIsFromGossip = true;
|
|
end
|
|
|
|
function DUIDialogBaseMixin:IsGossipCloseConsumed()
|
|
if self.consumeGossipClose then
|
|
self.consumeGossipClose = nil;
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ScrollDownOrAcceptQuest(fromMouseClick)
|
|
if SCROLLDOWN_THEN_ACCEPT_QUEST and not fromMouseClick then
|
|
if not self:IsScrollAtBottom() then
|
|
self:ScrollToBottom();
|
|
local noFeedback = true;
|
|
return noFeedback
|
|
end
|
|
end
|
|
|
|
self:SetAcceptCurrentQuest(); --For showing "Quest Accepted" banner
|
|
|
|
if self.acknowledgeAutoAcceptQuest then
|
|
self.acknowledgeAutoAcceptQuest = nil;
|
|
AcknowledgeAutoAcceptQuest();
|
|
else
|
|
AcceptQuest();
|
|
end
|
|
end
|
|
|
|
|
|
do --Clipboard
|
|
local strjoin = strjoin;
|
|
local function JoinText(...)
|
|
return strjoin("\n", ...);
|
|
end
|
|
|
|
local function ConcatenateQuestTable(quests)
|
|
local title, questID, text;
|
|
local str = "\n";
|
|
local idFormat = "[Quest: %d] %s";
|
|
|
|
for i, questInfo in ipairs(quests) do
|
|
text = idFormat:format(questInfo.questID, questInfo.title);
|
|
str = JoinText(str, text);
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
local function ConcatenateOptionTable(options)
|
|
local title, questID, text, name;
|
|
local str = "\n";
|
|
local idFormat = "[OptionID: %d] %s";
|
|
|
|
for i, data in ipairs(options) do
|
|
name = data.name;
|
|
if data.flags == 1 then
|
|
name = "(Quest) "..name;
|
|
end
|
|
text = idFormat:format(data.gossipOptionID, name);
|
|
str = JoinText(str, text);
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
local function ConcatenateQuestIDTitle(previousText, includeID)
|
|
local questID = GetQuestID();
|
|
local title = GetQuestTitle();
|
|
local idFormat = "[Quest: %d] %s";
|
|
if questID and questID ~= 0 then
|
|
local text;
|
|
if includeID then
|
|
text = idFormat:format(questID, title);
|
|
else
|
|
text = title
|
|
end
|
|
if previousText then
|
|
previousText = JoinText(previousText, text);
|
|
else
|
|
previousText = text;
|
|
end
|
|
end
|
|
|
|
return previousText
|
|
end
|
|
|
|
local function ConcatenateQuestItems(sourceType, numItems)
|
|
local GetQuestItemInfo = GetQuestItemInfo;
|
|
local str = "";
|
|
local idFormat = "[ItemID: %d] %s";
|
|
|
|
for index = 1, numItems do
|
|
local hidden = IsQuestItemHidden(index);
|
|
if hidden == 0 then
|
|
local name, texture, count, quality, isUsable, itemID = GetQuestItemInfo(sourceType, index);
|
|
local text = idFormat:format(itemID, name);
|
|
if count and count > 1 then
|
|
text = text.." x"..count;
|
|
end
|
|
str = JoinText(str, text);
|
|
end
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
local function ConcatenateCurrencies(sourceType, numCurrencies)
|
|
local GetQuestCurrencyInfo = GetQuestCurrencyInfo;
|
|
local GetQuestCurrencyID = GetQuestCurrencyID;
|
|
local str = "";
|
|
local idFormat = "[CurrencyID: %d] %s";
|
|
|
|
for index = 1, numCurrencies do
|
|
local name, texture, amount, quality = GetQuestCurrencyInfo(sourceType, index);
|
|
local currencyID = GetQuestCurrencyID(sourceType, index);
|
|
local text = idFormat:format(currencyID, name);
|
|
if amount and amount > 1 then
|
|
text = text.." x"..amount;
|
|
end
|
|
str = JoinText(str, text);
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
local function ConcatenateRewards(previousText)
|
|
local anyRewards;
|
|
|
|
local function AddItemText(itemButton)
|
|
local text = itemButton:GetClipboardOutput();
|
|
if text then
|
|
if not anyRewards then
|
|
anyRewards = true;
|
|
previousText = JoinText(previousText, " ", L["Rewards"], " ");
|
|
end
|
|
previousText = JoinText(previousText, text);
|
|
end
|
|
end
|
|
MainFrame.itemButtonPool:ProcessActiveObjects(AddItemText);
|
|
MainFrame.smallItemButtonPool:ProcessActiveObjects(AddItemText);
|
|
return previousText
|
|
end
|
|
|
|
function DUIDialogBaseMixin:GetContent(clipboardMode)
|
|
--For TTS and Clipboard
|
|
--clipboardMode = true includes item rewards and IDs
|
|
|
|
local str;
|
|
|
|
local GetGossipText = API.GetGossipText;
|
|
local GetQuestText = API.GetQuestText;
|
|
|
|
if clipboardMode then
|
|
local npcName, npcID = API.GetCurrentNPCInfo();
|
|
if npcName and npcID then
|
|
local idFormat = "[NPC: %d] %s";
|
|
str = idFormat:format(npcID, npcName);
|
|
end
|
|
end
|
|
|
|
if self.handler == "HandleGossip" then
|
|
local gossipText = GetGossipText();
|
|
|
|
if str then
|
|
str = JoinText(str, gossipText);
|
|
else
|
|
str = gossipText;
|
|
end
|
|
|
|
if clipboardMode then
|
|
local availableQuests = GetAvailableQuests();
|
|
local activeQuests = GetActiveQuests();
|
|
local options = GetOptions();
|
|
tsort(options, SortFunc_GossipOrder);
|
|
|
|
if #availableQuests > 0 then
|
|
str = str..ConcatenateQuestTable(availableQuests);
|
|
end
|
|
|
|
if #activeQuests > 0 then
|
|
str = str..ConcatenateQuestTable(activeQuests);
|
|
end
|
|
|
|
if #options > 0 then
|
|
str = str..ConcatenateOptionTable(options);
|
|
end
|
|
end
|
|
|
|
elseif self.handler == "HandleQuestDetail" then
|
|
str = ConcatenateQuestIDTitle(str, clipboardMode);
|
|
str = JoinText(str, "", GetQuestText("Detail"));
|
|
|
|
local objective = GetObjectiveText();
|
|
if objective and objective ~= "" then
|
|
str = JoinText(str, "", L["Quest Objectives"], "", objective);
|
|
end
|
|
|
|
if clipboardMode then
|
|
str = ConcatenateRewards(str);
|
|
end
|
|
|
|
elseif self.handler == "HandleQuestProgress" then
|
|
str = ConcatenateQuestIDTitle(str, clipboardMode);
|
|
str = JoinText(str, "", GetQuestText("Progress"));
|
|
|
|
if clipboardMode then
|
|
local numRequiredItems = GetNumQuestItems();
|
|
local numRequiredCurrencies = GetNumQuestCurrencies();
|
|
local numRequiredMoney = GetQuestMoneyToGet();
|
|
|
|
if numRequiredItems > 0 or numRequiredMoney > 0 or numRequiredCurrencies > 0 then
|
|
str = JoinText(str, "", L["Requirements"]);
|
|
|
|
if numRequiredMoney > 0 then
|
|
local colorized = false;
|
|
local noAbbreviation = true;
|
|
local moneyText = API.GenerateMoneyText(numRequiredMoney, colorized, noAbbreviation);
|
|
str = JoinText(str, moneyText);
|
|
end
|
|
|
|
if numRequiredItems > 0 then
|
|
str = JoinText(str, ConcatenateQuestItems("required", numRequiredItems));
|
|
end
|
|
|
|
if numRequiredCurrencies > 0 then
|
|
str = JoinText(str, ConcatenateCurrencies("required", numRequiredCurrencies));
|
|
end
|
|
end
|
|
end
|
|
|
|
elseif self.handler == "HandleQuestComplete" then
|
|
str = ConcatenateQuestIDTitle(str, clipboardMode);
|
|
str = JoinText(str, "", GetQuestText("Complete"));
|
|
|
|
if clipboardMode then
|
|
str = ConcatenateRewards(str);
|
|
end
|
|
|
|
elseif self.handler == "HandleQuestGreeting" then
|
|
str = ConcatenateQuestIDTitle(str, clipboardMode);
|
|
str = JoinText(str, "", GetQuestText("Greeting"));
|
|
|
|
if clipboardMode then
|
|
local numAvailableQuests = GetNumAvailableQuests();
|
|
local availableQuests = {};
|
|
for i = 1, numAvailableQuests do
|
|
local title = GetAvailableTitle(i);
|
|
local isTrivial, frequency, isRepeatable, isLegendary, questID = GetAvailableQuestInfo(i);
|
|
local questInfo = {
|
|
title = title,
|
|
questID = questID,
|
|
};
|
|
tinsert(availableQuests, questInfo);
|
|
end
|
|
|
|
if numAvailableQuests > 0 then
|
|
str = str..ConcatenateQuestTable(availableQuests);
|
|
end
|
|
|
|
local numActiveQuests = GetNumActiveQuests();
|
|
local activeQuests = {};
|
|
for i = 1, numActiveQuests do
|
|
local title, isComplete = GetActiveTitle(i);
|
|
local questID = GetActiveQuestID(i);
|
|
local questInfo = {
|
|
title = title,
|
|
questID = questID,
|
|
};
|
|
tinsert(activeQuests, questInfo);
|
|
end
|
|
|
|
if numActiveQuests > 0 then
|
|
str = str..ConcatenateQuestTable(activeQuests);
|
|
end
|
|
end
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SendContentToClipboard()
|
|
local str = self:GetContent(true);
|
|
|
|
if str then
|
|
if StripHyperlinks then
|
|
--We remove the atlas/texture since it messes up spacing
|
|
local maintainColor = true;
|
|
local maintainBrackets = true;
|
|
str = StripHyperlinks(str, true, true);
|
|
end
|
|
addon.Clipboard:ShowContent(str, self.CopyTextButton);
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
do --Quest Rewards
|
|
|
|
local ITEM_BUTTON_SPACING = 8;
|
|
local GridLayout = API.CreateGridLayout();
|
|
GridLayout:SetGrid(4, 2);
|
|
GridLayout:SetSpacing(8);
|
|
|
|
local GetQuestItemInfoLootType = API.GetQuestItemInfoLootType;
|
|
|
|
function DUIDialogBaseMixin:FormatRewards(offsetY, rewardList)
|
|
-- 4 x 2 Grid Layout:
|
|
-- ItemButton: 2x2
|
|
-- SmallItemButton: 1x1
|
|
local chooseItems = self.chooseItems;
|
|
|
|
local itemButtonWidth = self.halfFrameWidth;
|
|
local itemButtonHeight = 36;
|
|
local gridWidth = self.quarterFrameWidth;
|
|
local smallItemButtonHeight = 15;
|
|
local sizeX, sizeY;
|
|
|
|
GridLayout:ResetGrid();
|
|
GridLayout:SetGridSize(self.quarterFrameWidth, smallItemButtonHeight);
|
|
|
|
for i, data in ipairs(rewardList) do
|
|
local object;
|
|
local actualSizeX;
|
|
|
|
if i == 1 and data.isRewardChoices then
|
|
--One choice reward has been processed
|
|
local sourceType = "choice";
|
|
local onlyChoice = false;
|
|
local numChoices = data.numChoices;
|
|
local offsetX = 0;
|
|
local backgroundID;
|
|
|
|
sizeX = (INPUT_DEVICE_GAME_PAD and 4) or 2;
|
|
|
|
local isChoosingRewards = data.chooseItems;
|
|
|
|
if isChoosingRewards then
|
|
backgroundID = 2;
|
|
offsetY = self:InsertText(offsetY, REWARD_CHOOSE); --Choose
|
|
else
|
|
backgroundID = 1;
|
|
offsetY = self:InsertText(offsetY, REWARD_CHOICES); --Will be able to choose
|
|
end
|
|
|
|
offsetY = offsetY + ITEM_BUTTON_SPACING;
|
|
local fromOffsetY = offsetY;
|
|
|
|
for orderIndex = 1, numChoices do
|
|
object = self.itemButtonPool:Acquire();
|
|
object:SetBaseGridSize(sizeX, gridWidth, ITEM_BUTTON_SPACING);
|
|
object:SetBackgroundTexture(backgroundID);
|
|
|
|
local lootType = GetQuestItemInfoLootType(sourceType, orderIndex);
|
|
if (lootType == 0) then -- LOOT_LIST_ITEM
|
|
object:SetRewardChoiceItem(orderIndex, onlyChoice);
|
|
elseif (lootType == 1) then -- LOOT_LIST_CURRENCY
|
|
object:SetRewardChoiceCurrency(orderIndex, onlyChoice);
|
|
end
|
|
|
|
object:SetPoint("TOPLEFT", self.ContentFrame, "TOPLEFT", offsetX, -offsetY);
|
|
offsetX = offsetX + 2*gridWidth + 2*ITEM_BUTTON_SPACING;
|
|
|
|
if INPUT_DEVICE_GAME_PAD or orderIndex % 2 == 0 then
|
|
offsetY = offsetY + itemButtonHeight + ITEM_BUTTON_SPACING;
|
|
offsetX = 0;
|
|
end
|
|
|
|
if chooseItems then
|
|
self:IndexGamePadObject(object);
|
|
end
|
|
end
|
|
|
|
local numRows = (INPUT_DEVICE_GAME_PAD and numChoices) or math.ceil(numChoices / 2);
|
|
offsetY = fromOffsetY + (itemButtonHeight + ITEM_BUTTON_SPACING) * numRows - ITEM_BUTTON_SPACING;
|
|
offsetY = offsetY + PARAGRAPH_SPACING;
|
|
|
|
if #rewardList > 1 then
|
|
offsetY = self:InsertText(offsetY, REWARD_ITEMS); --You will also receive
|
|
offsetY = offsetY + ITEM_BUTTON_SPACING;
|
|
end
|
|
|
|
if isChoosingRewards then
|
|
self:RequestSellPrice();
|
|
end
|
|
else
|
|
if data.title then
|
|
object = self:AcquireLeftFontString();
|
|
object:SetText(data.title);
|
|
actualSizeX = 4;
|
|
sizeY = 1;
|
|
else
|
|
local method = data[1];
|
|
|
|
if data.small then
|
|
sizeX = 1;
|
|
sizeY = 1;
|
|
object = self.smallItemButtonPool:Acquire();
|
|
else
|
|
sizeX = 2;
|
|
sizeY = 2;
|
|
object = self.itemButtonPool:Acquire();
|
|
end
|
|
|
|
object:SetBaseGridSize(sizeX, gridWidth, ITEM_BUTTON_SPACING);
|
|
|
|
object[method](object, data[2], data[3], data[4], data[5]);
|
|
actualSizeX = object:GetActualGridTaken() or sizeX;
|
|
end
|
|
|
|
GridLayout:PlaceObject(object, actualSizeX, sizeY, self.ContentFrame, 0, -offsetY);
|
|
end
|
|
end
|
|
|
|
local width, height = GridLayout:GetWrappedSize();
|
|
|
|
return offsetY + height
|
|
end
|
|
end
|
|
|
|
|
|
do
|
|
--Clipboard
|
|
local CopyTextButton;
|
|
|
|
local function CopyTextButton_OnClick(self)
|
|
if addon.Clipboard:CloseIfFromSameSender(self) then
|
|
return
|
|
end
|
|
MainFrame:SendContentToClipboard();
|
|
end
|
|
|
|
local function Settings_ShowCopyTextButton(dbValue)
|
|
if dbValue == true then
|
|
if not CopyTextButton then
|
|
local themeID = 1; --Brown
|
|
CopyTextButton = addon.CreateCopyTextButton(MainFrame, CopyTextButton_OnClick, themeID);
|
|
CopyTextButton:SetPoint("TOPRIGHT", MainFrame, "TOPRIGHT", -8, -8);
|
|
MainFrame.CopyTextButton = CopyTextButton;
|
|
--CopyTextButton.Icon:SetSize(18, 18);
|
|
end
|
|
CopyTextButton:Show();
|
|
CopyTextButton:SetTheme(ThemeUtil:GetThemeID());
|
|
else
|
|
if CopyTextButton then
|
|
CopyTextButton:Hide();
|
|
end
|
|
end
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.ShowCopyTextButton", Settings_ShowCopyTextButton);
|
|
|
|
|
|
local function Settings_ScrollDownThenAcceptQuest(dbValue)
|
|
SCROLLDOWN_THEN_ACCEPT_QUEST = dbValue == true;
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.ScrollDownThenAcceptQuest", Settings_ScrollDownThenAcceptQuest);
|
|
|
|
local function Settings_CameraMovement(dbValue)
|
|
if dbValue == 0 then
|
|
ActiveAnimIntro = AnimIntro_SimpleFadeIn_OnUpdate;
|
|
elseif dbValue == 1 then
|
|
ActiveAnimIntro = AnimIntro_Unfold_OnUpdate;
|
|
elseif dbValue == 2 then
|
|
ActiveAnimIntro = AnimIntro_FlyInRight_OnUpdate;
|
|
end
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.CameraMovement", Settings_CameraMovement);
|
|
end
|
|
|
|
|
|
do --GamePad/Controller
|
|
function DUIDialogBaseMixin:UpdateScrollFrameBound()
|
|
self.scrollFrameTop = self.ScrollFrame:GetTop();
|
|
self.scrollFrameBottom = self.ScrollFrame:GetBottom();
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ResetGamePadObjects()
|
|
self.gamepadMaxIndex = 0;
|
|
self.gamepadFocusIndex = nil;
|
|
self.gamepadFocus = nil;
|
|
self.gamepadObjects = {};
|
|
end
|
|
|
|
function DUIDialogBaseMixin:IndexGamePadObject(object)
|
|
self.gamepadMaxIndex = self.gamepadMaxIndex + 1;
|
|
self.gamepadObjects[self.gamepadMaxIndex] = object;
|
|
object.gamepadIndex = self.gamepadMaxIndex;
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ClearGamePadFocus()
|
|
if self.gamepadFocus then
|
|
self.gamepadFocus:OnLeave();
|
|
self.gamepadFocus = nil;
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:SetGamePadFocusIndex(index)
|
|
self.gamepadFocusIndex = index;
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FocusObjectByDelta(delta)
|
|
local maxIndex = self.gamepadMaxIndex or 0;
|
|
local index = self.gamepadFocusIndex;
|
|
|
|
if not index then
|
|
index = 0;
|
|
end
|
|
|
|
if delta < 0 and index < maxIndex then
|
|
index = index + 1;
|
|
elseif delta > 0 and index > 1 then
|
|
index = index - 1;
|
|
elseif index == 0 then
|
|
index = maxIndex;
|
|
else
|
|
return
|
|
end
|
|
|
|
self:ClearGamePadFocus();
|
|
|
|
self.gamepadFocusIndex = index;
|
|
self.gamepadFocus = self.gamepadObjects[index];
|
|
|
|
if self.gamepadFocus then
|
|
self:UpdateScrollFrameBound();
|
|
|
|
self.gamepadFocus:OnEnter();
|
|
local buttonHeight = self.gamepadFocus:GetHeight();
|
|
local threshold = 2 * buttonHeight - 4;
|
|
if delta > 0 then
|
|
local top = self.gamepadFocus:GetTop();
|
|
if top + threshold >= self.scrollFrameTop then
|
|
self:ScrollBy(-3*buttonHeight);
|
|
end
|
|
else
|
|
local bottom = self.gamepadFocus:GetBottom();
|
|
if bottom - threshold <= self.scrollFrameBottom then
|
|
self:ScrollBy(3*buttonHeight);
|
|
end
|
|
end
|
|
return true
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FocusNextObject()
|
|
if self:FocusObjectByDelta(-1) then
|
|
return
|
|
end
|
|
|
|
if self:IsScrollable() then
|
|
self:ScrollBy(192);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:FocusPreviousObject()
|
|
if self:FocusObjectByDelta(1) then
|
|
return
|
|
end
|
|
|
|
if self:IsScrollable() then
|
|
self:ScrollBy(-192);
|
|
end
|
|
end
|
|
|
|
function DUIDialogBaseMixin:ClickFocusedObject()
|
|
if self.gamepadFocus then
|
|
self.gamepadFocus:OnClick("GamePad");
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
function DUIDialogBaseMixin:UpdateCompleteButton(highlightedButtonSelected)
|
|
local button = self.AcceptButton;
|
|
local hotkey = button.HotkeyFrame;
|
|
if not hotkey then return end;
|
|
|
|
if highlightedButtonSelected then
|
|
hotkey:Show();
|
|
button.hasHotkey = true;
|
|
button:Layout(true);
|
|
else
|
|
hotkey:Hide();
|
|
button.hasHotkey = false;
|
|
button:Layout(true);
|
|
end
|
|
|
|
self.GamePadFocusIndicator:SetShown(not highlightedButtonSelected);
|
|
end
|
|
end
|
|
|
|
|
|
do --TTS
|
|
local TTSButton;
|
|
|
|
local function Settings_TTSEnabled(dbValue)
|
|
if dbValue == true then
|
|
if not TTSButton then
|
|
local themeID = 1;
|
|
TTSButton = addon.CreateTTSButton(MainFrame, themeID);
|
|
TTSButton:SetPoint("TOPLEFT", MainFrame, "TOPLEFT", 8, -8);
|
|
MainFrame.TTSButton = TTSButton;
|
|
end
|
|
TTSButton:Show();
|
|
TTSButton:SetTheme(ThemeUtil:GetThemeID());
|
|
else
|
|
if TTSButton then
|
|
TTSButton:Hide();
|
|
end
|
|
end
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.TTSEnabled", Settings_TTSEnabled);
|
|
end
|
|
|
|
do
|
|
function DUIDialogBaseMixin:OnSettingsChanged()
|
|
if self:IsVisible() and self.handler then
|
|
self.keepGossipHistory = false;
|
|
self[self.handler](self);
|
|
end
|
|
end
|
|
|
|
local function OnFontSizeChanged(baseFontSize, fontSizeID)
|
|
local f = MainFrame;
|
|
|
|
if f.hotkeyFramePool then
|
|
local method = "UpdateBaseHeight";
|
|
f.hotkeyFramePool:CallAllObjects(method);
|
|
f.GamePadFocusIndicator:UpdateBaseHeight();
|
|
end
|
|
|
|
if f.optionButtonPool then
|
|
local method = "OnFontSizeChanged";
|
|
f.optionButtonPool:CallAllObjects(method);
|
|
end
|
|
|
|
if f.AcceptButton.HotkeyFrame then
|
|
f.AcceptButton.HotkeyFrame:UpdateBaseHeight();
|
|
end
|
|
|
|
if f.ExitButton.HotkeyFrame then
|
|
f.ExitButton.HotkeyFrame:UpdateBaseHeight();
|
|
end
|
|
|
|
FONT_SIZE = baseFontSize;
|
|
TEXT_SPACING = 0.35 * FONT_SIZE; --Recommended Line Height: 1.2 - 1.5
|
|
PARAGRAPH_SPACING = 4 * TEXT_SPACING; --4 * TEXT_SPACING
|
|
PARAGRAPH_BUTTON_SPACING = 2 * FONT_SIZE; --Font Size * 2
|
|
|
|
f:OnSettingsChanged();
|
|
end
|
|
CallbackRegistry:Register("FontSizeChanged", OnFontSizeChanged);
|
|
|
|
local function PostFontSizeChanged()
|
|
--There is delay before footer button height changed
|
|
After(0, function()
|
|
MainFrame:UpdateFrameSize();
|
|
MainFrame:OnSettingsChanged();
|
|
end);
|
|
end
|
|
CallbackRegistry:Register("PostFontSizeChanged", PostFontSizeChanged);
|
|
|
|
local FrameSizeIndexScale = {
|
|
[0] = 0.9,
|
|
[1] = 1.0,
|
|
[2] = 1.1,
|
|
[3] = 1.25,
|
|
};
|
|
|
|
local function Settings_FrameSize(dbValue)
|
|
--1: 1.0, 2: 1.1, 3:1.25
|
|
local newScale = dbValue and FrameSizeIndexScale[dbValue]
|
|
if newScale and newScale ~= FRAME_SIZE_MULTIPLIER then
|
|
local f = MainFrame;
|
|
FRAME_SIZE_MULTIPLIER = newScale;
|
|
|
|
if dbValue == 0 then
|
|
FRAME_OFFSET_RATIO = 4/5;
|
|
else
|
|
FRAME_OFFSET_RATIO = 3/4;
|
|
end
|
|
|
|
f:UpdateFrameSize();
|
|
f:OnSettingsChanged();
|
|
end
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.FrameSize", Settings_FrameSize);
|
|
|
|
|
|
local function Settings_ForceGossip(dbValue)
|
|
ALWAYS_GOSSIP = dbValue == true;
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.ForceGossip", Settings_ForceGossip);
|
|
|
|
local function Settings_ShowNPCNameOnPage(dbValue)
|
|
SHOW_NPC_NAME = dbValue == true;
|
|
MainFrame:OnSettingsChanged();
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.ShowNPCNameOnPage", Settings_ShowNPCNameOnPage);
|
|
|
|
local function Settings_MarkHighestSellPrice(dbValue)
|
|
MARK_HIGHEST_SELL_PRICE = dbValue == true;
|
|
MainFrame:OnSettingsChanged();
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.MarkHighestSellPrice", Settings_MarkHighestSellPrice);
|
|
|
|
local function Settings_AutoSelectGossip(dbValue)
|
|
AUTO_SELECT_GOSSIP = dbValue == true;
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.AutoSelectGossip", Settings_AutoSelectGossip);
|
|
|
|
local function Settings_HideUI(dbValue)
|
|
ExperienceBar:SetShown(dbValue == true);
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.HideUI", Settings_HideUI);
|
|
|
|
local function Settings_UseRoleplayName(dbValue)
|
|
if dbValue == true then
|
|
GetQuestText = API.GetModifiedQuestText;
|
|
GetGossipText = API.GetModifiedGossipText;
|
|
else
|
|
GetQuestText = API.GetQuestText;
|
|
GetGossipText = API.GetGossipText;
|
|
end
|
|
MainFrame:OnSettingsChanged();
|
|
end
|
|
CallbackRegistry:Register("SettingChanged.UseRoleplayName", Settings_UseRoleplayName);
|
|
|
|
|
|
local function SettingsUI_Show()
|
|
SETTINGS_UI_VISIBLE = true;
|
|
end
|
|
CallbackRegistry:Register("SettingsUI.Show", SettingsUI_Show);
|
|
|
|
local function SettingsUI_Hide()
|
|
SETTINGS_UI_VISIBLE = false;
|
|
end
|
|
CallbackRegistry:Register("SettingsUI.Hide", SettingsUI_Hide);
|
|
|
|
|
|
local function UpdateMainOptionButtonHotkey(b, key)
|
|
if b and b.HotkeyFrame then
|
|
b.HotkeyFrame.key = nil;
|
|
local keyShown = b.HotkeyFrame:IsShown();
|
|
b.HotkeyFrame:SetKey(key);
|
|
if keyShown then
|
|
b:Layout(true);
|
|
else
|
|
b.HotkeyFrame:Hide();
|
|
end
|
|
end
|
|
end
|
|
|
|
local function PostInputDeviceChanged(dbValue)
|
|
INPUT_DEVICE_GAME_PAD = dbValue ~= 1;
|
|
MainFrame:OnSettingsChanged();
|
|
|
|
UpdateMainOptionButtonHotkey(MainFrame.AcceptButton, "PRIMARY");
|
|
UpdateMainOptionButtonHotkey(MainFrame.ExitButton, "Esc");
|
|
|
|
if INPUT_DEVICE_GAME_PAD then
|
|
MainFrame.GamePadFocusIndicator:SetKey("PRIMARY");
|
|
else
|
|
MainFrame.GamePadFocusIndicator:ClearKey();
|
|
end
|
|
end
|
|
CallbackRegistry:Register("PostInputDeviceChanged", PostInputDeviceChanged);
|
|
end
|