ZO_PAGEDLIST_MOVEMENT_TYPES = { PAGE_FORWARD = 1, PAGE_BACK = 2, -- LAST allows derived classes to start their movement enumerations after the base movements LAST = 3, } function ZO_PagedListPlaySound(type) if type == ZO_PAGEDLIST_MOVEMENT_TYPES.PAGE_FORWARD then PlaySound(SOUNDS.GAMEPAD_PAGE_FORWARD) elseif type == ZO_PAGEDLIST_MOVEMENT_TYPES.PAGE_BACK then PlaySound(SOUNDS.GAMEPAD_PAGE_BACK) end end ZO_PagedListFooter = ZO_InitializingObject:Subclass() function ZO_PagedListFooter:Initialize(control) self.control = control self.previousButton = control:GetNamedChild("PreviousButton") self.nextButton = control:GetNamedChild("NextButton") self.pageNumberLabel = control:GetNamedChild("PageNumberText") end function ZO_PagedListFooter:SetPageText(pageNumber) self.pageNumberLabel:SetText(pageNumber) end function ZO_PagedListFooter:SetHidden(hidden) self.control:SetHidden(hidden) end function ZO_PagedListFooter:IsHidden() return self.control:IsHidden() end function ZO_PagedListSetupFooter(footerControl) return ZO_PagedListFooter:New(footerControl) end ZO_PagedList = ZO_SortFilterListBase:Subclass() function ZO_PagedList:New(...) return ZO_SortFilterListBase.New(self, ...) end function ZO_PagedList:BuildMasterList() -- intended to be overriden -- should populate the dataList by calling AddEntry end function ZO_PagedList:FilterList() -- intended to be overriden -- should take the dataList and filter it end function ZO_PagedList:SortList() -- can optionally be overriden -- should take the dataList and sort it -- The default implemenation will sort according to the sort keys specified in the SetupSort function if self.sortKeys then table.sort(self.dataList, function(listEntry1, listEntry2) return self:CompareSortEntries(listEntry1, listEntry2) end) end end function ZO_PagedList:OnListChanged() -- intended to be overriden -- allows a subclass to react when list contents change end function ZO_PagedList:OnPageChanged() -- intended to be overriden -- allows a subclass to react when list page changes end function ZO_PagedList:Initialize(control, movementController) ZO_SortFilterListBase.Initialize(self, control, movementController) self.listControl = control:GetNamedChild("List") self.focus = ZO_GamepadFocus:New(self.listControl, movementController) self.selectionChangedCallback = nil local selectionChangeCallback = function(entryControl) if self.selectionChangedCallback then local data = nil if entryControl then data = entryControl.data.data end self.selectionChangedCallback(data) end end self.focus:SetFocusChangedCallback(selectionChangeCallback) self.dataTypes = {} self.dataList = {} self.pages = {} self.currPageNum = 1 self.numPages = 0 self.rememberSpot = false local headerContainer = control:GetNamedChild("Headers") if headerContainer then local showArrows = true self.sortHeaderGroup = ZO_SortHeaderGroup:New(headerContainer, showArrows) self.sortHeaderGroup:SetColors(ZO_SELECTED_TEXT, ZO_NORMAL_TEXT, ZO_SELECTED_TEXT, ZO_DISABLED_TEXT) self.sortHeaderGroup:RegisterCallback(ZO_SortHeaderGroup.HEADER_CLICKED, function(key, order) self:OnSortHeaderClicked(key, order) end) self.sortHeaderGroup:AddHeadersFromContainer() end local footerControl = control:GetNamedChild("Footer") if footerControl then self.footer = { control = footerControl, previousButton = footerControl:GetNamedChild("PreviousButton"), nextButton = footerControl:GetNamedChild("NextButton"), pageNumberLabel = footerControl:GetNamedChild("PageNumberText"), } end self.onEnterRow = function(rowControl, data) self:OnEnterRow(rowControl, data.data) end self.onLeaveRow = function(rowControl, data) self:OnLeaveRow(rowControl, data.data) end self.onPlaySoundFunction = ZO_PagedListPlaySound local hideKeybind = footerControl ~= nil self.pagedListKeybindStripDescriptor = { alignment = KEYBIND_STRIP_ALIGN_LEFT, -- Previous { --Ethereal binds show no text, the name field is used to help identify the keybind when debugging. This text does not have to be localized. name = "Paged List Previous Page", keybind = "UI_SHORTCUT_LEFT_TRIGGER", order = 100, callback = function() self:PreviousPage() end, ethereal = hideKeybind, }, -- Next { --Ethereal binds show no text, the name field is used to help identify the keybind when debugging. This text does not have to be localized. name = "Paged List Next Page", keybind = "UI_SHORTCUT_RIGHT_TRIGGER", order = 100, callback = function() self:NextPage() end, ethereal = hideKeybind, }, } end function ZO_PagedList:TakeFocus() self.focus:Activate() end function ZO_PagedList:ClearFocus() self.focus:Deactivate() end function ZO_PagedList:Activate() self:TakeFocus() KEYBIND_STRIP:AddKeybindButtonGroup(self.pagedListKeybindStripDescriptor) end function ZO_PagedList:Deactivate(retainFocus) KEYBIND_STRIP:RemoveKeybindButtonGroup(self.pagedListKeybindStripDescriptor) self.focus:Deactivate(retainFocus) end function ZO_PagedList:ActivateHeader() if self.sortHeaderGroup then self.sortHeaderGroup:SetDirectionalInputEnabled(true) self.sortHeaderGroup:EnableSelection(true) end end function ZO_PagedList:DeactivateHeader() if self.sortHeaderGroup then self.sortHeaderGroup:SetDirectionalInputEnabled(false) self.sortHeaderGroup:EnableSelection(false) end end function ZO_PagedList:SetupSort(sortKeys, initialKey, initialDirection) self.sortKeys = sortKeys self.currentSortKey = initialKey self.currentSortOrder = initialDirection end function ZO_PagedList:SetSelectionChangedCallback(callback) self.selectionChangedCallback = callback end function ZO_PagedList:SetLeaveListAtBeginningCallback(callback) self.focus:SetLeaveFocusAtBeginningCallback(callback) end function ZO_PagedList:OnEnterRow(control, data) -- This is meant to be overriden in a subclass end function ZO_PagedList:OnLeaveRow(control, data) -- This is meant to be overriden in a subclass end function ZO_PagedList:RefreshData() self:BuildMasterList() self:FilterList() self:SortList() self:CommitList() end function ZO_PagedList:RefreshSort() self:SortList() self:CommitList() end function ZO_PagedList:RefreshFilters() self:FilterList() self:SortList() self:CommitList() end function ZO_PagedList:RefreshVisible() local page = self.pages[self.currPageNum] if page == nil then return end local lastIndex = (page.startIndex + page.count - 1) for i = page.startIndex, lastIndex do local data = self.dataList[i] local control = data.control local selected = self:IsSelected(data.data) self.dataTypes[control.templateName].setupCallback(control, data.data, selected) end self:OnListChanged() end function ZO_PagedList:CommitList() self:BuildPages() self:BuildPage(self.currPageNum) self:RefreshFooter() self:OnListChanged() end function ZO_PagedList:AddDataTemplate(templateName, height, setupCallback, controlPoolPrefix) if not self.dataTypes[templateName] then local dataTypeInfo = { pool = ZO_ControlPool:New(templateName, self.listControl, controlPoolPrefix or templateName), height = height, setupCallback = setupCallback } self.dataTypes[templateName] = dataTypeInfo end end function ZO_PagedList:AddEntry(templateName, data) if self.dataTypes[templateName] then local entry = { templateName = templateName, data = data } self.dataList[#self.dataList + 1] = entry end end function ZO_PagedList:Clear() self.dataList = {} for templateName, dataTypeInfo in pairs(self.dataTypes) do dataTypeInfo.pool:ReleaseAllObjects() end end function ZO_PagedList:GetSelectedData() local focusItem = self.focus:GetFocusItem() if focusItem then return focusItem.data.data end end function ZO_PagedList:IsSelected(data) local focusItem = self.focus:GetFocusItem() if focusItem then return focusItem.data.data == data end return false end function ZO_PagedList:SetPage(pageNum) local newPageNum = zo_clamp(pageNum, 1, self.numPages) if newPageNum ~= self.currPageNum then if newPageNum > self.currPageNum then self.onPlaySoundFunction(ZO_PAGEDLIST_MOVEMENT_TYPES.PAGE_FORWARD) else self.onPlaySoundFunction(ZO_PAGEDLIST_MOVEMENT_TYPES.PAGE_BACK) end self.currPageNum = newPageNum self:BuildPage(self.currPageNum) self:RefreshFooter() self:OnListChanged() end end function ZO_PagedList:PreviousPage() self:SetPage(self.currPageNum - 1) end function ZO_PagedList:NextPage() self:SetPage(self.currPageNum + 1) end function ZO_PagedList:AcquireControl(dataIndex, relativeControl) local PADDING = 0 local templateName = self.dataList[dataIndex].templateName local control, key = self.dataTypes[templateName].pool:AcquireObject() if relativeControl then control:SetAnchor(TOPLEFT, relativeControl, BOTTOMLEFT, 0, PADDING) else control:SetAnchor(TOPLEFT, self.listControl, TOPLEFT, 0, PADDING) end control.key = key control.templateName = templateName control.dataIndex = dataIndex return control, true end function ZO_PagedList:ReleaseControl(control) local templateName = control.templateName local pool = self.dataTypes[templateName].pool pool:ReleaseObject(control.key) end function ZO_PagedList:BuildPages() self.pages = {} local currPageHeight = 0 local currPageNum = 1 local _, pageHeight = self.listControl:GetDimensions() self.pages[currPageNum] = {startIndex = 1, count = 0} for i, data in ipairs(self.dataList) do local templateName = data.templateName local height = self.dataTypes[templateName].height if (currPageHeight + height) > pageHeight then currPageHeight = 0 currPageNum = currPageNum + 1 self.pages[currPageNum] = {startIndex = i, count = 0} end currPageHeight = currPageHeight + height self.pages[currPageNum].count = self.pages[currPageNum].count + 1 end if self.emptyRow then self.emptyRow:SetHidden(#self.dataList > 0) end self.numPages = currPageNum if self.rememberSpot then self.currPageNum = zo_min(self.currPageNum, currPageNum) else self.currPageNum = 1 end end local INCLUDE_SAVED_INDEX = true function ZO_PagedList:BuildPage(pageNum) local savedIndex = self.focus:GetFocus(INCLUDE_SAVED_INDEX) self.focus:RemoveAllEntries() for templateName, dataTypeInfo in pairs(self.dataTypes) do dataTypeInfo.pool:ReleaseAllObjects() end local page = self.pages[pageNum] local lastIndex = (page.startIndex + page.count - 1) local previousControl for i = page.startIndex, lastIndex do local data = self.dataList[i] local control = self:AcquireControl(i, previousControl) data.control = control local selected = self:IsSelected(data.data) self.dataTypes[control.templateName].setupCallback(control, data.data, selected) local entry = { control = control, highlight = control:GetNamedChild("Highlight"), data = data, activate = self.onEnterRow, deactivate = self.onLeaveRow, } self.focus:AddEntry(entry) previousControl = control if self.alternateRowBackgrounds then local rowBackground = control:GetNamedChild("BG") if rowBackground then local hidden = (i % 2) == 0 rowBackground:SetHidden(hidden) end end end if self.rememberSpot then local itemsOnPage = self.focus:GetItemCount() if savedIndex then savedIndex = zo_min(savedIndex, itemsOnPage) end self.focus:SetFocusByIndex(savedIndex or 1) else self.focus:SetFocusByIndex(1) end end function ZO_PagedList:RefreshSelectedRow() local focusItem = self.focus:GetFocusItem() if focusItem then local selected = self:IsSelected(focusItem.data.data) self.dataTypes[focusItem.control.templateName].setupCallback(focusItem.control, focusItem.data.data, selected) end end function ZO_PagedList:OnSortHeaderClicked(key, order) self.currentSortKey = key self.currentSortOrder = order self:RefreshSort() end function ZO_PagedList:CompareSortEntries(listEntry1, listEntry2) return ZO_TableOrderingFunction(listEntry1.data, listEntry2.data, self.currentSortKey, self.sortKeys, self.currentSortOrder) end function ZO_PagedList:SetEmptyText(emptyText, template) if not self.emptyRow then self.emptyRow = CreateControlFromVirtual("$(parent)EmptyRow", self.focus.control, template) end self.emptyRow:GetNamedChild("Message"):SetText(emptyText) end function ZO_PagedList:RefreshFooter() if not self.footer then return end local enablePrevious = self.currPageNum > 1 self.footer.previousButton:SetEnabled(enablePrevious) local enableNext = self.currPageNum < #self.pages self.footer.nextButton:SetEnabled(enableNext) local pageNumberText = zo_strformat(SI_GAMEPAD_PAGED_LIST_PAGE_NUMBER, self.currPageNum) self.footer.pageNumberLabel:SetText(pageNumberText) self.footer.control:SetHidden(#self.pages <= 1) end function ZO_PagedList:SetAlternateRowBackgrounds(alternate) self.alternateRowBackgrounds = alternate end function ZO_PagedList:SetPlaySoundFunction(fn) self.onPlaySoundFunction = fn end function ZO_PagedList:SetRememberSpotInList(rememberSpot) self.rememberSpot = rememberSpot end