Other scrolling method - fix hack (#122)

* other method: leave scrolling to icon updating function
downside: scroll can lag behind the selected entry if going too fast

* bring back looping so scrolling doesnt lag behind as much when going out of bounds
only about a second lag, then a second again for icons to load

* this method doesnt need to know the ids

* fix memory leak

* optimize for invisibility

* fix lockup when install checking threads are finished

* less magic, again
make icon loading functions/numbers more general

* increase wait time for fastcroll to give people more time to react, and to prevent some lag for the loading function
This commit is contained in:
LiquidFenrir
2017-12-31 05:01:31 +01:00
committed by Alex Taber
parent 841773d9e4
commit f65b32c90c
3 changed files with 107 additions and 142 deletions

View File

@@ -70,7 +70,6 @@ typedef struct {
ssize_t texture_id_offset; ssize_t texture_id_offset;
ssize_t icons_ids[ICONS_OFFSET_AMOUNT][ENTRIES_PER_SCREEN]; ssize_t icons_ids[ICONS_OFFSET_AMOUNT][ENTRIES_PER_SCREEN];
ssize_t assoc_entry_ids[ICONS_OFFSET_AMOUNT][ENTRIES_PER_SCREEN];
int previous_scroll; int previous_scroll;
int scroll; int scroll;
@@ -92,6 +91,7 @@ void delete_entry(Entry_s entry);
Result load_entries(const char * loading_path, Entry_List_s * list, EntryMode mode); Result load_entries(const char * loading_path, Entry_List_s * list, EntryMode mode);
bool load_preview(Entry_List_s list, int * preview_offset); bool load_preview(Entry_List_s list, int * preview_offset);
void load_icons_first(Entry_List_s * current_list, bool silent); void load_icons_first(Entry_List_s * current_list, bool silent);
void handle_scrolling(Entry_List_s * list);
void load_icons_thread(void * void_arg); void load_icons_thread(void * void_arg);
u32 load_data(char * filename, Entry_s entry, char ** buf); u32 load_data(char * filename, Entry_s entry, char ** buf);

View File

@@ -167,89 +167,45 @@ Result load_entries(const char * loading_path, Entry_List_s * list, EntryMode mo
return res; return res;
} }
static void small_load(Entry_List_s * current_list) void load_icons_first(Entry_List_s * list, bool silent)
{ {
DEBUG("small load\n"); if(list == NULL || list->entries == NULL) return;
ssize_t * icons_ids = (ssize_t *)current_list->icons_ids;
ssize_t * assoc_entry_ids = (ssize_t *)current_list->assoc_entry_ids;
ssize_t id = current_list->texture_id_offset;
for(int i = 0; i < current_list->entries_count; i++, id++)
{
Entry_s current_entry = current_list->entries[i];
load_smdh_icon(current_entry, id);
icons_ids[i] = id;
assoc_entry_ids[i] = i;
}
}
static void first_load(Entry_List_s * current_list)
{
DEBUG("first load\n");
ssize_t * above_icons_ids = current_list->icons_ids[ICONS_ABOVE];
ssize_t * visible_icons_ids = current_list->icons_ids[ICONS_VISIBLE];
ssize_t * under_icons_ids = current_list->icons_ids[ICONS_UNDER];
ssize_t * above_assoc_ids = current_list->assoc_entry_ids[ICONS_ABOVE];
ssize_t * visible_assoc_ids = current_list->assoc_entry_ids[ICONS_VISIBLE];
ssize_t * under_assoc_ids = current_list->assoc_entry_ids[ICONS_UNDER];
ssize_t id = current_list->texture_id_offset;
int starti = current_list->scroll;
memset(visible_icons_ids, 0, ENTRIES_PER_SCREEN*sizeof(ssize_t));
for(int i = starti; i < starti+ENTRIES_PER_SCREEN; i++, id++)
{
if(i >= current_list->entries_count) break;
Entry_s current_entry = current_list->entries[i];
load_smdh_icon(current_entry, id);
visible_icons_ids[i-starti] = id;
visible_assoc_ids[i-starti] = i;
}
memset(above_icons_ids, 0, ENTRIES_PER_SCREEN*sizeof(ssize_t));
starti -= ENTRIES_PER_SCREEN;
for(int i = starti; i < starti+ENTRIES_PER_SCREEN; i++, id++)
{
if(i >= current_list->entries_count) break;
int used_i = i;
if(i < 0)
used_i = current_list->entries_count + i;
Entry_s current_entry = current_list->entries[used_i];
load_smdh_icon(current_entry, id);
above_icons_ids[i-starti] = id;
above_assoc_ids[i-starti] = used_i;
}
memset(under_icons_ids, 0, ENTRIES_PER_SCREEN*sizeof(ssize_t));
starti += ENTRIES_PER_SCREEN*2;
for(int i = starti; i < starti+ENTRIES_PER_SCREEN; i++, id++)
{
int used_i = i;
if(i >= current_list->entries_count)
used_i = i - current_list->entries_count;
Entry_s current_entry = current_list->entries[used_i];
load_smdh_icon(current_entry, id);
under_icons_ids[i-starti] = id;
under_assoc_ids[i-starti] = used_i;
}
}
void load_icons_first(Entry_List_s * current_list, bool silent)
{
if(current_list == NULL || current_list->entries == NULL) return;
if(!silent) if(!silent)
draw_install(INSTALL_LOADING_ICONS); draw_install(INSTALL_LOADING_ICONS);
if(current_list->entries_count <= ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT) int starti = 0, endi = 0;
small_load(current_list); // if the list is one that doesnt need swapping, load everything at once
if(list->entries_count <= ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT)
{
DEBUG("small load\n");
// if the list is one that doesnt need swapping, load everything at once
endi = list->entries_count;
}
else else
first_load(current_list); {
DEBUG("extended load\n");
// otherwise, load around to prepare for swapping
starti = list->scroll - ENTRIES_PER_SCREEN*ICONS_VISIBLE;
endi = starti + ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT;
}
ssize_t * icon_ids = (ssize_t *)list->icons_ids;
ssize_t id = list->texture_id_offset;
memset(icon_ids, 0, ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT*sizeof(ssize_t));
for(int i = starti; i < endi; i++, id++)
{
int offset = i;
if(offset < 0)
offset += list->entries_count;
if(offset >= list->entries_count)
offset -= list->entries_count;
Entry_s current_entry = list->entries[offset];
load_smdh_icon(current_entry, id);
icon_ids[i-starti] = id;
}
} }
static void reverse(ssize_t a[], int sz) { static void reverse(ssize_t a[], int sz) {
@@ -269,18 +225,71 @@ static void rotate(ssize_t array[], int size, int amt) {
reverse(array, size-1); reverse(array, size-1);
} }
void handle_scrolling(Entry_List_s * list)
{
// Scroll the menu up or down if the selected theme is out of its bounds
//----------------------------------------------------------------
if(list->entries_count > ENTRIES_PER_SCREEN)
{
for(int i = 0; i < list->entries_count; i++)
{
int change = 0;
if(list->entries_count > ENTRIES_PER_SCREEN*2 && list->previous_scroll < ENTRIES_PER_SCREEN && list->selected_entry >= list->entries_count - ENTRIES_PER_SCREEN)
{
list->scroll = list->entries_count - ENTRIES_PER_SCREEN;
}
else if(list->entries_count > ENTRIES_PER_SCREEN*2 && list->selected_entry < ENTRIES_PER_SCREEN && list->previous_selected >= list->entries_count - ENTRIES_PER_SCREEN)
{
list->scroll = 0;
}
else if(list->selected_entry == list->previous_selected+1 && list->selected_entry == list->scroll+ENTRIES_PER_SCREEN)
{
change = 1;
}
else if(list->selected_entry == list->previous_selected-1 && list->selected_entry == list->scroll-1)
{
change = -1;
}
else if(list->selected_entry == list->previous_selected+ENTRIES_PER_SCREEN || list->selected_entry >= list->scroll + ENTRIES_PER_SCREEN)
{
change = ENTRIES_PER_SCREEN;
}
else if(list->selected_entry == list->previous_selected-ENTRIES_PER_SCREEN || list->selected_entry < list->scroll)
{
change = -ENTRIES_PER_SCREEN;
}
list->scroll += change;
if(list->scroll < 0)
list->scroll = 0;
else if(list->scroll > list->entries_count - ENTRIES_PER_SCREEN)
list->scroll = list->entries_count - ENTRIES_PER_SCREEN;
if(!change)
list->previous_selected = list->selected_entry;
else
list->previous_selected += change;
}
}
//----------------------------------------------------------------
}
static void load_icons(Entry_List_s * current_list) static void load_icons(Entry_List_s * current_list)
{ {
if(current_list == NULL || current_list->entries == NULL) if(current_list == NULL || current_list->entries == NULL)
return; return;
handle_scrolling(current_list);
if(current_list->entries_count <= ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT || current_list->previous_scroll == current_list->scroll) if(current_list->entries_count <= ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT || current_list->previous_scroll == current_list->scroll)
return; // return if the list is one that doesnt need swapping, or if nothing changed return; // return if the list is one that doesnt need swapping, or if nothing changed
#define SIGN(x) (x > 0 ? 1 : ((x < 0) ? -1 : 0)) #define SIGN(x) (x > 0 ? 1 : ((x < 0) ? -1 : 0))
int delta = current_list->scroll - current_list->previous_scroll; int delta = current_list->scroll - current_list->previous_scroll;
if(abs(delta) >= current_list->entries_count - ENTRIES_PER_SCREEN*2) if(abs(delta) >= current_list->entries_count - ENTRIES_PER_SCREEN*(ICONS_OFFSET_AMOUNT-1))
delta = -SIGN(delta) * (current_list->entries_count - abs(delta)); delta = -SIGN(delta) * (current_list->entries_count - abs(delta));
int starti = current_list->scroll; int starti = current_list->scroll;
@@ -300,27 +309,23 @@ static void load_icons(Entry_List_s * current_list)
#define LAST(arr) arr[ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT - 1] #define LAST(arr) arr[ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT - 1]
ssize_t * icons_ids = (ssize_t *)current_list->icons_ids; ssize_t * icons_ids = (ssize_t *)current_list->icons_ids;
ssize_t * assoc_entry_ids = (ssize_t *)current_list->assoc_entry_ids;
for(int i = starti; i != endi; i++, ctr++) for(int i = starti; i != endi; i++, ctr++)
{ {
ssize_t id = 0; ssize_t id = 0;
int offset = i; int offset = i;
ssize_t * assoc = NULL;
rotate(icons_ids, 3*ENTRIES_PER_SCREEN, -1*SIGN(delta)); rotate(icons_ids, ICONS_OFFSET_AMOUNT*ENTRIES_PER_SCREEN, -1*SIGN(delta));
if(delta > 0) if(delta > 0)
{ {
id = LAST(icons_ids); id = LAST(icons_ids);
assoc = &LAST(assoc_entry_ids); offset += ENTRIES_PER_SCREEN*ICONS_UNDER - delta;
offset += ENTRIES_PER_SCREEN*2 - delta;
} }
else else
{ {
id = FIRST(icons_ids); id = FIRST(icons_ids);
assoc = &FIRST(assoc_entry_ids); offset -= ENTRIES_PER_SCREEN*ICONS_VISIBLE;
offset -= ENTRIES_PER_SCREEN;
i -= 2; //i-- twice to counter the i++, needed only for this case i -= 2; //i-- twice to counter the i++, needed only for this case
} }
@@ -331,7 +336,6 @@ static void load_icons(Entry_List_s * current_list)
entries[ctr] = &current_list->entries[offset]; entries[ctr] = &current_list->entries[offset];
ids[ctr] = id; ids[ctr] = id;
*assoc = id;
} }
#undef FIRST #undef FIRST
@@ -341,9 +345,13 @@ static void load_icons(Entry_List_s * current_list)
svcSleepThread(1e6); svcSleepThread(1e6);
for(int i = 0; i < abs(delta); i++) for(int i = 0; i < abs(delta); i++)
load_smdh_icon(*entries[i], ids[i]); load_smdh_icon(*entries[i], ids[i]);
free(entries);
free(ids);
current_list->previous_scroll = current_list->scroll;
} }
static bool loading_icons = false;
void load_icons_thread(void * void_arg) void load_icons_thread(void * void_arg)
{ {
Thread_Arg_s * arg = (Thread_Arg_s *)void_arg; Thread_Arg_s * arg = (Thread_Arg_s *)void_arg;
@@ -352,11 +360,8 @@ void load_icons_thread(void * void_arg)
{ {
svcWaitSynchronization(update_request, U64_MAX); svcWaitSynchronization(update_request, U64_MAX);
svcClearEvent(update_request); svcClearEvent(update_request);
if(loading_icons) continue;
loading_icons = true;
volatile Entry_List_s * current_list = *(volatile Entry_List_s **)arg->thread_arg[0]; volatile Entry_List_s * current_list = *(volatile Entry_List_s **)arg->thread_arg[0];
load_icons((Entry_List_s *)current_list); load_icons((Entry_List_s *)current_list);
loading_icons = false;
} }
while(arg->run_thread); while(arg->run_thread);
} }

View File

@@ -34,7 +34,7 @@
#include "pp2d/pp2d/pp2d.h" #include "pp2d/pp2d/pp2d.h"
#include <time.h> #include <time.h>
#define FASTSCROLL_WAIT 1e8 #define FASTSCROLL_WAIT 1.5e8
static bool homebrew = false; static bool homebrew = false;
static bool installed_themes = false; static bool installed_themes = false;
@@ -88,7 +88,6 @@ static void stop_install_check(void)
if(installCheckThreads_arg[i].run_thread) if(installCheckThreads_arg[i].run_thread)
{ {
installCheckThreads_arg[i].run_thread = false; installCheckThreads_arg[i].run_thread = false;
threadJoin(installCheckThreads[i], U64_MAX);
} }
} }
} }
@@ -183,45 +182,6 @@ static void jump_menu(Entry_List_s * list)
} }
} }
static void handle_scrolling(Entry_List_s * list)
{
// Scroll the menu up or down if the selected theme is out of its bounds
//----------------------------------------------------------------
if(list->entries_count > ENTRIES_PER_SCREEN)
{
if(list->entries_count > ENTRIES_PER_SCREEN*2 && list->previous_scroll < ENTRIES_PER_SCREEN && list->selected_entry >= list->entries_count - ENTRIES_PER_SCREEN)
{
list->scroll = list->entries_count - ENTRIES_PER_SCREEN;
}
else if(list->entries_count > ENTRIES_PER_SCREEN*2 && list->selected_entry < ENTRIES_PER_SCREEN && list->previous_selected >= list->entries_count - ENTRIES_PER_SCREEN)
{
list->scroll = 0;
}
else if(list->selected_entry == list->previous_selected+1 && list->selected_entry == list->scroll+ENTRIES_PER_SCREEN)
{
list->scroll++;
}
else if(list->selected_entry == list->previous_selected-1 && list->selected_entry == list->scroll-1)
{
list->scroll--;
}
else if(list->selected_entry == list->previous_selected+ENTRIES_PER_SCREEN || list->selected_entry >= list->scroll + ENTRIES_PER_SCREEN)
{
list->scroll += ENTRIES_PER_SCREEN;
}
else if(list->selected_entry == list->previous_selected-ENTRIES_PER_SCREEN || list->selected_entry < list->scroll)
{
list->scroll -= ENTRIES_PER_SCREEN;
}
if(list->scroll < 0)
list->scroll = 0;
if(list->scroll > list->entries_count - ENTRIES_PER_SCREEN)
list->scroll = list->entries_count - ENTRIES_PER_SCREEN;
}
//----------------------------------------------------------------
}
static void change_selected(Entry_List_s * list, int change_value) static void change_selected(Entry_List_s * list, int change_value)
{ {
if(abs(change_value) >= list->entries_count) return; if(abs(change_value) >= list->entries_count) return;
@@ -348,12 +308,16 @@ int main(void)
if(qr_mode) take_picture(); if(qr_mode) take_picture();
else if(preview_mode) draw_preview(preview_offset); else if(preview_mode) draw_preview(preview_offset);
else { else {
if(!iconLoadingThread_arg.run_thread)
{
handle_scrolling(current_list); handle_scrolling(current_list);
svcSignalEvent(update_icons_handle);
svcSleepThread(1e6);
current_list->previous_scroll = current_list->scroll; current_list->previous_scroll = current_list->scroll;
current_list->previous_selected = current_list->selected_entry; }
else
{
svcSignalEvent(update_icons_handle);
svcSleepThread(5e6);
}
draw_interface(current_list, instructions); draw_interface(current_list, instructions);
svcSleepThread(1e7); svcSleepThread(1e7);
@@ -606,12 +570,10 @@ int main(void)
else if(kDown & KEY_LEFT) else if(kDown & KEY_LEFT)
{ {
change_selected(current_list, -ENTRIES_PER_SCREEN); change_selected(current_list, -ENTRIES_PER_SCREEN);
load_icons_first(current_list, true);
} }
else if(kDown & KEY_RIGHT) else if(kDown & KEY_RIGHT)
{ {
change_selected(current_list, ENTRIES_PER_SCREEN); change_selected(current_list, ENTRIES_PER_SCREEN);
load_icons_first(current_list, true);
} }
// Fast scroll using circle pad // Fast scroll using circle pad
@@ -657,7 +619,6 @@ int main(void)
if(BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll > 0) if(BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll > 0)
{ {
change_selected(current_list, -ENTRIES_PER_SCREEN); change_selected(current_list, -ENTRIES_PER_SCREEN);
load_icons_first(current_list, true);
} }
else if(BETWEEN(320-24, x, 320)) else if(BETWEEN(320-24, x, 320))
{ {
@@ -685,7 +646,6 @@ int main(void)
if(BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll < current_list->entries_count - ENTRIES_PER_SCREEN) if(BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll < current_list->entries_count - ENTRIES_PER_SCREEN)
{ {
change_selected(current_list, ENTRIES_PER_SCREEN); change_selected(current_list, ENTRIES_PER_SCREEN);
load_icons_first(current_list, true);
} }
else if(BETWEEN(176, x, 320)) else if(BETWEEN(176, x, 320))
{ {