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

@@ -167,89 +167,45 @@ Result load_entries(const char * loading_path, Entry_List_s * list, EntryMode mo
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");
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(list == NULL || list->entries == NULL) return;
if(!silent)
draw_install(INSTALL_LOADING_ICONS);
if(current_list->entries_count <= ENTRIES_PER_SCREEN*ICONS_OFFSET_AMOUNT)
small_load(current_list); // if the list is one that doesnt need swapping, load everything at once
int starti = 0, endi = 0;
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
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) {
@@ -269,18 +225,71 @@ static void rotate(ssize_t array[], int size, int amt) {
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)
{
if(current_list == NULL || current_list->entries == NULL)
return;
handle_scrolling(current_list);
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
#define SIGN(x) (x > 0 ? 1 : ((x < 0) ? -1 : 0))
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));
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]
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++)
{
ssize_t id = 0;
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)
{
id = LAST(icons_ids);
assoc = &LAST(assoc_entry_ids);
offset += ENTRIES_PER_SCREEN*2 - delta;
offset += ENTRIES_PER_SCREEN*ICONS_UNDER - delta;
}
else
{
id = FIRST(icons_ids);
assoc = &FIRST(assoc_entry_ids);
offset -= ENTRIES_PER_SCREEN;
offset -= ENTRIES_PER_SCREEN*ICONS_VISIBLE;
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];
ids[ctr] = id;
*assoc = id;
}
#undef FIRST
@@ -341,9 +345,13 @@ static void load_icons(Entry_List_s * current_list)
svcSleepThread(1e6);
for(int i = 0; i < abs(delta); 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)
{
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);
svcClearEvent(update_request);
if(loading_icons) continue;
loading_icons = true;
volatile Entry_List_s * current_list = *(volatile Entry_List_s **)arg->thread_arg[0];
load_icons((Entry_List_s *)current_list);
loading_icons = false;
}
while(arg->run_thread);
}