From adfdb1e54f10b7ecb854e82f759154d22ff53790 Mon Sep 17 00:00:00 2001 From: obligaron Date: Mon, 1 Nov 2021 09:55:10 +0100 Subject: [PATCH] Refactored UiList ViewPort Logic --- Source/DiabloUI/diabloui.cpp | 62 ++++++++++++++++++++++-------------- Source/DiabloUI/diabloui.h | 3 +- Source/DiabloUI/selhero.cpp | 51 ++++------------------------- 3 files changed, 45 insertions(+), 71 deletions(-) diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index 286f1e768..87fcc8825 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -44,7 +44,7 @@ namespace devilution { std::size_t SelectedItemMax; std::size_t ListViewportSize = 1; -const std::size_t *ListOffset = nullptr; +std::size_t listOffset = 0; std::array ArtLogos; std::array ArtFocus; @@ -84,13 +84,21 @@ struct ScrollBarState { } } scrollBarState; +void AdjustListOffset(std::size_t itemIndex) +{ + if (itemIndex >= listOffset + ListViewportSize) + listOffset = itemIndex - (ListViewportSize - 1); + if (itemIndex < listOffset) + listOffset = itemIndex; +} + } // namespace -void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), const std::vector> &items, bool itemsWraps, bool (*fnYesNo)(), size_t selectedItem /*= 0*/) +void UiInitList(size_t listViewportSize, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), const std::vector> &items, bool itemsWraps, bool (*fnYesNo)(), size_t selectedItem /*= 0*/) { SelectedItem = selectedItem; - SelectedItemMax = std::max(count - 1, 0); - ListViewportSize = count; + SelectedItemMax = 0; + ListViewportSize = listViewportSize; gfnListFocus = fnFocus; gfnListSelect = fnSelect; gfnListEsc = fnEsc; @@ -99,7 +107,8 @@ void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int valu for (const auto &item : items) gUiItems.push_back(item.get()); UiItemsWraps = itemsWraps; - ListOffset = nullptr; + listOffset = 0; + AdjustListOffset(selectedItem); if (fnFocus != nullptr) fnFocus(selectedItem); @@ -107,6 +116,7 @@ void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int valu SDL_StopTextInput(); // input is enabled by default #endif textInputActive = false; + UiScrollbar *uiScrollbar = nullptr; for (const auto &item : items) { if (item->m_type == UiType::Edit) { auto *pItemUIEdit = static_cast(item.get()); @@ -124,18 +134,20 @@ void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int valu #endif UiTextInput = pItemUIEdit->m_value; UiTextInputLen = pItemUIEdit->m_max_length; + } else if (item->m_type == UiType::List) { + auto *uiList = static_cast(item.get()); + SelectedItemMax = std::max(uiList->m_vecItems.size() - 1, static_cast(0)); + } else if (item->m_type == UiType::Scrollbar) { + uiScrollbar = static_cast(item.get()); } } -} -void UiInitScrollBar(UiScrollbar *uiSb, std::size_t viewportSize, const std::size_t *currentOffset) -{ - ListViewportSize = viewportSize; - ListOffset = currentOffset; - if (ListViewportSize >= static_cast(SelectedItemMax + 1)) { - uiSb->add_flag(UiFlags::ElementHidden); - } else { - uiSb->remove_flag(UiFlags::ElementHidden); + if (uiScrollbar != nullptr) { + if (ListViewportSize >= static_cast(SelectedItemMax + 1)) { + uiScrollbar->add_flag(UiFlags::ElementHidden); + } else { + uiScrollbar->remove_flag(UiFlags::ElementHidden); + } } } @@ -175,6 +187,8 @@ void UiFocus(std::size_t itemIndex) UiPlayMoveSound(); + AdjustListOffset(itemIndex); + if (gfnListFocus != nullptr) gfnListFocus(itemIndex); } @@ -199,33 +213,33 @@ void UiFocusDown() void UiFocusPageUp() { - if (ListOffset == nullptr || *ListOffset == 0) { + if (listOffset == 0) { UiFocus(0); } else { - const std::size_t relpos = SelectedItem - *ListOffset; + const std::size_t relpos = SelectedItem - listOffset; std::size_t prevPageStart = SelectedItem - relpos; if (prevPageStart >= ListViewportSize) prevPageStart -= ListViewportSize; else prevPageStart = 0; UiFocus(prevPageStart); - UiFocus(*ListOffset + relpos); + UiFocus(listOffset + relpos); } } void UiFocusPageDown() { - if (ListOffset == nullptr || *ListOffset + ListViewportSize > static_cast(SelectedItemMax)) { + if (listOffset + ListViewportSize > static_cast(SelectedItemMax)) { UiFocus(SelectedItemMax); } else { - const std::size_t relpos = SelectedItem - *ListOffset; + const std::size_t relpos = SelectedItem - listOffset; std::size_t nextPageEnd = SelectedItem + (ListViewportSize - relpos - 1); if (nextPageEnd + ListViewportSize <= static_cast(SelectedItemMax)) nextPageEnd += ListViewportSize; else nextPageEnd = SelectedItemMax; UiFocus(nextPageEnd); - UiFocus(*ListOffset + relpos); + UiFocus(listOffset + relpos); } } @@ -753,10 +767,10 @@ void Render(const UiList *uiList) { const Surface &out = Surface(DiabloUiSurface()); - for (std::size_t i = 0; i < uiList->m_vecItems.size(); ++i) { - SDL_Rect rect = uiList->itemRect(i); + for (std::size_t i = listOffset; i < uiList->m_vecItems.size() && (i - listOffset) < ListViewportSize; ++i) { + SDL_Rect rect = uiList->itemRect(i - listOffset); const UiListItem *item = uiList->GetItem(i); - if (i + (ListOffset == nullptr ? 0 : *ListOffset) == SelectedItem) + if (i == SelectedItem) DrawSelector(rect); Rectangle rectangle { { rect.x, rect.y }, { rect.w, rect.h } }; @@ -856,7 +870,7 @@ bool HandleMouseEventList(const SDL_Event &event, UiList *uiList) return false; std::size_t index = uiList->indexAt(event.button.y); - index += (ListOffset == nullptr ? 0 : *ListOffset); + index += listOffset; if (gfnListFocus != nullptr && SelectedItem != index) { UiFocus(index); diff --git a/Source/DiabloUI/diabloui.h b/Source/DiabloUI/diabloui.h index 75f7b5e4c..3cb5ae0b3 100644 --- a/Source/DiabloUI/diabloui.h +++ b/Source/DiabloUI/diabloui.h @@ -122,8 +122,7 @@ void UiAddLogo(std::vector> *vecDialog, int size = L void UiFocusNavigationSelect(); void UiFocusNavigationEsc(); void UiFocusNavigationYesNo(); -void UiInitList(int count, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), const std::vector> &items, bool wraps = false, bool (*fnYesNo)() = NULL, size_t selectedItem = 0); -void UiInitScrollBar(UiScrollbar *uiSb, std::size_t viewportSize, const std::size_t *currentOffset); +void UiInitList(size_t listViewportSize, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), const std::vector> &items, bool wraps = false, bool (*fnYesNo)() = NULL, size_t selectedItem = 0); void UiClearScreen(); void UiPollAndRender(); void UiRenderItems(const std::vector &items); diff --git a/Source/DiabloUI/selhero.cpp b/Source/DiabloUI/selhero.cpp index 1532cb08a..ccd9dbe95 100644 --- a/Source/DiabloUI/selhero.cpp +++ b/Source/DiabloUI/selhero.cpp @@ -88,33 +88,6 @@ void SelheroSetStats() std::size_t listOffset = 0; UiArtTextButton *SELLIST_DIALOG_DELETE_BUTTON; -void SelheroUpdateViewportItems() -{ - const std::size_t numViewportHeroes = std::min(selhero_SaveCount - listOffset, MaxViewportItems); - for (std::size_t i = 0; i < numViewportHeroes; i++) { - const std::size_t index = i + listOffset; - vecSelHeroDlgItems[i]->m_text = selhero_heros[index].name; - vecSelHeroDlgItems[i]->m_value = static_cast(index); - } - if (numViewportHeroes < MaxViewportItems) { - vecSelHeroDlgItems[numViewportHeroes]->m_text = _("New Hero"); - vecSelHeroDlgItems[numViewportHeroes]->m_value = static_cast(selhero_SaveCount); - } -} - -void SelheroScrollIntoView(std::size_t index) -{ - std::size_t newOffset = listOffset; - if (index >= listOffset + MaxViewportItems) - newOffset = index - (MaxViewportItems - 1); - if (index < listOffset) - newOffset = index; - if (newOffset != listOffset) { - listOffset = newOffset; - SelheroUpdateViewportItems(); - } -} - bool SelHeroGetHeroInfo(_uiheroinfo *pInfo) { selhero_heros[selhero_SaveCount] = *pInfo; @@ -127,7 +100,6 @@ bool SelHeroGetHeroInfo(_uiheroinfo *pInfo) void SelheroListFocus(int value) { const auto index = static_cast(value); - SelheroScrollIntoView(index); UiFlags baseFlags = UiFlags::AlignCenter | UiFlags::FontSize30; if (selhero_SaveCount != 0 && index < selhero_SaveCount) { memcpy(&selhero_heroInfo, &selhero_heros[index], sizeof(selhero_heroInfo)); @@ -506,27 +478,17 @@ void selhero_List_Init() vecSelDlgItems.push_back(std::make_unique(_("Select Hero"), rect1, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiSilver, 3)); vecSelHeroDlgItems.clear(); - const size_t numViewportHeroes = std::min(selhero_SaveCount + 1, MaxViewportItems); - for (std::size_t i = 0; i < numViewportHeroes; i++) { - vecSelHeroDlgItems.push_back(std::make_unique("", -1)); - } - // Adjust list to last selected hero - for (size_t i = 0; i < selhero_SaveCount; i++) { - if (selhero_heros[i].saveNumber == selhero_heroInfo.saveNumber) { + for (std::size_t i = 0; i < selhero_SaveCount; i++) { + vecSelHeroDlgItems.push_back(std::make_unique(selhero_heros[i].name, static_cast(i))); + if (selhero_heros[i].saveNumber == selhero_heroInfo.saveNumber) selectedItem = i; - if (i > (MaxViewportItems - 1)) - listOffset = i - (MaxViewportItems - 1); - break; - } } - SelheroUpdateViewportItems(); + vecSelHeroDlgItems.push_back(std::make_unique(_("New Hero"), static_cast(selhero_SaveCount))); vecSelDlgItems.push_back(std::make_unique(vecSelHeroDlgItems, PANEL_LEFT + 265, (UI_OFFSET_Y + 256), 320, 26, UiFlags::AlignCenter | UiFlags::FontSize24 | UiFlags::ColorUiGold)); SDL_Rect rect2 = { (Sint16)(PANEL_LEFT + 585), (Sint16)(UI_OFFSET_Y + 244), 25, 178 }; - auto pinnedScrollBar = std::make_unique(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rect2); - auto *scrollBar = pinnedScrollBar.get(); - vecSelDlgItems.push_back(std::move(pinnedScrollBar)); + vecSelDlgItems.push_back(std::move(std::make_unique(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rect2))); SDL_Rect rect3 = { (Sint16)(PANEL_LEFT + 239), (Sint16)(UI_OFFSET_Y + 429), 120, 35 }; vecSelDlgItems.push_back(std::make_unique(_("OK"), &UiFocusNavigationSelect, rect3, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); @@ -539,8 +501,7 @@ void selhero_List_Init() SDL_Rect rect5 = { (Sint16)(PANEL_LEFT + 489), (Sint16)(UI_OFFSET_Y + 429), 120, 35 }; vecSelDlgItems.push_back(std::make_unique(_("Cancel"), &UiFocusNavigationEsc, rect5, UiFlags::AlignCenter | UiFlags::FontSize30 | UiFlags::ColorUiGold)); - UiInitList(selhero_SaveCount + 1, SelheroListFocus, SelheroListSelect, SelheroListEsc, vecSelDlgItems, false, SelheroListDeleteYesNo, selectedItem); - UiInitScrollBar(scrollBar, MaxViewportItems, &listOffset); + UiInitList(MaxViewportItems, SelheroListFocus, SelheroListSelect, SelheroListEsc, vecSelDlgItems, false, SelheroListDeleteYesNo, selectedItem); if (selhero_isMultiPlayer) { title = _("Multi Player Characters"); } else {