From 3bf2ed273087d55be2d493d1a2681d6a7d87de0c Mon Sep 17 00:00:00 2001 From: Robsdedude Date: Tue, 17 Mar 2020 16:38:50 +0100 Subject: [PATCH] Dynamically load/unload list items while scrolling --- src/Views/ListView/listView.cpp | 113 ++++++++++++++++++++++++++++-- src/Views/ListView/listView.h | 9 ++- src/Views/ListView/searchView.cpp | 10 +-- 3 files changed, 122 insertions(+), 10 deletions(-) diff --git a/src/Views/ListView/listView.cpp b/src/Views/ListView/listView.cpp index 0fa734d..4dc563f 100644 --- a/src/Views/ListView/listView.cpp +++ b/src/Views/ListView/listView.cpp @@ -88,9 +88,107 @@ ListView::ListView(std::vector homebrews) { log_printf(DBG_DEBUG, "posY: %d", posY); log_printf(DBG_DEBUG, "homebrews size: %d", homebrews.size()); - for (Homebrew hb : homebrews) + this->homebrews = homebrews; + listItems = std::vector(homebrews.size(), nullptr); + LoadListItems(); +} + +long ListView::_LoadPreviousListItems(long firstDisplayed, long firstToLoad, long maxLoad) +{ + long loaded = 0; + for (long i = firstDisplayed; i >= firstToLoad; i--) + { + if (!listItems[i]) + { + listItems[i] = new ListItem(homebrews[i]); + if (++loaded > maxLoad) + { + break; + } + } + } + return loaded; +} + +long ListView::_LoadShownListItems(long firstDisplayed, long lastDisplayed, long maxLoad) +{ + long loaded = 0; + for (long i = firstDisplayed; i <= lastDisplayed; i++) { - listItems.emplace_back(hb); + if (!listItems[i]) + { + listItems[i] = new ListItem(homebrews[i]); + if (++loaded > maxLoad) + { + break; + } + } + } + return loaded; +} + +long ListView::_LoadNextListItems(long lastDisplayed, long lastToLoad, long maxLoad) +{ + long loaded = 0; + for (long i = lastDisplayed; i <= lastToLoad; i++) + { + if (!listItems[i]) + { + listItems[i] = new ListItem(homebrews[i]); + if (++loaded > maxLoad) + { + break; + } + } + } + return loaded; +} + +void ListView::LoadListItems() +{ + auto first = (long)firstDisplayedItem(); + auto last = (long)lastDisplayedItem(); + long firstToLoad = std::max(first - PRE_RENDER_EXTRA_LIST_ITEM, 0); + long lastToLoad = std::min(last + PRE_RENDER_EXTRA_LIST_ITEM, listItems.size()); + long loaded = 0; + for (long i = 0; i < firstToLoad; i++) + { + if (listItems[i]) + { + delete listItems[i]; + listItems[i] = nullptr; + } + } + for (long i = lastToLoad; i < (long)listItems.size(); i++) + { + if (listItems[i]) + { + delete listItems[i]; + listItems[i] = nullptr; + } + } + + loaded += _LoadShownListItems(first, last, MAX_LOAD_LIST_ITEMS_PER_CYCLE); + if (loaded >= MAX_LOAD_LIST_ITEMS_PER_CYCLE) + return; + + if (scrollSpeed >= 0) + { + // preferably pre-load further down the list + loaded += _LoadNextListItems(first, last, MAX_LOAD_LIST_ITEMS_PER_CYCLE); + if (loaded >= MAX_LOAD_LIST_ITEMS_PER_CYCLE) + return; + loaded += _LoadPreviousListItems(first, last, MAX_LOAD_LIST_ITEMS_PER_CYCLE); + if (loaded >= MAX_LOAD_LIST_ITEMS_PER_CYCLE) + return; + } else { + // preferably pre-load further up the list + loaded += _LoadPreviousListItems(first, last, MAX_LOAD_LIST_ITEMS_PER_CYCLE); + if (loaded >= MAX_LOAD_LIST_ITEMS_PER_CYCLE) + return; + loaded += _LoadNextListItems(first, last, MAX_LOAD_LIST_ITEMS_PER_CYCLE); + if (loaded >= MAX_LOAD_LIST_ITEMS_PER_CYCLE) + return; } } @@ -127,7 +225,7 @@ int ListView::HandleInput(int focus, const Input& input) log_printf(DBG_DEBUG, "Clicked, adding view..."); try { - Activity::get_instance()->AddView(std::make_shared(listItems.at(selectedItem).homebrew)); + Activity::get_instance()->AddView(std::make_shared(homebrews.at(selectedItem))); } catch (const std::exception& ex) { @@ -205,7 +303,7 @@ int ListView::HandleInput(int focus, const Input& input) log_printf(DBG_DEBUG, "Pressed, adding view..."); try { - Activity::get_instance()->AddView(std::make_shared(listItems.at(selectedItem).homebrew)); + Activity::get_instance()->AddView(std::make_shared(homebrews.at(selectedItem))); } catch (const std::exception& ex) { @@ -227,6 +325,8 @@ int ListView::HandleInput(int focus, const Input& input) } } + LoadListItems(); + return 0; } @@ -246,7 +346,10 @@ int ListView::Display() } for (int i = firstDisplayedItem(); i <= lastDisplayedItem(); i++) { - listItems[i].Display(itemPosY(i), i == selectedItem, itemHighlightAlpha); + if(listItems[i]) + { + listItems[i]->Display(itemPosY(i), i == selectedItem, itemHighlightAlpha); + } } if (itemHighlightDirection) { diff --git a/src/Views/ListView/listView.h b/src/Views/ListView/listView.h index 86ec9aa..23f65d8 100644 --- a/src/Views/ListView/listView.h +++ b/src/Views/ListView/listView.h @@ -10,6 +10,8 @@ #define LIST_MAX_Y 543 // This ordinate is included too #define LIST_RANGE_Y (LIST_MAX_Y - LIST_MIN_Y) #define LIST_HEIGHT (LIST_RANGE_Y + 1) +#define PRE_RENDER_EXTRA_LIST_ITEM 30 +#define MAX_LOAD_LIST_ITEMS_PER_CYCLE 1 // Max speed px/ms above which selected item is no more selected #define LIST_SELECTION_MAX_SPEED 0.000070 @@ -27,7 +29,9 @@ class ListView: public View { virtual bool IsReadyToShow() { return true; }; protected: - std::vector listItems; + std::vector homebrews; + std::vector listItems; + void LoadListItems(); private: Font font_43; @@ -49,4 +53,7 @@ class ListView: public View { unsigned int lastFullyDisplayedItem(); int coordinateToItem(double coordY); int updateScrollSpeed(double &scrollSpeed, unsigned long timeDif); + long _LoadPreviousListItems(long firstDisplayed, long firstToLoad, long maxLoad); + long _LoadShownListItems(long firstDisplayed, long lastDisplayed, long maxLoad); + long _LoadNextListItems(long lastDisplayed, long lastToLoad, long loadMax); }; diff --git a/src/Views/ListView/searchView.cpp b/src/Views/ListView/searchView.cpp index 8d665a7..952e7b7 100644 --- a/src/Views/ListView/searchView.cpp +++ b/src/Views/ListView/searchView.cpp @@ -34,11 +34,13 @@ int SearchView::Display() auto db = Database::get_instance(); std::vector hbs; hbs = db->Search(SearchQuery(_ime_search_view_result->userText)); - listItems.clear(); - for (Homebrew hb : hbs) - { - listItems.emplace_back(hb); + homebrews = hbs; + for (ListItem* item: listItems) { + delete item; } + listItems.clear(); + listItems = std::vector(homebrews.size(), nullptr); + LoadListItems(); lastQuery = _ime_search_view_result->userText; } else