local CONFIRM_SCENE_NAME = "gamepad_smithing_research_confirm" local CONFIRM_TEMPLATE_NAME = "ZO_GamepadSubMenuEntryTemplateWithStatus" ZO_GAMEPAD_CONFIRM_CANCEL_RESEARCH_DIALOG = "GAMEPAD_CONFIRM_CANCEL_RESEARCH" local GAMEPAD_SMITHING_RESEARCH_FILTER_INCLUDE_BANKED = 1 local g_filters = { [GAMEPAD_SMITHING_RESEARCH_FILTER_INCLUDE_BANKED] = { header = SI_GAMEPAD_SMITHING_FILTERS, filterName = GetString(SI_CRAFTING_INCLUDE_BANKED), filterTooltip = GetString(SI_CRAFTING_INCLUDE_BANKED_TOOLTIP), checked = false, }, } ZO_GamepadSmithingResearch = ZO_SharedSmithingResearch:Subclass() function ZO_GamepadSmithingResearch:Initialize(panelContent, owner, scene) local researchPanel = panelContent:GetNamedChild("Research") ZO_SharedSmithingResearch.Initialize(self, researchPanel, owner, "ZO_GamepadSmithingResearchSlot") self.panelContent = panelContent scene:RegisterCallback("StateChange", function(oldState, newState) if newState == SCENE_SHOWING then self:PerformDeferredInitialization() KEYBIND_STRIP:AddKeybindButtonGroup(self.keybindStripDescriptor) local tabBarEntries = self:GenerateTabBarEntries() self.focus:Activate() self.owner:SetEnableSkillBar(true) local savedFilter = self.typeFilter local titleString = ZO_GamepadCraftingUtils_GetLineNameForCraftingType(GetCraftingInteractionType()) ZO_GamepadCraftingUtils_SetupGenericHeader(self.owner, titleString, tabBarEntries) ZO_GamepadCraftingUtils_RefreshGenericHeader(self.owner) self:SetupTabBar(tabBarEntries, savedFilter) self:Refresh() local NARRATE_HEADER = true SCREEN_NARRATION_MANAGER:QueueFocus(self.focus, NARRATE_HEADER) elseif newState == SCENE_HIDING then KEYBIND_STRIP:RemoveKeybindButtonGroup(self.keybindStripDescriptor) self.focus:Deactivate() self.owner:SetEnableSkillBar(false) ZO_GamepadGenericHeader_Deactivate(self.owner.header) GAMEPAD_TOOLTIPS:Reset(GAMEPAD_LEFT_TOOLTIP) end end) GAMEPAD_SMITHING_RESEARCH_CONFIRM_SCENE = self.owner:CreateInteractScene(CONFIRM_SCENE_NAME) GAMEPAD_SMITHING_RESEARCH_CONFIRM_SCENE:RegisterCallback("StateChange", function(oldState, newState) if newState == SCENE_SHOWING then local function AddEntry(data) local entry = ZO_GamepadEntryData:New(data.name) entry:InitializeCraftingInventoryVisualData(data.bag, data.index, data.stack) self.confirmList:AddEntry(CONFIRM_TEMPLATE_NAME, entry) end local function IsResearchableItem(bagId, slotIndex) return ZO_SharedSmithingResearch.IsResearchableItem(bagId, slotIndex, self.confirmCraftingType, self.confirmResearchLineIndex, self.confirmTraitIndex) end local confirmPanel = self.panelContent:GetNamedChild("Confirm") confirmPanel:GetNamedChild("SelectionText"):SetText(GetString(SI_GAMEPAD_SMITHING_RESEARCH_SELECT_ITEM)) self.confirmList:Clear() local virtualInventoryList = PLAYER_INVENTORY:GenerateListOfVirtualStackedItems(INVENTORY_BACKPACK, IsResearchableItem) if self.savedVars.includeBankedItemsChecked then PLAYER_INVENTORY:GenerateListOfVirtualStackedItems(INVENTORY_BANK, IsResearchableItem, virtualInventoryList) end for itemId, itemInfo in pairs(virtualInventoryList) do itemInfo.name = zo_strformat(SI_TOOLTIP_ITEM_NAME, GetItemName(itemInfo.bag, itemInfo.index)) AddEntry(itemInfo) end self.confirmList:Commit() self.confirmList:Activate() KEYBIND_STRIP:AddKeybindButtonGroup(self.confirmKeybindStripDescriptor) elseif newState == SCENE_HIDING then self.confirmList:Deactivate() KEYBIND_STRIP:RemoveKeybindButtonGroup(self.confirmKeybindStripDescriptor) GAMEPAD_TOOLTIPS:Reset(GAMEPAD_LEFT_TOOLTIP) end end) end function ZO_GamepadSmithingResearch:PerformDeferredInitialization() if self.keybindStripDescriptor then return end self:InitializeResearchLineList(ZO_HorizontalScrollList_Gamepad, "ZO_GamepadSmithingResearchListSlot") self:InitializeKeybindStripDescriptors() self:InitializeConfirmList() self:InitializeFocusItems() self:InitializeConfirmDestroyDialog() self:AnchorTimerBar() self:SetupSavedVars() end function ZO_GamepadSmithingResearch:AnchorTimerBar() local timerBar = self.control:GetNamedChild("TimerBar") local researchList = self.control:GetNamedChild("ResearchLineList") timerBar:SetParent(researchList) timerBar:ClearAnchors() local newAnchor = ZO_Anchor:New(TOPLEFT, researchList:GetNamedChild("List"), BOTTOMLEFT) newAnchor:AddToControl(timerBar) newAnchor = ZO_Anchor:New(TOPRIGHT, researchList:GetNamedChild("List"), BOTTOMRIGHT, 0, 8) newAnchor:AddToControl(timerBar) end function ZO_GamepadSmithingResearch:GenerateTabBarEntries() local tabBarEntries = {} local function AddTabEntry(filterType) if ZO_CraftingUtils_CanSmithingFilterBeCraftedHere(filterType) then local entry = {} entry.text = GetString("SI_SMITHINGFILTERTYPE", filterType) entry.callback = function() self.typeFilter = filterType self:HandleDirtyEvent() local NARRATE_HEADER = true SCREEN_NARRATION_MANAGER:QueueFocus(self.focus, NARRATE_HEADER) end entry.mode = filterType table.insert(tabBarEntries, entry) end end AddTabEntry(SMITHING_FILTER_TYPE_WEAPONS) AddTabEntry(SMITHING_FILTER_TYPE_ARMOR) AddTabEntry(SMITHING_FILTER_TYPE_JEWELRY) return tabBarEntries end function ZO_GamepadSmithingResearch:SetupTabBar(tabBarEntries, savedFilter) if #tabBarEntries == 1 then self.typeFilter = tabBarEntries[1].mode else ZO_GamepadGenericHeader_Activate(self.owner.header) local filterFound = false for index, entry in pairs(tabBarEntries) do if savedFilter == entry.mode then self.typeFilter = savedFilter ZO_GamepadGenericHeader_SetActiveTabIndex(self.owner.header, index) filterFound = true break end end if not filterFound then self.typeFilter = tabBarEntries[1].mode ZO_GamepadGenericHeader_SetActiveTabIndex(self.owner.header, 1) end end end function ZO_GamepadSmithingResearch:RefreshAvailableFilters(dontReselect) end function ZO_GamepadSmithingResearch:RefreshCurrentResearchStatusDisplay(currentlyResearching, maxResearchable) ZO_GamepadCraftingUtils_SetGenericHeaderData2(self.owner, GetString(SI_GAMEPAD_SMITHING_CURRENT_RESEARCH_HEADER), zo_strformat(SI_GAMEPAD_SMITHING_CURRENT_RESEARCH_AMOUNT, currentlyResearching, maxResearchable)) ZO_GamepadCraftingUtils_RefreshGenericHeaderData(self.owner) end function ZO_GamepadSmithingResearch:InitializeKeybindStripDescriptors() self.keybindStripDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Perform research { keybind = "UI_SHORTCUT_PRIMARY", name = function() return GetString(SI_ITEM_ACTION_RESEARCH) end, callback = function() self:Research() end, enabled = function() if not ZO_CraftingUtils_IsPerformingCraftProcess() then return self:IsResearchable() end end, }, -- Cancel research { keybind = "UI_SHORTCUT_SECONDARY", name = function() return GetString(SI_CRAFTING_CANCEL_RESEARCH) end, callback = function() self:CancelResearch() end, visible = function() if not ZO_CraftingUtils_IsPerformingCraftProcess() then return self:CanCancelResearch() end end, }, -- Item Options { name = GetString(SI_GAMEPAD_CRAFTING_OPTIONS), keybind = "UI_SHORTCUT_TERTIARY", gamepadOrder = 1020, callback = function() self:ShowOptionsMenu() end, enabled = function() return not ZO_CraftingUtils_IsPerformingCraftProcess() end, }, } ZO_Gamepad_AddBackNavigationKeybindDescriptors(self.keybindStripDescriptor, GAME_NAVIGATION_TYPE_BUTTON) ZO_CraftingUtils_ConnectKeybindButtonGroupToCraftingProcess(self.keybindStripDescriptor) local function ConfirmResearch() local targetData = self.confirmList:GetTargetData() if targetData then local _, _, _, timeRequiredForNextResearchSecs = GetSmithingResearchLineInfo(self.confirmCraftingType, self.confirmResearchLineIndex) local formattedTime = ZO_FormatTime(timeRequiredForNextResearchSecs, TIME_FORMAT_STYLE_COLONS, TIME_FORMAT_PRECISION_TWELVE_HOUR) ZO_Dialogs_ShowGamepadDialog("GAMEPAD_CONFIRM_RESEARCH_ITEM", { bagId = targetData.bagId, slotIndex = targetData.slotIndex, owner = self }, { mainTextParams = { formattedTime }}) end end -- Confirm research keybind descriptor. self.confirmKeybindStripDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, { keybind = "UI_SHORTCUT_PRIMARY", name = GetString(SI_SMITHING_RESEARCH_DIALOG_CONFIRM), callback = ConfirmResearch, sound = SOUNDS.SMITHING_START_RESEARCH, }, } ZO_Gamepad_AddBackNavigationKeybindDescriptors(self.confirmKeybindStripDescriptor, GAME_NAVIGATION_TYPE_BUTTON) end function ZO_GamepadSmithingResearch:InitializeConfirmDestroyDialog() local function ReleaseDialog() ZO_Dialogs_ReleaseDialogOnButtonPress(ZO_GAMEPAD_CONFIRM_CANCEL_RESEARCH_DIALOG) end ZO_Dialogs_RegisterCustomDialog(ZO_GAMEPAD_CONFIRM_CANCEL_RESEARCH_DIALOG, { blockDialogReleaseOnPress = true, canQueue = true, gamepadInfo = { dialogType = GAMEPAD_DIALOGS.BASIC, allowRightStickPassThrough = true, }, setup = function(dialog) self.destroyConfirmText = nil dialog:setupFunc() end, title = { text = SI_CRAFTING_CONFIRM_CANCEL_RESEARCH_TITLE, }, mainText = { text = SI_GAMEPAD_CRAFTING_CONFIRM_CANCEL_RESEARCH_DESCRIPTION, }, buttons = { { onShowCooldown = 2000, keybind = "DIALOG_PRIMARY", text = GetString(SI_YES), callback = function(dialog) local data = dialog.data CancelSmithingTraitResearch(data.craftingType, data.researchLineIndex, data.traitIndex) ReleaseDialog() end, }, { keybind = "DIALOG_NEGATIVE", text = GetString(SI_NO), callback = function() ReleaseDialog() end, }, } }) end function ZO_GamepadSmithingResearch:AcceptResearch(bagId, slotIndex) ResearchSmithingTrait(bagId, slotIndex) --go back to the trait selection screen SCENE_MANAGER:HideCurrentScene() end function ZO_GamepadSmithingResearch:SetupSavedVars() local defaults = { includeBankedItemsChecked = true } local savedVars = ZO_SavedVars:New("ZO_Ingame_SavedVariables", 1, "GamepadSmithingResearch", defaults) self:SetSavedVars(savedVars) g_filters[GAMEPAD_SMITHING_RESEARCH_FILTER_INCLUDE_BANKED].checked = self.savedVars.includeBankedItemsChecked end function ZO_GamepadSmithingResearch:ShowOptionsMenu() local dialogData = { filters = g_filters, finishedCallback = function() self:SaveFilters() GAMEPAD_TOOLTIPS:ClearTooltip(GAMEPAD_LEFT_TOOLTIP) end } if not self.craftingOptionsDialogGamepad then self.craftingOptionsDialogGamepad = ZO_CraftingOptionsDialogGamepad:New() end self.craftingOptionsDialogGamepad:ShowOptionsDialog(dialogData) end function ZO_GamepadSmithingResearch:SaveFilters() local filterChanged = self.savedVars.includeBankedItemsChecked ~= g_filters[GAMEPAD_SMITHING_RESEARCH_FILTER_INCLUDE_BANKED].checked if filterChanged then self.savedVars.includeBankedItemsChecked = g_filters[GAMEPAD_SMITHING_RESEARCH_FILTER_INCLUDE_BANKED].checked self:HandleDirtyEvent() ZO_SavePlayerConsoleProfile() end end function ZO_GamepadSmithingResearch:InitializeConfirmList() self.confirmList = ZO_GamepadVerticalItemParametricScrollList:New(self.panelContent:GetNamedChild("Confirm"):GetNamedChild("List")) self.confirmList:SetAlignToScreenCenter(true) self.confirmList:AddDataTemplate(CONFIRM_TEMPLATE_NAME, ZO_SharedGamepadEntry_OnSetup, ZO_GamepadMenuEntryTemplateParametricListFunction, nil, "Entry") local function OnEntryChanged(list, selectedData) if selectedData then GAMEPAD_TOOLTIPS:LayoutBagItem(GAMEPAD_LEFT_TOOLTIP, selectedData.bagId, selectedData.slotIndex) if selectedData.isEquippedInCurrentCategory or selectedData.isEquippedInAnotherCategory then GAMEPAD_TOOLTIPS:SetStatusLabelText(GAMEPAD_LEFT_TOOLTIP, GetString(SI_GAMEPAD_EQUIPPED_ITEM_HEADER)) self:UpdateTooltipEquippedIndicatorText(self.selectedEquippedIndicator, selectedData.slotIndex) else GAMEPAD_TOOLTIPS:ClearStatusLabel(GAMEPAD_LEFT_TOOLTIP) end else GAMEPAD_TOOLTIPS:ClearTooltip(GAMEPAD_LEFT_TOOLTIP) end end self.confirmList:SetOnSelectedDataChangedCallback(OnEntryChanged) ZO_Gamepad_AddListTriggerKeybindDescriptors(self.confirmKeybindStripDescriptor, self.confirmList) local narrationInfo = { canNarrate = function() return GAMEPAD_SMITHING_RESEARCH_CONFIRM_SCENE:IsShowing() end, headerNarrationFunction = function() --Use the "choose an item to research" text as the header instead of the actual header here, as the actual header isn't actually active return SCREEN_NARRATION_MANAGER:CreateNarratableObject(GetString(SI_GAMEPAD_SMITHING_RESEARCH_SELECT_ITEM)) end, } SCREEN_NARRATION_MANAGER:RegisterParametricList(self.confirmList, narrationInfo) end function ZO_GamepadSmithingResearch:InitializeFocusItems() self.focus = ZO_GamepadFocus:New(self.panelContent) --Narrate the current focus when the focused item changes self.focus:SetFocusChangedCallback(function(focusItem) if focusItem then SCREEN_NARRATION_MANAGER:QueueFocus(self.focus) end end) --Re-narrate the current focus upon closing a dialog CALLBACK_MANAGER:RegisterCallback("AllDialogsHidden", function() if self.focus:IsActive() then local NARRATE_HEADER = true SCREEN_NARRATION_MANAGER:QueueFocus(self.focus, NARRATE_HEADER) end end) end function ZO_GamepadSmithingResearch:RefreshFocusItems(focusIndex) local function AddEntry(control, highlight, activate, deactivate, narrationText, directionalInputNarrationFunction) self.focus:AddEntry( { control = control, highlight = highlight, activate = activate, deactivate = deactivate, narrationText = narrationText, additionalInputNarrationFunction = directionalInputNarrationFunction, headerNarrationFunction = function() return ZO_GamepadGenericHeader_GetNarrationText(self.owner.header, self.owner.headerData) end, footerNarrationFunction = function() return self.owner:GetFooterNarration() end, }) end local ACTIVE = true local function UpdateBorderHighlight(focusedControl, active) focusedControl.inactiveBG:SetHidden(active) focusedControl.activeBG:SetHidden(not active) end local function ListActivate(control, data) control:Activate() UpdateBorderHighlight(control:GetControl():GetParent(), ACTIVE) end local function ListDeactivate(control, data) control:Deactivate() UpdateBorderHighlight(control:GetControl():GetParent(), not ACTIVE) end local function ListNarrationText(focusItem) local narrations = {} table.insert(narrations, ZO_FormatSpinnerNarrationText(GetString(SI_SMITHING_RESEARCH_LINE_HEADER), self.traitLineText)) if self.timer and self.timer:IsStarted() then table.insert(narrations, self.timer:GetNarrationText()) else table.insert(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(self.extraInfoText)) end return narrations end local function GetListDirectionalInputNarrationData() if self.researchLineList then local narrationFunction = self.researchLineList:GetAdditionalInputNarrationFunction() return narrationFunction() end return {} end AddEntry(self.researchLineList, self.control:GetNamedChild("ResearchLineList").focusTexture, ListActivate, ListDeactivate, ListNarrationText, GetListDirectionalInputNarrationData) local function Activate(control) self:OnResearchRowActivate(control) end local function Deactivate(control) self:OnResearchRowDeactivate(control) end local function TraitNarrationText(focusItem) local traitType = focusItem.control.traitType local narrations = {} --Include the "Trait Progress" text in the narration if this is the first trait in the list if focusItem.control.traitIndex == 1 then table.insert(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(GetString(SI_SMITHING_RESEARCH_PROGRESS_HEADER))) end table.insert(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(GetString("SI_ITEMTRAITTYPE", traitType))) table.insert(narrations, SCREEN_NARRATION_MANAGER:CreateNarratableObject(focusItem.control.statusText)) return narrations end local entries = self.slotPool:GetActiveObjects() for _, v in pairs(entries) do AddEntry(v, v:GetNamedChild("Highlight"), Activate, Deactivate, TraitNarrationText) end if focusIndex then self.focus:SetFocusByIndex(focusIndex) else self.focus:SetFocusByIndex(1) end end function ZO_GamepadSmithingResearch:OnControlsAcquired() ZO_SharedSmithingResearch.OnControlsAcquired(self) local savedFocusIndex = self.focus:GetFocus() self.focus:RemoveAllEntries() self:RefreshFocusItems(savedFocusIndex) end function ZO_GamepadSmithingResearch:SetupTooltip(row) GAMEPAD_TOOLTIPS:LayoutResearchSmithingItem(GAMEPAD_LEFT_TOOLTIP, GetString("SI_ITEMTRAITTYPE", row.traitType), row.traitDescription, row.traitResearchSourceDescription, row.traitMaterialSourceDescription) end function ZO_GamepadSmithingResearch:ClearTooltip(row) GAMEPAD_TOOLTIPS:ClearTooltip(GAMEPAD_LEFT_TOOLTIP) end function ZO_GamepadSmithingResearch:Research() local canResearchCurrentTrait = self:CanResearchCurrentTraitLine() if self.atMaxResearchLimit then local craftingSkillLineData = SKILLS_DATA_MANAGER:GetCraftingSkillLineData(GetCraftingInteractionType()) ZO_Alert(UI_ALERT_CATEGORY_ALERT, SOUNDS.NEGATIVE_CLICK, SI_SMITHING_RESEARCH_ALL_SLOTS_IN_USE, craftingSkillLineData:GetName()) elseif not canResearchCurrentTrait then ZO_Alert(UI_ALERT_CATEGORY_ALERT, SOUNDS.NEGATIVE_CLICK, SI_SMITHING_RESEARCH_TRAIT_ALREADY_BEING_RESEARCHED, self.traitLineText) else self.confirmCraftingType, self.confirmResearchLineIndex, self.confirmTraitIndex = self.activeRow.craftingType, self.activeRow.researchLineIndex, self.activeRow.traitIndex SCENE_MANAGER:Push(CONFIRM_SCENE_NAME) end end function ZO_GamepadSmithingResearch:GetResearchTimeString(count, time) local timeWithIcon = zo_iconTextFormatNoSpace("EsoUI/Art/Miscellaneous/Gamepad/gp_icon_timer32.dds", "100%", "100%", time) return zo_strformat(SI_GAMEPAD_SMITHING_RESEARCH_TIME_FOR_NEXT, count, timeWithIcon) end function ZO_GamepadSmithingResearch:GetExtraInfoColor() return ZO_SELECTED_TEXT:UnpackRGBA() end function ZO_GamepadSmithingResearch:SetupTraitDisplay(slotControl, researchLine, known, duration, traitIndex) local iconControl = slotControl:GetNamedChild("Icon") if known then slotControl.nameLabel:SetColor(ZO_NORMAL_TEXT:UnpackRGBA()) slotControl.statusLabel:SetText("") slotControl.statusText = "" slotControl.timerIcon:SetHidden(true) iconControl:SetDesaturation(0) iconControl:SetAlpha(1) elseif duration then slotControl.nameLabel:SetColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) slotControl.statusText = GetString(SI_SMITHING_RESEARCH_IN_PROGRESS) slotControl.statusLabel:SetText(slotControl.statusText) slotControl.statusLabel:SetColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) slotControl.timerIcon:SetHidden(false) slotControl.timerIcon:SetColor(ZO_SECOND_CONTRAST_TEXT:UnpackRGBA()) iconControl:SetDesaturation(0) iconControl:SetAlpha(.3) elseif researchLine.itemTraitCounts and researchLine.itemTraitCounts[traitIndex] then slotControl.nameLabel:SetColor(ZO_SELECTED_TEXT:UnpackRGBA()) slotControl.statusText = GetString(SI_SMITHING_RESEARCH_RESEARCHABLE) slotControl.statusLabel:SetText(slotControl.statusText) slotControl.statusLabel:SetColor(ZO_SELECTED_TEXT:UnpackRGBA()) slotControl.timerIcon:SetHidden(true) iconControl:SetDesaturation(0) iconControl:SetAlpha(1) slotControl.researchable = true else slotControl.nameLabel:SetColor(ZO_DISABLED_TEXT:UnpackRGBA()) slotControl.statusText = GetString(SI_SMITHING_RESEARCH_UNKNOWN) slotControl.statusLabel:SetText(slotControl.statusText) slotControl.statusLabel:SetColor(ZO_DISABLED_TEXT:UnpackRGBA()) slotControl.timerIcon:SetHidden(true) iconControl:SetDesaturation(1) iconControl:SetAlpha(1) end end