diff --git a/include/camera.h b/include/camera.h index 9fa53bf..07beefa 100644 --- a/include/camera.h +++ b/include/camera.h @@ -30,22 +30,24 @@ #include "common.h" typedef struct { - u16 *camera_buffer; - C2D_Image image; - C3D_Tex *tex; - Handle mutex; - volatile bool finished; - volatile bool closed; - volatile bool success; - Handle cancel; - Handle started; + u16* camera_buffer; + + Handle event_stop; + Thread cam_thread, ui_thread; + + LightEvent event_cam_info, event_ui_info; + + CondVar cond; + LightLock mut; + u32 num_readers_active; + bool writer_waiting; + bool writer_active; + + bool any_update; - bool capturing; struct quirc* context; } qr_data; bool init_qr(void); -void exit_qr(qr_data *data); -void take_picture(void); #endif diff --git a/include/loading.h b/include/loading.h index ea472d9..2a8b072 100644 --- a/include/loading.h +++ b/include/loading.h @@ -65,7 +65,7 @@ typedef struct { u16 desc[0x81]; u16 author[0x41]; - u32 placeholder_color; + // u32 placeholder_color; u16 path[0x106]; bool is_zip; diff --git a/source/camera.c b/source/camera.c index f050afa..57d3583 100644 --- a/source/camera.c +++ b/source/camera.c @@ -36,28 +36,63 @@ #include #include -void exit_qr(qr_data *data) +static void start_read(qr_data *data) { - DEBUG("Exiting QR\n"); - svcSignalEvent(data->cancel); - while(!data->finished) - svcSleepThread(1000000); - svcCloseHandle(data->cancel); - data->capturing = false; + LightLock_Lock(&data->mut); + while(data->writer_waiting || data->writer_active) + { + CondVar_Wait(&data->cond, &data->mut); + } - free(data->camera_buffer); - free(data->tex); - quirc_destroy(data->context); + AtomicIncrement(&data->num_readers_active); + LightLock_Unlock(&data->mut); +} +static void stop_read(qr_data *data) +{ + LightLock_Lock(&data->mut); + AtomicDecrement(&data->num_readers_active); + if(data->num_readers_active == 0) + { + CondVar_Signal(&data->cond); + } + LightLock_Unlock(&data->mut); +} +static void start_write(qr_data *data) +{ + LightLock_Lock(&data->mut); + data->writer_waiting = true; + + while(data->num_readers_active) + { + CondVar_Wait(&data->cond, &data->mut); + } + + data->writer_waiting = false; + data->writer_active = true; + + LightLock_Unlock(&data->mut); +} +static void stop_write(qr_data *data) +{ + LightLock_Lock(&data->mut); + + data->writer_active = false; + CondVar_Broadcast(&data->cond); + + LightLock_Unlock(&data->mut); } -void capture_cam_thread(void *arg) +static void capture_cam_thread(void *arg) { qr_data *data = (qr_data *) arg; - Handle events[3] = {0}; - events[0] = data->cancel; - u32 transferUnit; - u16 *buffer = calloc(1, 400 * 240 * sizeof(u16)); + Handle cam_events[3] = {0}; + cam_events[0] = data->event_stop; + + u32 transferUnit; + const u32 bufsz = 400 * 240 * sizeof(u16); + u16 *buffer = linearAlloc(bufsz); + camInit(); CAMU_SetSize(SELECT_OUT1, SIZE_CTR_TOP_LCD, CONTEXT_A); CAMU_SetOutputFormat(SELECT_OUT1, OUTPUT_RGB_565, CONTEXT_A); @@ -66,38 +101,42 @@ void capture_cam_thread(void *arg) CAMU_SetAutoExposure(SELECT_OUT1, true); CAMU_SetAutoWhiteBalance(SELECT_OUT1, true); CAMU_Activate(SELECT_OUT1); - CAMU_GetBufferErrorInterruptEvent(&events[2], PORT_CAM1); + CAMU_GetBufferErrorInterruptEvent(&cam_events[2], PORT_CAM1); CAMU_SetTrimming(PORT_CAM1, false); CAMU_GetMaxBytes(&transferUnit, 400, 240); CAMU_SetTransferBytes(PORT_CAM1, transferUnit, 400, 240); CAMU_ClearBuffer(PORT_CAM1); - CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), (s16) transferUnit); + CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit); CAMU_StartCapture(PORT_CAM1); - svcSignalEvent(data->started); + bool cancel = false; - while (!cancel) + + while (!cancel) { s32 index = 0; - svcWaitSynchronizationN(&index, events, 3, false, U64_MAX); + svcWaitSynchronizationN(&index, cam_events, 3, false, U64_MAX); switch(index) { case 0: DEBUG("Cancel event received\n"); cancel = true; break; case 1: - svcCloseHandle(events[1]); - events[1] = 0; - svcWaitSynchronization(data->mutex, U64_MAX); - memcpy(data->camera_buffer, buffer, 400 * 240 * sizeof(u16)); - GSPGPU_FlushDataCache(data->camera_buffer, 400 * 240 * sizeof(u16)); - svcReleaseMutex(data->mutex); - CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit); + svcCloseHandle(cam_events[1]); + cam_events[1] = 0; + + start_write(data); + memcpy(data->camera_buffer, buffer, bufsz); + data->any_update = true; + stop_write(data); + + CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit); break; case 2: - svcCloseHandle(events[1]); - events[1] = 0; + svcCloseHandle(cam_events[1]); + cam_events[1] = 0; + CAMU_ClearBuffer(PORT_CAM1); - CAMU_SetReceiving(&events[1], buffer, PORT_CAM1, 400 * 240 * sizeof(u16), transferUnit); + CAMU_SetReceiving(&cam_events[1], buffer, PORT_CAM1, bufsz, transferUnit); CAMU_StartCapture(PORT_CAM1); break; default: @@ -115,221 +154,261 @@ void capture_cam_thread(void *arg) CAMU_ClearBuffer(PORT_CAM1); CAMU_Activate(SELECT_NONE); camExit(); - free(buffer); - for(int i = 1; i < 3; i++) { - if(events[i] != 0) { - svcCloseHandle(events[i]); - events[i] = 0; + + linearFree(buffer); + for(int i = 1; i < 3; i++) + { + if(cam_events[i] != 0) { + svcCloseHandle(cam_events[i]); + cam_events[i] = 0; } } - svcCloseHandle(data->mutex); - data->finished = true; + + LightEvent_Signal(&data->event_cam_info); } -void update_ui(void *arg) +static void update_ui(void *arg) { qr_data* data = (qr_data*) arg; + C3D_Tex tex; - while (!data->finished) + static const Tex3DS_SubTexture subt3x = { 400, 240, 0.0f, 1.0f, 400.0f/512.0f, 1.0f - (240.0f/256.0f) }; + C3D_TexInit(&tex, 512, 256, GPU_RGB565); + + C3D_TexSetFilter(&tex, GPU_LINEAR, GPU_LINEAR); + + while(svcWaitSynchronization(data->event_stop, 2 * 1000 * 1000ULL) == 0x09401BFE) // timeout of 2ms occured, still have 14 for copy and render { draw_base_interface(); // Untiled texture loading code adapted from FBI - svcWaitSynchronization(data->mutex, U64_MAX); - for(u32 x = 0; x < 400 && !data->finished; x++) { - for(u32 y = 0; y < 256 && !data->finished; y++) { - u32 dstPos = ((((y >> 3) * (512 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))) * sizeof(u16); - u32 srcPos = (y * 400 + x) * sizeof(u16); - - memcpy(&((u8*) data->image.tex->data)[dstPos], &((u8*) data->camera_buffer)[srcPos], sizeof(u16)); - } - } - - svcReleaseMutex(data->mutex); - - if (data->finished) + start_read(data); + if(data->any_update) { - end_frame(); - break; - } + for(u32 y = 0; y < 240; y++) { + const u32 srcPos = y * 400; + for(u32 x = 0; x < 400; x++) { + const u32 dstPos = ((((y >> 3) * (512 >> 3) + (x >> 3)) << 6) + ((x & 1) | ((y & 1) << 1) | ((x & 2) << 1) | ((y & 2) << 2) | ((x & 4) << 2) | ((y & 4) << 3))); - C2D_DrawImageAt(data->image, 0.0f, 0.0f, 0.4f, NULL, 1.0f, 1.0f); + ((u16*)tex.data)[dstPos] = data->camera_buffer[srcPos + x]; + } + } + data->any_update = false; + } + stop_read(data); + + C2D_DrawImageAt((C2D_Image){ &tex, &subt3x }, 0.0f, 0.0f, 0.4f, NULL, 1.0f, 1.0f); set_screen(bottom); draw_text_center(GFX_BOTTOM, 4, 0.5, 0.5, 0.5, colors[COLOR_WHITE], "Press \uE005 To Quit"); end_frame(); } - data->closed = true; + + C3D_TexDelete(&tex); + LightEvent_Signal(&data->event_ui_info); } -bool start_capture_cam(qr_data *data) +static bool start_capture_cam(qr_data *data) { - data->mutex = 0; - data->cancel = 0; - svcCreateEvent(&data->cancel, RESET_STICKY); - svcCreateMutex(&data->mutex, false); - if(threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, true) == NULL) + if((data->cam_thread = threadCreate(capture_cam_thread, data, 0x10000, 0x1A, 1, false)) == NULL) { throw_error("Capture cam thread creation failed\nPlease report this to the developers", ERROR_LEVEL_ERROR); + LightEvent_Signal(&data->event_cam_info); + LightEvent_Signal(&data->event_ui_info); return false; } - svcWaitSynchronization(data->started, U64_MAX); - if(threadCreate(update_ui, data, 0x10000, 0x1A, 1, true) == NULL) + if((data->ui_thread = threadCreate(update_ui, data, 0x10000, 0x1A, 1, false)) == NULL) { - exit_qr(data); + LightEvent_Signal(&data->event_ui_info); return false; } return true; } -void update_qr(qr_data *data) +static bool update_qr(qr_data *data, struct quirc_data* scan_data) { - hidScanInput(); - if (hidKeysDown() & (KEY_R | KEY_B | KEY_TOUCH)) { - exit_qr(data); - return; - } - - if (!data->capturing) { - if(start_capture_cam(data)) - data->capturing = true; - else { - exit_qr(data); - return; - } - - } - - if (data->finished) { - exit_qr(data); - return; - } - int w; int h; u8 *image = (u8*) quirc_begin(data->context, &w, &h); - for (ssize_t x = 0; x < w; x++) { - for (ssize_t y = 0; y < h; y++) { - u16 px = data->camera_buffer[y * 400 + x]; - image[y * w + x] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); + + start_read(data); + for (int y = 0; y < h; y++) { + const int actual_y = y * w; + for (int x = 0; x < w; x++) { + const int actual_off = actual_y + x; + const u16 px = data->camera_buffer[actual_off]; + image[actual_off] = (u8)(((((px >> 11) & 0x1F) << 3) + (((px >> 5) & 0x3F) << 2) + ((px & 0x1F) << 3)) / 3); } } + stop_read(data); + quirc_end(data->context); if(quirc_count(data->context) > 0) { struct quirc_code code; - struct quirc_data scan_data; quirc_extract(data->context, 0, &code); - if (!quirc_decode(&code, &scan_data)) + if (!quirc_decode(&code, scan_data)) { - exit_qr(data); - - while (!data->finished) svcSleepThread(1000000); - - draw_install(INSTALL_DOWNLOAD); - char * zip_buf = NULL; - char * filename = NULL; - u32 zip_size = http_get((char*)scan_data.payload, &filename, &zip_buf, INSTALL_DOWNLOAD, "application/zip"); - - if(zip_size != 0) - { - draw_install(INSTALL_CHECKING_DOWNLOAD); - - struct archive *a = archive_read_new(); - archive_read_support_format_zip(a); - - int r = archive_read_open_memory(a, zip_buf, zip_size); - archive_read_free(a); - - if(r == ARCHIVE_OK) - { - EntryMode mode = MODE_AMOUNT; - - char * buf = NULL; - do { - if(zip_memory_to_buf("body_LZ.bin", zip_buf, zip_size, &buf) != 0) - { - mode = MODE_THEMES; - break; - } - - free(buf); - buf = NULL; - if(zip_memory_to_buf("splash.bin", zip_buf, zip_size, &buf) != 0) - { - mode = MODE_SPLASHES; - break; - } - - free(buf); - buf = NULL; - if(zip_memory_to_buf("splashbottom.bin", zip_buf, zip_size, &buf) != 0) - { - mode = MODE_SPLASHES; - break; - } - } - while(false); - - free(buf); - buf = NULL; - - if(mode != MODE_AMOUNT) - { - char path_to_file[0x107] = {0}; - sprintf(path_to_file, "%s%s", main_paths[mode], filename); - char * extension = strrchr(path_to_file, '.'); - if (extension == NULL || strcmp(extension, ".zip")) - strcat(path_to_file, ".zip"); - - remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size); - buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf); - data->success = true; - } - else - { - // TODO: handle more elegantly - throw_error("Zip downloaded is neither\na splash nor a theme.", ERROR_LEVEL_WARNING); - } - } - else - { - // TODO: marked for deletion - throw_error("File downloaded isn't a zip.", ERROR_LEVEL_WARNING); - } - free(zip_buf); - } - - free(filename); - } + return true; + } } + return false; +} + +static void start_qr(qr_data *data) +{ + svcCreateEvent(&data->event_stop, RESET_STICKY); + LightEvent_Init(&data->event_cam_info, RESET_STICKY); + LightEvent_Init(&data->event_ui_info, RESET_STICKY); + LightLock_Init(&data->mut); + CondVar_Init(&data->cond); + + data->cam_thread = NULL; + data->ui_thread = NULL; + data->any_update = false; + + data->context = quirc_new(); + quirc_resize(data->context, 400, 240); + data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16)); +} +static void exit_qr(qr_data *data) +{ + svcSignalEvent(data->event_stop); + + LightEvent_Wait(&data->event_ui_info); + LightEvent_Clear(&data->event_ui_info); + if(data->ui_thread != NULL) + { + threadJoin(data->ui_thread, U64_MAX); + threadFree(data->ui_thread); + data->ui_thread = NULL; + } + + LightEvent_Wait(&data->event_cam_info); + LightEvent_Clear(&data->event_cam_info); + if(data->cam_thread != NULL) + { + threadJoin(data->cam_thread, U64_MAX); + threadFree(data->cam_thread); + data->cam_thread = NULL; + } + + free(data->camera_buffer); + data->camera_buffer = NULL; + svcCloseHandle(data->event_stop); + data->event_stop = 0; } bool init_qr(void) { - qr_data *data = calloc(1, sizeof(qr_data)); - data->capturing = false; - data->finished = false; - data->closed = false; - svcCreateEvent(&data->started, RESET_STICKY); - - data->context = quirc_new(); - quirc_resize(data->context, 400, 240); + qr_data data; - data->camera_buffer = calloc(1, 400 * 240 * sizeof(u16)); + memset(&data, 0, sizeof(data)); - data->tex = (C3D_Tex*)malloc(sizeof(C3D_Tex)); - static const Tex3DS_SubTexture subt3x = { 512, 256, 0.0f, 1.0f, 1.0f, 0.0f }; - data->image = (C2D_Image){ data->tex, &subt3x }; - C3D_TexInit(data->image.tex, 512, 256, GPU_RGB565); - C3D_TexSetFilter(data->image.tex, GPU_LINEAR, GPU_LINEAR); + start_qr(&data); - while (!data->finished) update_qr(data); - bool success = data->success; - while (!data->closed) svcSleepThread(1000000); - svcCloseHandle(data->started); - free(data); + struct quirc_data* scan_data = calloc(1, sizeof(struct quirc_data)); + const bool ready = start_capture_cam(&data); + bool finished = !ready; + while(!finished) + { + hidScanInput(); + if (hidKeysDown() & (KEY_R | KEY_B | KEY_TOUCH)) + { + break; + } + + finished = update_qr(&data, scan_data); + svcSleepThread(50 * 1000 * 1000ULL); // only scan every 50ms + } + + exit_qr(&data); + + bool success = false; + if(finished && ready) + { + draw_install(INSTALL_DOWNLOAD); + char * zip_buf = NULL; + char * filename = NULL; + u32 zip_size = http_get((char*)scan_data->payload, &filename, &zip_buf, INSTALL_DOWNLOAD); + + if(zip_size != 0) + { + draw_install(INSTALL_CHECKING_DOWNLOAD); + + struct archive *a = archive_read_new(); + archive_read_support_format_zip(a); + + int r = archive_read_open_memory(a, zip_buf, zip_size); + archive_read_free(a); + + if(r == ARCHIVE_OK) + { + EntryMode mode = MODE_AMOUNT; + + char * buf = NULL; + do { + if(zip_memory_to_buf("body_LZ.bin", zip_buf, zip_size, &buf) != 0) + { + mode = MODE_THEMES; + break; + } + + free(buf); + buf = NULL; + if(zip_memory_to_buf("splash.bin", zip_buf, zip_size, &buf) != 0) + { + mode = MODE_SPLASHES; + break; + } + + free(buf); + buf = NULL; + if(zip_memory_to_buf("splashbottom.bin", zip_buf, zip_size, &buf) != 0) + { + mode = MODE_SPLASHES; + break; + } + } + while(false); + + free(buf); + buf = NULL; + + if(mode != MODE_AMOUNT) + { + char path_to_file[0x107] = {0}; + sprintf(path_to_file, "%s%s", main_paths[mode], filename); + char * extension = strrchr(path_to_file, '.'); + if (extension == NULL || strcmp(extension, ".zip")) + strcat(path_to_file, ".zip"); + + remake_file(fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_size); + buf_to_file(zip_size, fsMakePath(PATH_ASCII, path_to_file), ArchiveSD, zip_buf); + success = true; + } + else + { + throw_error("Zip downloaded is neither\na splash nor a theme.", ERROR_LEVEL_WARNING); + } + } + else + { + throw_error("File downloaded isn't a zip.", ERROR_LEVEL_WARNING); + } + free(zip_buf); + } + else + { + throw_error("Download failed.", ERROR_LEVEL_WARNING); + } + + free(filename); + } + + free(scan_data); + quirc_destroy(data.context); return success; } diff --git a/source/draw.c b/source/draw.c index cf2ab8e..ee81dbb 100644 --- a/source/draw.c +++ b/source/draw.c @@ -552,13 +552,18 @@ void draw_grid_interface(Entry_List_s* list, Instructions_s instructions) vertical_offset += 24; horizontal_offset += 16; + // theoretically impossible to have no icon when from the api + /* if(!current_entry->placeholder_color) { + */ C2D_Image * image = list->icons[i]; C2D_DrawImageAt(*image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); + /* } else C2D_DrawRectSolid(horizontal_offset, vertical_offset, 0.5f, list->entry_size, list->entry_size, current_entry->placeholder_color); + */ if(i == selected_entry) { @@ -713,19 +718,24 @@ void draw_interface(Entry_List_s* list, Instructions_s instructions) C2D_DrawSpriteTinted(&sprite_installed, &tint); } + // no icons not allowed anymore + /* if(!current_entry->placeholder_color) { + */ C2D_Image * image = NULL; if(list->entries_count > list->entries_loaded*ICONS_OFFSET_AMOUNT) image = list->icons[ICONS_VISIBLE*list->entries_loaded + (i - list->scroll)]; else image = list->icons[i]; C2D_DrawImageAt(*image, horizontal_offset, vertical_offset, 0.5f, NULL, 1.0f, 1.0f); + /* } else { C2D_DrawRectSolid(horizontal_offset, vertical_offset, 0.5f, list->entry_size, list->entry_size, current_entry->placeholder_color); } + */ } char entries_count_str[0x20] = {0}; diff --git a/source/loading.c b/source/loading.c index 61556c5..138d5c3 100644 --- a/source/loading.c +++ b/source/loading.c @@ -83,6 +83,7 @@ C2D_Image * loadTextureIcon(Icon_s *icon) void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name) { + /* if(icon == NULL) { memcpy(entry->name, fallback_name, 0x80); @@ -91,28 +92,13 @@ void parse_smdh(Icon_s *icon, Entry_s * entry, const u16 * fallback_name) entry->placeholder_color = C2D_Color32(rand() % 255, rand() % 255, rand() % 255, 255); return; } + */ memcpy(entry->name, icon->name, 0x40*sizeof(u16)); memcpy(entry->desc, icon->desc, 0x80*sizeof(u16)); memcpy(entry->author, icon->author, 0x40*sizeof(u16)); } -static void parse_entry_smdh(Entry_s * entry, const u16 * fallback_name) -{ - char *info_buffer = NULL; - u64 size = load_data("/info.smdh", *entry, &info_buffer); - - if(!size) - { - free(info_buffer); - info_buffer = NULL; - } - - Icon_s * smdh = (Icon_s *)info_buffer; - - parse_smdh(smdh, entry, fallback_name); -} - static C2D_Image * load_entry_icon(Entry_s entry) { char *info_buffer = NULL; @@ -120,7 +106,9 @@ static C2D_Image * load_entry_icon(Entry_s entry) if(!size) return NULL; Icon_s * smdh = (Icon_s *)info_buffer; - return loadTextureIcon(smdh); + C2D_Image* out = loadTextureIcon(smdh); + free(info_buffer); + return out; } typedef int (*sort_comparator)(const void *, const void *); @@ -202,20 +190,21 @@ Result load_entries(const char * loading_path, Entry_List_s * list) } else { + const ssize_t len = strulen(path, 0x106); struacat(path, "/info.smdh"); u32 size = file_to_buf(fsMakePath(PATH_UTF16, path), ArchiveSD, &buf); if (size == 0) continue; + memset(&path[len], 0, (0x106 - len) * sizeof(u16)); } - free(buf); list->entries_count++; Entry_s * new_list = realloc(list->entries, list->entries_count * sizeof(Entry_s)); if(new_list == NULL) { - free(list->entries); - list->entries = NULL; - res = -1; - DEBUG("break\n"); + // out of memory: still allow use of currently loaded entries. + // Many things might die, depending on the heap layout after + list->entries_count--; + free(buf); break; } else @@ -223,12 +212,11 @@ Result load_entries(const char * loading_path, Entry_List_s * list) Entry_s * current_entry = &(list->entries[list->entries_count-1]); memset(current_entry, 0, sizeof(Entry_s)); + parse_smdh((Icon_s *)buf, current_entry, dir_entry.name); + free(buf); - struacat(current_entry->path, loading_path); - strucat(current_entry->path, dir_entry.name); - + memcpy(current_entry->path, path, 0x106 * sizeof(u16)); current_entry->is_zip = !strcmp(dir_entry.shortExt, "ZIP"); - parse_entry_smdh(current_entry, dir_entry.name); } FSDIR_Close(dir_handle); diff --git a/source/main.c b/source/main.c index a89e66b..8cb3bad 100644 --- a/source/main.c +++ b/source/main.c @@ -359,7 +359,6 @@ int main(void) bool preview_mode = false; int preview_offset = 0; - bool qr_mode = false; bool install_mode = false; bool extra_mode = false; C2D_Image preview = {0}; @@ -407,7 +406,6 @@ int main(void) instructions = extra_instructions[index]; } - if(qr_mode) take_picture(); else if(preview_mode) { draw_preview(preview, preview_offset); @@ -440,14 +438,14 @@ int main(void) if(!install_mode && !extra_mode) { - if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes + if(!preview_mode && kDown & KEY_L) //toggle between splashes and themes { switch_mode: current_mode++; current_mode %= MODE_AMOUNT; continue; } - else if(!qr_mode && !preview_mode && kDown & KEY_R) //toggle QR mode + else if(!preview_mode && kDown & KEY_R) //toggle QR mode { enable_qr: draw_base_interface(); @@ -480,7 +478,7 @@ int main(void) continue; } - else if(!qr_mode && kDown & KEY_Y && current_list->entries != NULL) //toggle preview mode + else if(kDown & KEY_Y && current_list->entries != NULL) //toggle preview mode { toggle_preview: if(!preview_mode) @@ -525,7 +523,7 @@ int main(void) } } - if(qr_mode || preview_mode || current_list->entries == NULL) + if(preview_mode || current_list->entries == NULL) goto touch; int selected_entry = current_list->selected_entry;