/* * This file is part of Anemone3DS * Copyright (C) 2016-2017 Alex Taber ("astronautlevel"), Dawid Eckert ("daedreth") * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Additional Terms 7.b and 7.c of GPLv3 apply to this file: * * Requiring preservation of specified reasonable legal notices or * author attributions in that material or in the Appropriate Legal * Notices displayed by works containing it. * * Prohibiting misrepresentation of the origin of that material, * or requiring that modified versions of such material be marked in * reasonable ways as different from the original version. */ #include "fs.h" #include "loading.h" #include "themes.h" #include "splashes.h" #include "draw.h" #include "camera.h" #include "instructions.h" #include "pp2d/pp2d/pp2d.h" #include #define FASTSCROLL_WAIT 1e8 static bool homebrew = false; int __stacksize__ = 64 * 1024; Result archive_result; const char * main_paths[MODE_AMOUNT] = { "/Themes/", "/Splashes/", }; void init_services(void) { consoleDebugInit(debugDevice_SVC); cfguInit(); ptmuInit(); acInit(); httpcInit(0); archive_result = open_archives(); if(envIsHomebrew()) { s64 out; svcGetSystemInfo(&out, 0x10000, 0); homebrew = !out; } } void exit_services(void) { close_archives(); cfguExit(); ptmuExit(); httpcExit(); acExit(); } void exit_function(void) { exit_screens(); exit_services(); if(homebrew) { APT_HardwareResetAsync(); } else { srvPublishToSubscriber(0x202, 0); } } void change_selected(Entry_List_s * list, int change_value) { list->selected_entry += change_value; if(change_value < 0 && list->selected_entry < 0) list->selected_entry = list->entries_count - 1; else list->selected_entry %= list->entries_count; } void load_lists(Entry_List_s * lists) { DEBUG("origin: %u\n", TEXTURE_ICON); ssize_t last_icon_id = TEXTURE_ICON; for(int i = 0; i < MODE_AMOUNT; i++) { Entry_List_s * current_list = &lists[i]; last_icon_id += current_list->entries_count; free(current_list->entries); memset(current_list, 0, sizeof(Entry_List_s)); } pp2d_free_texture(last_icon_id); DEBUG("max: %u\n", last_icon_id); ssize_t icon_id_start = TEXTURE_ICON; for(int i = 0; i < MODE_AMOUNT; i++) { Entry_List_s * current_list = &lists[i]; current_list->icon_id_start = icon_id_start; load_entries(main_paths[i], current_list); icon_id_start += current_list->entries_count; } DEBUG("end: %u\n", icon_id_start); } int main(void) { srand(time(NULL)); init_services(); init_screens(); Entry_List_s lists[MODE_AMOUNT] = {0}; load_lists(lists); EntryMode current_mode = MODE_THEMES; bool preview_mode = false; int preview_offset = 0; bool qr_mode = false; bool install_mode = false; while(aptMainLoop()) { #ifndef CITRA_MODE if(R_FAILED(archive_result) && current_mode == MODE_THEMES) { throw_error("Theme extdata does not exist!\nSet a default theme from the home menu.", ERROR_LEVEL_ERROR); break; } #endif hidScanInput(); u32 kDown = hidKeysDown(); u32 kHeld = hidKeysHeld(); u32 kUp = hidKeysUp(); Entry_List_s * current_list = &lists[current_mode]; if(qr_mode) take_picture(); else if(preview_mode) draw_preview(preview_offset); else { draw_interface(current_list, current_mode); if(install_mode) draw_instructions(install_instructions); else draw_instructions(normal_instructions[current_mode]); } pp2d_end_draw(); if(kDown & KEY_START) break; if(!install_mode) { if(!preview_mode && !qr_mode && kDown & KEY_L) //toggle between splashes and themes { current_mode++; current_mode %= MODE_AMOUNT; continue; } else if(!preview_mode && kDown & KEY_R) //toggle QR mode { u32 out; ACU_GetWifiStatus(&out); if(out) { qr_mode = !qr_mode; if(qr_mode) init_qr(); else exit_qr(); } else { throw_error("Please connect to Wi-Fi before scanning QR", ERROR_LEVEL_WARNING); } continue; } else if(!qr_mode && kDown & KEY_Y) //toggle preview mode { if(!preview_mode) preview_mode = load_preview(*current_list, &preview_offset); else preview_mode = false; continue; } else if(qr_mode && kDown & KEY_L) //scan a QR code while in QR mode { CAMU_StopCapture(PORT_BOTH); CAMU_Activate(SELECT_NONE); qr_mode = !scan_qr(current_mode); CAMU_Activate(SELECT_OUT1_OUT2); CAMU_StartCapture(PORT_BOTH); if(!qr_mode) load_lists(lists); continue; } } if(qr_mode || preview_mode || current_list->entries == NULL) continue; int selected_entry = current_list->selected_entry; Entry_s * current_entry = ¤t_list->entries[selected_entry]; if(install_mode) { if(kUp & KEY_A) install_mode = false; if(!install_mode) { if((kDown | kHeld) & KEY_DLEFT) { draw_install(INSTALL_BGM); bgm_install(*current_entry); } else if((kDown | kHeld) & KEY_DUP) { draw_install(INSTALL_SINGLE); theme_install(*current_entry); } else if((kDown | kHeld) & KEY_DRIGHT) { draw_install(INSTALL_NO_BGM); no_bgm_install(*current_entry); } else if((kDown | kHeld) & KEY_DDOWN) { if(current_list->shuffle_count > MAX_SHUFFLE_THEMES) { throw_error("You have too many themes selected.", ERROR_LEVEL_WARNING); } else if(current_list->shuffle_count == 0) { throw_error("You dont have any themes selected.", ERROR_LEVEL_WARNING); } else { draw_install(INSTALL_SHUFFLE); Result res = shuffle_install(*current_list); if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res); else current_list->shuffle_count = 0; } } } continue; } // Actions if(kDown & KEY_A) { switch(current_mode) { case MODE_THEMES: install_mode = true; break; case MODE_SPLASHES: draw_install(INSTALL_SPLASH); splash_install(*current_entry); break; default: break; } } else if(kDown & KEY_B) { switch(current_mode) { case MODE_THEMES: if(current_entry->in_shuffle) current_list->shuffle_count--; else current_list->shuffle_count++; current_entry->in_shuffle = !current_entry->in_shuffle; break; case MODE_SPLASHES: if(draw_confirm("Are you sure you would like to delete\nthe installed splash?", current_list, current_mode)) { draw_install(INSTALL_SPLASH_DELETE); splash_delete(); } break; default: break; } } else if(kDown & KEY_X) { switch(current_mode) { case MODE_THEMES: break; case MODE_SPLASHES: break; default: break; } } else if(kDown & KEY_SELECT) { if(draw_confirm("Are you sure you would like to delete this?", current_list, current_mode)) { draw_install(INSTALL_ENTRY_DELETE); delete_entry(*current_entry); load_lists(lists); } } // Movement in the UI else if(kDown & KEY_UP) { change_selected(current_list, -1); } else if(kDown & KEY_DOWN) { change_selected(current_list, 1); } // Quick moving else if(kDown & KEY_LEFT) { change_selected(current_list, -ENTRIES_PER_SCREEN); } else if(kDown & KEY_RIGHT) { change_selected(current_list, ENTRIES_PER_SCREEN); } // Fast scroll using circle pad else if(kHeld & KEY_CPAD_UP) { change_selected(current_list, -1); svcSleepThread(FASTSCROLL_WAIT); } else if(kHeld & KEY_CPAD_DOWN) { change_selected(current_list, 1); svcSleepThread(FASTSCROLL_WAIT); } else if(kHeld & KEY_CPAD_LEFT) { change_selected(current_list, -ENTRIES_PER_SCREEN); svcSleepThread(FASTSCROLL_WAIT); } else if(kHeld & KEY_CPAD_RIGHT) { change_selected(current_list, ENTRIES_PER_SCREEN); svcSleepThread(FASTSCROLL_WAIT); } } exit_function(); return 0; }