diff --git a/assets/back.png b/assets/back.png new file mode 100644 index 0000000..acb3d95 Binary files /dev/null and b/assets/back.png differ diff --git a/assets/bgm_only.png b/assets/bgm_only.png new file mode 100644 index 0000000..5fa9eed Binary files /dev/null and b/assets/bgm_only.png differ diff --git a/assets/dump.png b/assets/dump.png new file mode 100644 index 0000000..195fd28 Binary files /dev/null and b/assets/dump.png differ diff --git a/assets/download.png b/assets/install.png similarity index 100% rename from assets/download.png rename to assets/install.png diff --git a/assets/list.png b/assets/menu.png similarity index 100% rename from assets/list.png rename to assets/menu.png diff --git a/assets/qr.png b/assets/qr.png new file mode 100644 index 0000000..c6615ef Binary files /dev/null and b/assets/qr.png differ diff --git a/assets/sprites.t3s b/assets/sprites.t3s index 86b990d..ce0db62 100644 --- a/assets/sprites.t3s +++ b/assets/sprites.t3s @@ -11,10 +11,10 @@ battery4.png battery5.png browse.png charging.png -download.png +install.png exit.png installed.png -list.png +menu.png no_home.png preview.png select.png @@ -22,3 +22,7 @@ shuffle.png shuffle_no_bgm.png sort.png start.png +qr.png +bgm_only.png +back.png +dump.png diff --git a/include/common.h b/include/common.h index 9e1abcc..609242b 100644 --- a/include/common.h +++ b/include/common.h @@ -54,6 +54,8 @@ static inline int max(const int a, const int b) #define FASTSCROLL_WAIT 1e8 +#define BETWEEN(min, x, max) (min < x && x < max) + typedef enum { MODE_THEMES = 0, MODE_SPLASHES, @@ -61,6 +63,14 @@ typedef enum { MODE_AMOUNT, } EntryMode; +typedef enum { + DRAW_MODE_LIST = 0, + DRAW_MODE_INSTALL, + DRAW_MODE_EXTRA, + + DRAW_MODE_AMOUNT, +} DrawMode; + extern const char * main_paths[MODE_AMOUNT]; extern const int entries_per_screen_v[MODE_AMOUNT]; extern const int entries_per_screen_h[MODE_AMOUNT]; diff --git a/include/conversion.h b/include/conversion.h index e2976dd..bc5d23f 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -4,6 +4,6 @@ #include "common.h" size_t bin_to_abgr(char ** bufp, size_t size); -size_t png_to_abgr(char ** bufp, size_t size); +size_t png_to_abgr(char ** bufp, size_t size, u32 *height); -#endif \ No newline at end of file +#endif diff --git a/include/draw.h b/include/draw.h index 2c02c96..7d1e7aa 100644 --- a/include/draw.h +++ b/include/draw.h @@ -163,7 +163,7 @@ void end_frame(void); void set_screen(C3D_RenderTarget * screen); void throw_error(const char * error, ErrorLevel level); -bool draw_confirm(const char * conf_msg, Entry_List_s * list); +bool draw_confirm(const char * conf_msg, Entry_List_s * list, DrawMode draw_mode); void draw_preview(C2D_Image preview, int preview_offset); @@ -178,6 +178,6 @@ void draw_home(u64 start_time, u64 cur_time); void draw_base_interface(void); void draw_grid_interface(Entry_List_s * list, Instructions_s instructions); -void draw_interface(Entry_List_s * list, Instructions_s instructions); +void draw_interface(Entry_List_s * list, Instructions_s instructions, DrawMode draw_mode); #endif diff --git a/include/instructions.h b/include/instructions.h deleted file mode 100644 index 5d7cc36..0000000 --- a/include/instructions.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -* This file is part of Anemone3DS -* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md -* -* 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. -*/ - -#ifndef INSTRUCTIONS_H -#define INSTRUCTIONS_H - -#include "draw.h" -#include "colors.h" - -Instructions_s normal_instructions[MODE_AMOUNT] = { - { - .info_line = NULL, - .instructions = { - { - "\uE000 Hold to install", - "\uE001 Queue shuffle theme" - }, - { - "\uE002 Hold for more", - "\uE003 Preview theme" - }, - { - "\uE004 Switch to splashes", - "\uE005 Scan QR code" - }, - { - "Exit", - "Delete from SD" - } - } - }, - { - .info_line = NULL, - .instructions = { - { - "\uE000 Install splash", - "\uE001 Delete installed splash" - }, - { - "\uE002 Hold for more", - "\uE003 Preview splash" - }, - { - "\uE004 Switch to themes", - "\uE005 Scan QR code" - }, - { - "Exit", - "Delete from SD" - } - } - } -}; - -Instructions_s install_instructions = { - .info_line = "Release \uE000 to cancel or hold \uE006 and release \uE000 to install", - .instructions = { - { - "\uE079 Normal install", - "\uE07A Shuffle install" - }, - { - "\uE07B BGM-only install", - "\uE07C No-BGM install" - }, - { - NULL, - NULL - }, - { - "Exit", - NULL - } - } -}; - -Instructions_s extra_instructions[3] = { - { - .info_line = "Release \uE002 to cancel or hold \uE006 and release \uE002 to sort", - .instructions = { - { - "\uE079 Sort by name", - "\uE07A Sort by author" - }, - { - "\uE07B Sort by filename", - NULL - }, - { - NULL, - NULL - }, - { - "Exit", - NULL - } - } - }, - { - .info_line = "Release \uE002 to cancel or hold \uE006 and release \uE002 to do stuff", - .instructions = { - { - "\uE079 Jump in the list", - "\uE07A Reload broken icons" - }, - { - "\uE07B Browse ThemePlaza", - NULL - }, - { - "\uE004 Sorting menu", - "\uE005 Dumping menu" - }, - { - "Exit", - NULL - } - } - }, - { - .info_line = "Release \uE002 to cancel or hold \uE006 and release \uE002 to dump", - .instructions = { - { - "\uE079 Dump Current Theme", - "\uE07A Dump All Themes" - }, - { - NULL, - NULL - }, - { - NULL, - NULL - }, - { - "Exit", - NULL - } - } - } -}; - -#endif diff --git a/include/loading.h b/include/loading.h index 5855566..9363608 100644 --- a/include/loading.h +++ b/include/loading.h @@ -68,7 +68,7 @@ void copy_texture_data(C3D_Tex * texture, const u16 * src, const Entry_Icon_s * void parse_smdh(Icon_s * icon, Entry_s * entry, const u16 * fallback_name); -bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset); +bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset, int height); bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * preview_offset); void free_preview(C2D_Image preview_image); Result load_audio(const Entry_s *, audio_s *); diff --git a/include/ui_strings.h b/include/ui_strings.h new file mode 100644 index 0000000..592bcdb --- /dev/null +++ b/include/ui_strings.h @@ -0,0 +1,188 @@ +/* +* This file is part of Anemone3DS +* Copyright (C) 2016-2020 Contributors in CONTRIBUTORS.md +* +* 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. +*/ + +#ifndef UISTRINGS_H +#define UISTRINGS_H + +#include "colors.h" +#include "draw.h" +#include "common.h" + +#define SPLASHES_STRINGS 2 +#define THEMES_STRINGS 6 + +typedef struct { + const char *quit; + const char *thread_error; + const char *zip_not_theme_splash; + const char *file_not_zip; + const char *download_failed; +} Camera_Strings_s; + +typedef struct { + const char *theme_mode; + const char *splash_mode; + const char *no_themes; + const char *no_splashes; + const char *qr_download; + const char *switch_splashes; + const char *switch_themes; + const char *quit; + const char *by; + const char *selected; + const char *sel; + const char *tp_theme_mode; + const char *tp_splash_mode; + const char *search; + const char *page; + const char *err_quit; + const char *warn_continue; + const char *yes_no; + const char *load_themes; + const char *load_splash; + const char *load_icons; + const char *install_splash; + const char *delete_splash; + const char *install_theme; + const char *install_shuffle; + const char *install_bgm; + const char *install_no_bgm; + const char *downloading; + const char *checking_dl; + const char *delete_sd; + const char *download_themes; + const char *download_splashes; + const char *download_preview; + const char *download_bgm; + const char *dump_single; + const char *dump_all_official; + float start_pos; +} Draw_Strings_s; + +typedef struct { + const char *illegal_input; + const char *new_or_overwrite; + const char *cancel; + const char *overwrite; + const char *rename; + const char *swkbd_fail; + const char *sd_full; + const char *fs_error; +} FS_Strings_s; + +typedef struct { + const char *no_preview; +} Loading_Strings_s; + +typedef struct { + const char *position_too_big; + const char *position_zero; + const char *jump_q; + const char *cancel; + const char *jump; + const char *no_theme_extdata; + const char *loading_qr; + const char *no_wifi; + const char *qr_homebrew; + const char *camera_broke; + const char *too_many_themes; + const char *not_enough_themes; + const char *uninstall_confirm; + const char *delete_confirm; +} Main_Strings_s; + +typedef struct { + const char *no_results; + const char *check_wifi; + const char *new_page_big; + const char *new_page_zero; + const char *jump_page; + const char *cancel; + const char *jump; + const char *tags; + const char *search; + const char *parental_fail; + const char *zip_not_found; + const char *generic_httpc_error; + const char *http303_tp; + const char *http303; + const char *http404; + const char *http_err_url; + const char *http_errcode_generic; + const char *http401; + const char *http403; + const char *http407; + const char *http414; + const char *http418; + const char *http426; + const char *http451; + const char *http500; + const char *http502; + const char *http503; + const char *http504; + const char *http_unexpected; +} Remote_Strings_s; + +typedef struct { + const char *no_splash_found; + const char *splash_disabled; +} Splashes_Strings_s; + +typedef struct { + const char *no_body_found; + const char *mono_warn; + const char *illegal_char; + const char *name_folder; + const char *cancel; + const char *done; +} Themes_Strings_s; + +typedef struct { + Instructions_s normal_instructions[MODE_AMOUNT]; + Instructions_s install_instructions; + Instructions_s extra_instructions[3]; + Camera_Strings_s camera; + Draw_Strings_s draw; + FS_Strings_s fs; + Loading_Strings_s loading; + Main_Strings_s main; + Remote_Strings_s remote; + Instructions_s remote_instructions[MODE_AMOUNT]; + Instructions_s remote_extra_instructions; + Splashes_Strings_s splashes; + Themes_Strings_s themes; +} Language_s; + +typedef enum { + LANGUAGE_EN, + + LANGUAGE_AMOUNT, +} Language_Name; + +Language_s init_strings(CFG_Language lang); +extern Language_s language; + +#endif diff --git a/source/camera.c b/source/camera.c index c0e1575..e0b4731 100644 --- a/source/camera.c +++ b/source/camera.c @@ -32,6 +32,7 @@ #include "fs.h" #include "loading.h" #include "remote.h" +#include "ui_strings.h" #include #include @@ -200,7 +201,7 @@ static void update_ui(void * arg) 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"); + draw_text_center(GFX_BOTTOM, 4, 0.5, 0.5, 0.5, colors[COLOR_WHITE], language.camera.quit); end_frame(); } @@ -212,7 +213,7 @@ static bool start_capture_cam(qr_data * data) { 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); + throw_error(language.camera.thread_error, ERROR_LEVEL_ERROR); LightEvent_Signal(&data->event_cam_info); LightEvent_Signal(&data->event_ui_info); return false; @@ -397,18 +398,18 @@ bool init_qr(void) } else { - throw_error("Zip downloaded is neither\na splash nor a theme.", ERROR_LEVEL_WARNING); + throw_error(language.camera.zip_not_theme_splash, ERROR_LEVEL_WARNING); } } else { - throw_error("File downloaded isn't a zip.", ERROR_LEVEL_WARNING); + throw_error(language.camera.file_not_zip, ERROR_LEVEL_WARNING); } free(zip_buf); } else { - throw_error("Download failed.", ERROR_LEVEL_WARNING); + throw_error(language.camera.download_failed, ERROR_LEVEL_WARNING); } free(filename); diff --git a/source/conversion.c b/source/conversion.c index 53610f2..517ec50 100644 --- a/source/conversion.c +++ b/source/conversion.c @@ -49,7 +49,7 @@ size_t bin_to_abgr(char ** bufp, size_t size) return out_size; } -size_t png_to_abgr(char ** bufp, size_t size) +size_t png_to_abgr(char ** bufp, size_t size, u32 *height) { size_t out_size = 0; if(size < 8 || png_sig_cmp((png_bytep)*bufp, 0, 8)) @@ -70,7 +70,7 @@ size_t png_to_abgr(char ** bufp, size_t size) png_read_info(png, info); u32 width = png_get_image_width(png, info); - u32 height = png_get_image_height(png, info); + *height = png_get_image_height(png, info); png_byte color_type = png_get_color_type(png, info); png_byte bit_depth = png_get_bit_depth(png, info); @@ -107,10 +107,10 @@ size_t png_to_abgr(char ** bufp, size_t size) png_read_update_info(png, info); - row_pointers = malloc(sizeof(png_bytep) * height); - out_size = sizeof(u32) * (width * height); + row_pointers = malloc(sizeof(png_bytep) * *height); + out_size = sizeof(u32) * (width * *height); u32 * out = malloc(out_size); - for(u32 y = 0; y < height; y++) + for(u32 y = 0; y < *height; y++) { row_pointers[y] = (png_bytep)(out + (width * y)); } @@ -126,4 +126,4 @@ size_t png_to_abgr(char ** bufp, size_t size) *bufp = (char*)out; return out_size; -} \ No newline at end of file +} diff --git a/source/draw.c b/source/draw.c index f2b6513..ce5feb8 100644 --- a/source/draw.c +++ b/source/draw.c @@ -27,6 +27,7 @@ #include "draw.h" #include "unicode.h" #include "colors.h" +#include "ui_strings.h" #include "sprites.h" @@ -77,56 +78,56 @@ void init_screens(void) C2D_TextParse(&text[TEXT_VERSION], staticBuf, VERSION); - C2D_TextParse(&text[TEXT_THEME_MODE], staticBuf, "Theme mode"); - C2D_TextParse(&text[TEXT_SPLASH_MODE], staticBuf, "Splash mode"); + C2D_TextParse(&text[TEXT_THEME_MODE], staticBuf, language.draw.theme_mode); + C2D_TextParse(&text[TEXT_SPLASH_MODE], staticBuf, language.draw.splash_mode); - C2D_TextParse(&text[TEXT_NO_THEME_FOUND], staticBuf, "No theme found"); - C2D_TextParse(&text[TEXT_NO_SPLASH_FOUND], staticBuf, "No splash found"); + C2D_TextParse(&text[TEXT_NO_THEME_FOUND], staticBuf, language.draw.no_themes); + C2D_TextParse(&text[TEXT_NO_SPLASH_FOUND], staticBuf, language.draw.no_splashes); - C2D_TextParse(&text[TEXT_DOWNLOAD_FROM_QR], staticBuf, "Press \uE005 to download from QR"); + C2D_TextParse(&text[TEXT_DOWNLOAD_FROM_QR], staticBuf, language.draw.qr_download); - C2D_TextParse(&text[TEXT_SWITCH_TO_SPLASHES], staticBuf, "Or \uE004 to switch to splashes"); - C2D_TextParse(&text[TEXT_SWITCH_TO_THEMES], staticBuf, "Or \uE004 to switch to themes"); + C2D_TextParse(&text[TEXT_SWITCH_TO_SPLASHES], staticBuf, language.draw.switch_splashes); + C2D_TextParse(&text[TEXT_SWITCH_TO_THEMES], staticBuf, language.draw.switch_themes); - C2D_TextParse(&text[TEXT_OR_START_TO_QUIT], staticBuf, "Or to quit"); + C2D_TextParse(&text[TEXT_OR_START_TO_QUIT], staticBuf, language.draw.quit); - C2D_TextParse(&text[TEXT_BY_AUTHOR], staticBuf, "By "); - C2D_TextParse(&text[TEXT_SELECTED], staticBuf, "Selected:"); - C2D_TextParse(&text[TEXT_SELECTED_SHORT], staticBuf, "Sel.:"); + C2D_TextParse(&text[TEXT_BY_AUTHOR], staticBuf, language.draw.by); + C2D_TextParse(&text[TEXT_SELECTED], staticBuf, language.draw.selected); + C2D_TextParse(&text[TEXT_SELECTED_SHORT], staticBuf, language.draw.sel); - C2D_TextParse(&text[TEXT_THEMEPLAZA_THEME_MODE], staticBuf, "ThemePlaza Theme mode"); - C2D_TextParse(&text[TEXT_THEMEPLAZA_SPLASH_MODE], staticBuf, "ThemePlaza Splash mode"); + C2D_TextParse(&text[TEXT_THEMEPLAZA_THEME_MODE], staticBuf, language.draw.tp_theme_mode); + C2D_TextParse(&text[TEXT_THEMEPLAZA_SPLASH_MODE], staticBuf, language.draw.tp_splash_mode); - C2D_TextParse(&text[TEXT_SEARCH], staticBuf, "Search..."); - C2D_TextParse(&text[TEXT_PAGE], staticBuf, "Page:"); + C2D_TextParse(&text[TEXT_SEARCH], staticBuf, language.draw.search); + C2D_TextParse(&text[TEXT_PAGE], staticBuf, language.draw.page); - C2D_TextParse(&text[TEXT_ERROR_QUIT], staticBuf, "Press \uE000 to quit."); - C2D_TextParse(&text[TEXT_ERROR_CONTINUE], staticBuf, "Press \uE000 to continue."); + C2D_TextParse(&text[TEXT_ERROR_QUIT], staticBuf, language.draw.err_quit); + C2D_TextParse(&text[TEXT_ERROR_CONTINUE], staticBuf, language.draw.warn_continue); - C2D_TextParse(&text[TEXT_CONFIRM_YES_NO], staticBuf, "\uE000 Yes \uE001 No"); + C2D_TextParse(&text[TEXT_CONFIRM_YES_NO], staticBuf, language.draw.yes_no); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_THEMES], staticBuf, "Loading themes, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_SPLASHES], staticBuf, "Loading splashes, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_ICONS], staticBuf, "Loading icons, please wait..."); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_THEMES], staticBuf, language.draw.load_themes); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_SPLASHES], staticBuf, language.draw.load_splash); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_ICONS], staticBuf, language.draw.load_icons); - C2D_TextParse(&text[TEXT_INSTALL_SPLASH], staticBuf, "Installing a splash..."); - C2D_TextParse(&text[TEXT_INSTALL_SPLASH_DELETE], staticBuf, "Deleting installed splash..."); + C2D_TextParse(&text[TEXT_INSTALL_SPLASH], staticBuf, language.draw.install_splash); + C2D_TextParse(&text[TEXT_INSTALL_SPLASH_DELETE], staticBuf, language.draw.delete_splash); - C2D_TextParse(&text[TEXT_INSTALL_SINGLE], staticBuf, "Installing a single theme..."); - C2D_TextParse(&text[TEXT_INSTALL_SHUFFLE], staticBuf, "Installing shuffle themes..."); - C2D_TextParse(&text[TEXT_INSTALL_BGM], staticBuf, "Installing BGM-only theme..."); - C2D_TextParse(&text[TEXT_INSTALL_NO_BGM], staticBuf, "Installing theme without BGM..."); + C2D_TextParse(&text[TEXT_INSTALL_SINGLE], staticBuf, language.draw.install_theme); + C2D_TextParse(&text[TEXT_INSTALL_SHUFFLE], staticBuf, language.draw.install_shuffle); + C2D_TextParse(&text[TEXT_INSTALL_BGM], staticBuf, language.draw.install_bgm); + C2D_TextParse(&text[TEXT_INSTALL_NO_BGM], staticBuf, language.draw.install_no_bgm); - C2D_TextParse(&text[TEXT_INSTALL_DOWNLOAD], staticBuf, "Downloading..."); - C2D_TextParse(&text[TEXT_INSTALL_CHECKING_DOWNLOAD], staticBuf, "Checking downloaded file..."); - C2D_TextParse(&text[TEXT_INSTALL_ENTRY_DELETE], staticBuf, "Deleting from SD..."); + C2D_TextParse(&text[TEXT_INSTALL_DOWNLOAD], staticBuf, language.draw.downloading); + C2D_TextParse(&text[TEXT_INSTALL_CHECKING_DOWNLOAD], staticBuf, language.draw.checking_dl); + C2D_TextParse(&text[TEXT_INSTALL_ENTRY_DELETE], staticBuf, language.draw.delete_sd); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_THEMES], staticBuf, "Downloading theme list, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_SPLASHES], staticBuf, "Downloading splash list, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_PREVIEW], staticBuf, "Downloading preview, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_BGM], staticBuf, "Downloading BGM, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_DUMPING_THEME], staticBuf, "Dumping theme, please wait..."); - C2D_TextParse(&text[TEXT_INSTALL_DUMPING_ALL_THEMES], staticBuf, "Dumping official themes, please wait..."); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_THEMES], staticBuf, language.draw.download_themes); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_SPLASHES], staticBuf, language.draw.download_splashes); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_PREVIEW], staticBuf, language.draw.download_preview); + C2D_TextParse(&text[TEXT_INSTALL_LOADING_REMOTE_BGM], staticBuf, language.draw.download_bgm); + C2D_TextParse(&text[TEXT_INSTALL_DUMPING_THEME], staticBuf, language.draw.dump_single); + C2D_TextParse(&text[TEXT_INSTALL_DUMPING_ALL_THEMES], staticBuf, language.draw.dump_all_official); for(int i = 0; i < TEXT_AMOUNT; i++) C2D_TextOptimize(&text[i]); @@ -318,12 +319,12 @@ void throw_error(const char * error, ErrorLevel level) } } -bool draw_confirm(const char * conf_msg, Entry_List_s * list) +bool draw_confirm(const char * conf_msg, Entry_List_s * list, DrawMode draw_mode) { while(aptMainLoop()) { Instructions_s instructions = {0}; - draw_interface(list, instructions); + draw_interface(list, instructions, draw_mode); set_screen(top); draw_text_center(GFX_TOP, BUTTONS_Y_LINE_1, 0.5f, 0.7f, 0.7f, colors[COLOR_YELLOW], conf_msg); draw_c2d_text_center(GFX_TOP, BUTTONS_Y_LINE_3, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], &text[TEXT_CONFIRM_YES_NO]); @@ -535,7 +536,7 @@ void draw_grid_interface(Entry_List_s * list, Instructions_s instructions) draw_c2d_text(7, 3, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], &text[TEXT_SEARCH]); - draw_image(sprites_list_idx, 320-96, 0); + draw_image(sprites_back_idx, 320-96, 0); draw_image(sprites_exit_idx, 320-72, 0); draw_image(sprites_preview_idx, 320-48, 0); @@ -601,7 +602,7 @@ void draw_grid_interface(Entry_List_s * list, Instructions_s instructions) draw_c2d_text(176, 219, 0.5, 0.6, 0.6, colors[COLOR_WHITE], &text[TEXT_PAGE]); } -void draw_interface(Entry_List_s * list, Instructions_s instructions) +void draw_interface(Entry_List_s * list, Instructions_s instructions, DrawMode draw_mode) { draw_base_interface(); EntryMode current_mode = list->mode; @@ -613,7 +614,7 @@ void draw_interface(Entry_List_s * list, Instructions_s instructions) draw_c2d_text_center(GFX_TOP, 4, 0.5f, 0.5f, 0.5f, colors[COLOR_WHITE], mode_string[current_mode]); - if(list->entries == NULL) + if(list->entries == NULL || list->entries_count == 0) { C2D_Text * mode_found_string[MODE_AMOUNT] = { &text[TEXT_NO_THEME_FOUND], @@ -633,7 +634,7 @@ void draw_interface(Entry_List_s * list, Instructions_s instructions) C2D_ImageTint yellow_tint; C2D_PlainImageTint(&yellow_tint, colors[COLOR_YELLOW], 1.0f); - C2D_SpriteSetPos(&sprite_start, 162, 173); + C2D_SpriteSetPos(&sprite_start, language.draw.start_pos, 173); C2D_SpriteSetScale(&sprite_start, 1.25f, 1.4f); C2D_DrawSpriteTinted(&sprite_start, &yellow_tint); C2D_SpriteSetScale(&sprite_start, 1.0f, 1.0f); @@ -641,7 +642,7 @@ void draw_interface(Entry_List_s * list, Instructions_s instructions) set_screen(bottom); draw_image(sprites_sort_idx, 320-144, 0); - draw_image(sprites_download_idx, 320-120, 0); + draw_image(sprites_qr_idx, 320-120, 0); draw_image(sprites_browse_idx, 320-96, 0); draw_image(sprites_exit_idx, 320-72, 0); draw_image(sprites_preview_idx, 320-48, 0); @@ -667,18 +668,41 @@ void draw_interface(Entry_List_s * list, Instructions_s instructions) free(shuffle_count_string); } - draw_image(sprites_sort_idx, 320-144, 0); - draw_image(sprites_download_idx, 320-120, 0); - draw_image(sprites_browse_idx, 320-96, 0); - draw_image(sprites_exit_idx, 320-72, 0); - draw_image(sprites_preview_idx, 320-48, 0); - - draw_text(320-24+2.5, -3, 0.6, 1.0f, 0.9f, colors[COLOR_WHITE], mode_switch_char[!current_mode]); + if (draw_mode == DRAW_MODE_LIST) + { + draw_image(sprites_install_idx, 320-120, 0); + draw_image(sprites_qr_idx, 320-96, 0); + draw_image(sprites_exit_idx, 320-72, 0); + draw_image(sprites_preview_idx, 320-48, 0); + draw_text(320-24+2.5, -3, 0.6, 1.0f, 0.9f, colors[COLOR_WHITE], mode_switch_char[!current_mode]); + draw_image(sprites_menu_idx, 320-144, 0); + if (current_mode == MODE_THEMES) + { + draw_image(sprites_shuffle_idx, 320-168, 0); + } + } + else + { + if (draw_mode == DRAW_MODE_INSTALL) + { + draw_image(sprites_install_idx, 320-24, 0); + draw_image(sprites_shuffle_idx, 320-48, 0); + draw_image(sprites_shuffle_no_bgm_idx, 320-72, 0); + draw_image(sprites_bgm_only_idx, 320-96, 0); + draw_image(sprites_back_idx, 320-120, 0); + } else if (draw_mode == DRAW_MODE_EXTRA) + { + draw_image(sprites_browse_idx, 320-24, 0); + draw_image(sprites_dump_idx, 320-48, 0); + draw_image(sprites_sort_idx, 320-72, 0); + draw_image(sprites_back_idx, 320-96, 0); + } + } // Show arrows if there are themes out of bounds //---------------------------------------------------------------- if(list->scroll > 0) - draw_image(sprites_arrow_up_idx, 152, 4); + draw_image(sprites_arrow_up_idx, 136, 220); if(list->scroll + list->entries_loaded < list->entries_count) draw_image(sprites_arrow_down_idx, 152, 220); @@ -763,4 +787,8 @@ void draw_interface(Entry_List_s * list, Instructions_s instructions) draw_c2d_text(176, 219, 0.5, 0.6, 0.6, colors[COLOR_WHITE], &text[TEXT_SELECTED]); else draw_c2d_text(176, 219, 0.5, 0.6, 0.6, colors[COLOR_WHITE], &text[TEXT_SELECTED_SHORT]); + if(draw_mode != DRAW_MODE_LIST) + { + C2D_DrawRectSolid(0, 24, 1.0f, 320, 240-48, C2D_Color32(0, 0, 0, 128)); + } } diff --git a/source/fs.c b/source/fs.c index b0b093b..6149d06 100644 --- a/source/fs.c +++ b/source/fs.c @@ -29,6 +29,7 @@ #include "fs.h" #include "draw.h" #include "unicode.h" +#include "ui_strings.h" #include #include @@ -372,7 +373,8 @@ static SwkbdCallbackResult fat32filter(void * user, const char ** ppMessage, con { (void)textlen; (void)user; - *ppMessage = "Input must not contain:\n" ILLEGAL_CHARS; + + *ppMessage = language.fs.illegal_input; if(strpbrk(text, ILLEGAL_CHARS)) { DEBUG("illegal filename: %s\n", text); @@ -434,12 +436,12 @@ renamed: SwkbdState swkbd; swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 3, max_chars / 2); - swkbdSetHintText(&swkbd, "Choose a new filename or tap Overwrite"); + swkbdSetHintText(&swkbd, language.fs.new_or_overwrite); swkbdSetFeatures(&swkbd, SWKBD_PREDICTIVE_INPUT | SWKBD_DARKEN_TOP_SCREEN); - swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_MIDDLE, "Overwrite", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Rename", true); + swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, language.fs.cancel, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_MIDDLE, language.fs.overwrite, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, language.fs.rename, true); swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, SWKBD_FILTER_CALLBACK, -1); swkbdSetFilterCallback(&swkbd, &fat32filter, NULL); @@ -462,18 +464,18 @@ renamed: return; case SWKBD_BUTTON_NONE: DEBUG("SWKBD broke wtf??? :- %x\n", swkbdGetResult(&swkbd)); - return throw_error("???\nTry a USB keyboard", ERROR_LEVEL_WARNING); + return throw_error(language.fs.swkbd_fail, ERROR_LEVEL_WARNING); } } else if (res == (long)0xC86044D2) { DEBUG("SD card is full\n"); - return throw_error("SD card is full.\nDelete some themes to make space.", ERROR_LEVEL_WARNING); + return throw_error(language.fs.sd_full, ERROR_LEVEL_WARNING); } else { DEBUG("error: %lx\n", res); - return throw_error("FS Error:\nGet a new SD card.", ERROR_LEVEL_ERROR); + return throw_error(language.fs.fs_error, ERROR_LEVEL_ERROR); } } diff --git a/source/loading.c b/source/loading.c index 6288f24..39c8506 100644 --- a/source/loading.c +++ b/source/loading.c @@ -30,6 +30,7 @@ #include "music.h" #include "draw.h" #include "conversion.h" +#include "ui_strings.h" #include @@ -306,9 +307,8 @@ void load_icons_thread(void * void_arg) } while(arg->run_thread); } -bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset) +bool load_preview_from_buffer(char * row_pointers, u32 size, C2D_Image * preview_image, int * preview_offset, int height) { - int height = SCREEN_HEIGHT * 2; int width = (uint32_t)((size / 4) / height); free_preview(*preview_image); @@ -355,10 +355,11 @@ bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * pr char * preview_buffer = NULL; u32 size = load_data("/preview.png", entry, &preview_buffer); + u32 height = 480; if(size) { - if (!(size = png_to_abgr(&preview_buffer, size))) + if (!(size = png_to_abgr(&preview_buffer, size, &height))) { return false; } @@ -409,7 +410,7 @@ bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * pr if (!found_splash) { free(rgba_buffer); - throw_error("No preview found.", ERROR_LEVEL_WARNING); + throw_error(language.loading.no_preview, ERROR_LEVEL_WARNING); return false; } @@ -417,7 +418,7 @@ bool load_preview(const Entry_List_s * list, C2D_Image * preview_image, int * pr preview_buffer = rgba_buffer; } - bool ret = load_preview_from_buffer(preview_buffer, size, preview_image, preview_offset); + bool ret = load_preview_from_buffer(preview_buffer, size, preview_image, preview_offset, height); free(preview_buffer); if(ret) diff --git a/source/main.c b/source/main.c index 8853d6a..3fbe08d 100644 --- a/source/main.c +++ b/source/main.c @@ -32,7 +32,7 @@ #include "camera.h" #include "music.h" #include "remote.h" -#include "instructions.h" +#include "ui_strings.h" #include bool quit = false; @@ -53,6 +53,8 @@ static Thread_Arg_s install_check_threads_arg[MODE_AMOUNT] = {0}; static Entry_List_s lists[MODE_AMOUNT] = {0}; +Language_s language = {0}; + int __stacksize__ = 64 * 1024; Result archive_result; u32 old_time_limit; @@ -254,8 +256,8 @@ static void load_lists(Entry_List_s * lists) DEBUG("total: %i\n", current_list->entries_count); - load_icons_first(current_list, false); sort_by_name(current_list); + load_icons_first(current_list, false); void (*install_check_function)(void *) = NULL; if(i == MODE_THEMES) @@ -283,12 +285,12 @@ static SwkbdCallbackResult jump_menu_callback(void * entries_count, const char * int typed_value = atoi(text); if(typed_value > *(int *)entries_count) { - *ppMessage = "The new position has to be\nsmaller or equal to the\nnumber of entries!"; + *ppMessage = language.main.position_too_big; return SWKBD_CALLBACK_CONTINUE; } else if(typed_value == 0) { - *ppMessage = "The new position has to\nbe positive!"; + *ppMessage = language.main.position_zero; return SWKBD_CALLBACK_CONTINUE; } return SWKBD_CALLBACK_OK; @@ -309,11 +311,11 @@ static void jump_menu(Entry_List_s * list) sprintf(numbuf, "%i", list->selected_entry); swkbdSetInitialText(&swkbd, numbuf); - sprintf(numbuf, "Where do you want to jump to?\nMay cause icons to reload."); + sprintf(numbuf, language.main.jump_q); swkbdSetHintText(&swkbd, numbuf); - swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Jump", true); + swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, language.main.cancel, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, language.main.jump, true); swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, max_chars); swkbdSetFilterCallback(&swkbd, jump_menu_callback, &list->entries_count); @@ -375,6 +377,9 @@ int main(void) { srand(time(NULL)); init_services(); + CFG_Language lang; + CFGU_GetSystemLanguage(&lang); + language = init_strings(lang); init_screens(); svcCreateMutex(&update_icons_mutex, true); @@ -400,7 +405,9 @@ int main(void) int preview_offset = 0; bool install_mode = false; + DrawMode draw_mode = DRAW_MODE_LIST; bool extra_mode = false; + int extra_index = 1; C2D_Image preview = {0}; while(aptMainLoop()) @@ -421,7 +428,7 @@ int main(void) #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); + throw_error(language.main.no_theme_extdata, ERROR_LEVEL_ERROR); quit = true; continue; } @@ -434,22 +441,12 @@ int main(void) current_list = &lists[current_mode]; - Instructions_s instructions = normal_instructions[current_mode]; + Instructions_s instructions = language.normal_instructions[current_mode]; if(install_mode) - instructions = install_instructions; + instructions = language.install_instructions; if(extra_mode) { - int index = 1; - bool key_l = (kDown | kHeld) & KEY_L; - bool key_r = (kDown | kHeld) & KEY_R; - if(key_l ^ key_r) - { - if(key_l) - index = 0; - else if(key_r) // uncomment when we use the right menu. we don't for now - index = 2; - } - instructions = extra_instructions[index]; + instructions = language.extra_instructions[extra_index]; } if(preview_mode) @@ -472,7 +469,7 @@ int main(void) svcWaitSynchronization(update_icons_mutex, U64_MAX); } - draw_interface(current_list, instructions); + draw_interface(current_list, instructions, draw_mode); svcSleepThread(1e7); released = false; @@ -502,7 +499,7 @@ int main(void) { enable_qr: draw_base_interface(); - draw_text_center(GFX_TOP, 100, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], "Loading QR Scanner..."); + draw_text_center(GFX_TOP, 100, 0.5f, 0.6f, 0.6f, colors[COLOR_WHITE], language.main.loading_qr); end_frame(); if(R_SUCCEEDED(camInit())) { @@ -518,15 +515,15 @@ int main(void) } else { - throw_error("Please connect to Wi-Fi before scanning QR codes", ERROR_LEVEL_WARNING); + throw_error(language.main.no_wifi, ERROR_LEVEL_WARNING); } } else { if(homebrew) - throw_error("QR scanning doesnt work from the Homebrew\nLauncher, use the ThemePlaza browser instead.", ERROR_LEVEL_WARNING); + throw_error(language.main.qr_homebrew, ERROR_LEVEL_WARNING); else - throw_error("Your camera seems to have a problem,\nunable to scan QR codes.", ERROR_LEVEL_WARNING); + throw_error(language.main.camera_broke, ERROR_LEVEL_WARNING); } continue; @@ -580,92 +577,138 @@ int main(void) if(install_mode) { - if(kUp & KEY_A) - install_mode = false; - if(!install_mode) + if ((kDown | kHeld) & KEY_TOUCH) { - if((kDown | kHeld) & KEY_DLEFT) + touchPosition touch = {0}; + hidTouchRead(&touch); + u16 x = touch.px; + u16 y = touch.py; + + if (kDown & KEY_TOUCH) { - aptSetHomeAllowed(false); - draw_install(INSTALL_BGM); - if(R_SUCCEEDED(bgm_install(current_entry))) + if (y < 24) { - for(int i = 0; i < current_list->entries_count; i++) + if (BETWEEN(320-24, x, 320)) { - Entry_s * theme = ¤t_list->entries[i]; - if(theme == current_entry) - theme->installed = true; - else - theme->installed = false; + goto install_theme_single; + } else if (BETWEEN(320-48, x, 320-24)) + { + goto install_theme_shuffle; + } else if (BETWEEN(320-72, x, 320-48)) + { + goto install_theme_no_bgm; + } else if (BETWEEN(320-96, x, 320-72)) + { + goto install_theme_bgm_only; + } else if (BETWEEN(320-120, x, 320-96)) + { + goto install_leave; } - installed_themes = true; } } - else if((kDown | kHeld) & KEY_DUP) + } + + if(kDown & KEY_B) + { + install_leave: + install_mode = false; + draw_mode = DRAW_MODE_LIST; + } + else if(kDown & KEY_DLEFT) + { + install_theme_bgm_only: + install_mode = false; + draw_mode = DRAW_MODE_LIST; + aptSetHomeAllowed(false); + draw_install(INSTALL_BGM); + if(R_SUCCEEDED(bgm_install(current_entry))) + { + for(int i = 0; i < current_list->entries_count; i++) + { + #define BETWEEN(min, x, max) (min < x && x < max) + Entry_s * theme = ¤t_list->entries[i]; + if(theme == current_entry) + theme->installed = true; + else + theme->installed = false; + } + installed_themes = true; + } + } + else if(kDown & KEY_DUP) + { + install_theme_single: + install_mode = false; + draw_mode = DRAW_MODE_LIST; + aptSetHomeAllowed(false); + draw_install(INSTALL_SINGLE); + if(R_SUCCEEDED(theme_install(current_entry))) + { + for(int i = 0; i < current_list->entries_count; i++) + + { + Entry_s * theme = ¤t_list->entries[i]; + if(theme == current_entry) + theme->installed = true; + else + theme->installed = false; + } + installed_themes = true; + } + } + else if(kDown & KEY_DRIGHT) + { + install_theme_no_bgm: + install_mode = false; + draw_mode = DRAW_MODE_LIST; + aptSetHomeAllowed(false); + draw_install(INSTALL_NO_BGM); + if(R_SUCCEEDED(no_bgm_install(current_entry))) + { + for(int i = 0; i < current_list->entries_count; i++) + { + Entry_s * theme = ¤t_list->entries[i]; + if(theme == current_entry) + theme->installed = true; + else + theme->installed = false; + } + installed_themes = true; + } + } + else if(kDown & KEY_DDOWN) + { + install_theme_shuffle: + install_mode = false; + draw_mode = DRAW_MODE_LIST; + if(current_list->shuffle_count > MAX_SHUFFLE_THEMES) + { + throw_error(language.main.too_many_themes, ERROR_LEVEL_WARNING); + } + else if(current_list->shuffle_count < 2) + { + throw_error(language.main.not_enough_themes, ERROR_LEVEL_WARNING); + } + else { aptSetHomeAllowed(false); - draw_install(INSTALL_SINGLE); - if(R_SUCCEEDED(theme_install(current_entry))) - { - for(int i = 0; i < current_list->entries_count; i++) - { - Entry_s * theme = ¤t_list->entries[i]; - if(theme == current_entry) - theme->installed = true; - else - theme->installed = false; - } - installed_themes = true; - } - } - else if((kDown | kHeld) & KEY_DRIGHT) - { - aptSetHomeAllowed(false); - draw_install(INSTALL_NO_BGM); - if(R_SUCCEEDED(no_bgm_install(current_entry))) - { - for(int i = 0; i < current_list->entries_count; i++) - { - Entry_s * theme = ¤t_list->entries[i]; - if(theme == current_entry) - theme->installed = true; - else - theme->installed = false; - } - installed_themes = true; - } - } - 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 < 2) - { - throw_error("You don't have enough themes selected.", ERROR_LEVEL_WARNING); - } + draw_install(INSTALL_SHUFFLE); + Result res = shuffle_install(current_list); + if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res); else { - aptSetHomeAllowed(false); - draw_install(INSTALL_SHUFFLE); - Result res = shuffle_install(current_list); - if(R_FAILED(res)) DEBUG("shuffle install result: %lx\n", res); - else + for(int i = 0; i < current_list->entries_count; i++) { - for(int i = 0; i < current_list->entries_count; i++) + Entry_s * theme = ¤t_list->entries[i]; + if(theme->in_shuffle) { - Entry_s * theme = ¤t_list->entries[i]; - if(theme->in_shuffle) - { - theme->in_shuffle = false; - theme->installed = true; - } - else theme->installed = false; + theme->in_shuffle = false; + theme->installed = true; } - current_list->shuffle_count = 0; - installed_themes = true; + else theme->installed = false; } + current_list->shuffle_count = 0; + installed_themes = true; } } } @@ -673,71 +716,151 @@ int main(void) } else if(extra_mode) { - if(kUp & KEY_X) - extra_mode = false; - if(!extra_mode) + if((kDown | kHeld) & KEY_TOUCH) { - bool key_l = (kDown | kHeld) & KEY_L; - bool key_r = (kDown | kHeld) & KEY_R; - if(!(key_l ^ key_r)) + touchPosition touch = {0}; + hidTouchRead(&touch); + u16 x = touch.px; + u16 y = touch.py; + if (kDown & KEY_TOUCH) { - if((kDown | kHeld) & KEY_DLEFT) + if (y < 24) { - browse_themeplaza: - if(themeplaza_browser(current_mode)) + if (BETWEEN(320-24, x, 320)) { - current_mode = MODE_THEMES; - load_lists(lists); + goto browse_themeplaza; + } else if (BETWEEN(320-48, x, 320-24)) + { + goto dump_single; + } else if (BETWEEN(320-72, x, 320-48)) + { + switch (current_list->current_sort) + { + case SORT_NAME: + goto sort_author; + break; + case SORT_AUTHOR: + goto sort_path; + break; + case SORT_PATH: + goto sort_name; + break; + default: + break; + } + } else if (BETWEEN(320-96, x, 320-72)) + { + extra_mode = false; + extra_index = 1; + draw_mode = DRAW_MODE_LIST; } } - else if((kDown | kHeld) & KEY_DUP) + } + } + else if(extra_index == 1) + { + if(kDown & KEY_B) + { + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + } + else if(kDown & KEY_DLEFT) + { + browse_themeplaza: + if(themeplaza_browser(current_mode)) { - jump: - jump_menu(current_list); + current_mode = MODE_THEMES; + load_lists(lists); + } + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if(kDown & KEY_DUP) + { + jump: + jump_menu(current_list); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; - } - else if((kDown | kHeld) & KEY_DDOWN) - { - load_icons_first(current_list, false); - } } - else if(key_l) + else if(kDown & KEY_DDOWN) { - if((kDown | kHeld) & KEY_DLEFT) - { - sort_path: - sort_by_filename(current_list); - load_icons_first(current_list, false); - } - else if(((kDown | kHeld)) & KEY_DUP) - { - sort_name: - sort_by_name(current_list); - load_icons_first(current_list, false); - } - else if(((kDown | kHeld)) & KEY_DDOWN) - { - sort_author: - sort_by_author(current_list); - load_icons_first(current_list, false); - } + load_icons_first(current_list, false); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; } - else if(key_r) + else if (kDown & KEY_R) { - if(((kDown | kHeld)) & KEY_DUP) - { - draw_install(INSTALL_DUMPING_THEME); - Result res = dump_current_theme(); - if (R_FAILED(res)) DEBUG("Dump theme result: %lx\n", res); - else load_lists(lists); - } - else if(((kDown | kHeld)) & KEY_DDOWN) - { - draw_install(INSTALL_DUMPING_ALL_THEMES); - Result res = dump_all_themes(); - if (R_FAILED(res)) DEBUG("Dump all themes result: %lx\n", res); - else load_lists(lists); - } + extra_index = 2; + } + else if(kDown & KEY_L) + { + extra_index = 0; + } + } + else if(extra_index == 0) + { + if(kDown & KEY_DLEFT) + { + sort_path: + sort_by_filename(current_list); + load_icons_first(current_list, false); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if(kDown & KEY_DUP) + { + sort_name: + sort_by_name(current_list); + load_icons_first(current_list, false); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if(kDown & KEY_DDOWN) + { + sort_author: + sort_by_author(current_list); + load_icons_first(current_list, false); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if (kDown & KEY_B) + { + extra_index = 1; + } + } + else if(extra_index == 2) + { + if(kDown & KEY_DUP) + { + dump_single: + draw_install(INSTALL_DUMPING_THEME); + Result res = dump_current_theme(); + if (R_FAILED(res)) DEBUG("Dump theme result: %lx\n", res); + else load_lists(lists); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if(kDown & KEY_DDOWN) + { + draw_install(INSTALL_DUMPING_ALL_THEMES); + Result res = dump_all_themes(); + if (R_FAILED(res)) DEBUG("Dump all themes result: %lx\n", res); + else load_lists(lists); + extra_mode = false; + draw_mode = DRAW_MODE_LIST; + extra_index = 1; + } + else if(kDown &KEY_B) + { + extra_index = 1; } } continue; @@ -751,6 +874,7 @@ int main(void) { case MODE_THEMES: install_mode = true; + draw_mode = DRAW_MODE_INSTALL; break; case MODE_SPLASHES: draw_install(INSTALL_SPLASH); @@ -776,7 +900,7 @@ int main(void) toggle_shuffle(current_list); break; case MODE_SPLASHES: - if(draw_confirm("Are you sure you would like to delete\nthe installed splash?", current_list)) + if(draw_confirm(language.main.uninstall_confirm, current_list, draw_mode)) { draw_install(INSTALL_SPLASH_DELETE); splash_delete(); @@ -789,10 +913,11 @@ int main(void) else if(kDown & KEY_X) { extra_mode = true; + draw_mode = DRAW_MODE_EXTRA; } else if(kDown & KEY_SELECT) { - if(draw_confirm("Are you sure you would like to delete this?", current_list)) + if(draw_confirm(language.main.delete_confirm, current_list, draw_mode)) { draw_install(INSTALL_ENTRY_DELETE); delete_entry(current_entry, current_entry->is_zip); @@ -851,43 +976,49 @@ int main(void) u16 x = touch.px; u16 y = touch.py; - u16 arrowStartX = 152; + u16 arrowStartX = 136; u16 arrowEndX = arrowStartX+16; - #define BETWEEN(min, x, max) (min < x && x < max) if(kDown & KEY_TOUCH) { if(y < 24) { - if(current_list->entries != NULL && BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll > 0) + if(BETWEEN(320-168, x, 320-144)) { - change_selected(current_list, -current_list->entries_per_screen_v); + if (current_mode == MODE_THEMES) + { + toggle_shuffle(current_list); + } } else if(BETWEEN(320-144, x, 320-120)) { - switch(current_list->current_sort) - { - case SORT_NAME: - goto sort_author; - break; - case SORT_AUTHOR: - goto sort_path; - break; - case SORT_PATH: - goto sort_name; - break; - default: - break; - } + extra_mode = true; + draw_mode = DRAW_MODE_EXTRA; } else if(BETWEEN(320-120, x, 320-96)) { - goto enable_qr; + if (current_mode == MODE_THEMES) + { + install_mode = true; + draw_mode = DRAW_MODE_INSTALL; + } else if (current_mode == MODE_SPLASHES) + { + draw_install(INSTALL_SPLASH); + splash_install(current_entry); + for(int i = 0; i < current_list->entries_count; i++) + { + Entry_s * splash = ¤t_list->entries[i]; + if(splash == current_entry) + splash->installed = true; + else + splash->installed = false; + } + } } else if(BETWEEN(320-96, x, 320-72)) { - goto browse_themeplaza; + goto enable_qr; } else if(BETWEEN(320-72, x, 320-48)) { @@ -904,7 +1035,11 @@ int main(void) } else if(y >= 216) { - if(current_list->entries != NULL && BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll < current_list->entries_count - current_list->entries_per_screen_v) + if(current_list->entries != NULL && BETWEEN(arrowStartX, x, arrowEndX) && current_list->scroll > 0) + { + change_selected(current_list, -current_list->entries_per_screen_v); + } + else if(current_list->entries != NULL && BETWEEN(arrowStartX + 16, x, arrowEndX + 16) && current_list->scroll < current_list->entries_count - current_list->entries_per_screen_v) { change_selected(current_list, current_list->entries_per_screen_v); } diff --git a/source/remote.c b/source/remote.c index 7964514..5dff767 100644 --- a/source/remote.c +++ b/source/remote.c @@ -33,78 +33,12 @@ #include "music.h" #include "urls.h" #include "conversion.h" +#include "ui_strings.h" // forward declaration of special case used only here // TODO: replace this travesty with a proper handler static Result http_get_with_not_found_flag(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types, bool not_found_is_error); -static Instructions_s browser_instructions[MODE_AMOUNT] = { - { - .info_line = NULL, - .instructions = { - { - "\uE000 Download theme", - "\uE001 Go back" - }, - { - "\uE002 Hold for more", - "\uE003 Preview theme" - }, - { - "\uE004 Previous page", - "\uE005 Next page" - }, - { - "Exit", - NULL - } - } - }, - { - .info_line = NULL, - .instructions = { - { - "\uE000 Download splash", - "\uE001 Go back" - }, - { - "\uE002 Hold for more", - "\uE003 Preview splash" - }, - { - "\uE004 Previous page", - "\uE005 Next page" - }, - { - "Exit", - NULL - } - } - } -}; - -static Instructions_s extra_instructions = { - .info_line = "Release \uE002 to cancel or hold \uE006 and release \uE002 to do stuff", - .instructions = { - { - "\uE079 Jump to page", - "\uE07A Search tags" - }, - { - "\uE07B Toggle splash/theme", - "\uE07C Reload without cache" - }, - { - NULL, - NULL - }, - { - "Exit", - NULL - } - } -}; - static void free_icons(Entry_List_s * list) { if (list != NULL) @@ -237,7 +171,7 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod load_remote_entries(list, value, ignore_cache, loading_screen); else if (json_is_string(value) && !strcmp(key, THEMEPLAZA_JSON_ERROR_MESSAGE) && !strcmp(json_string_value(value), THEMEPLAZA_JSON_ERROR_MESSAGE_NOT_FOUND)) - throw_error("No results for this search.", ERROR_LEVEL_WARNING); + throw_error(language.remote.no_results, ERROR_LEVEL_WARNING); } } else @@ -246,7 +180,7 @@ static void load_remote_list(Entry_List_s * list, json_int_t page, EntryMode mod json_decref(root); } else - throw_error("Couldn't download Theme Plaza data.\nMake sure WiFi is on.", ERROR_LEVEL_WARNING); + throw_error(language.remote.check_wifi, ERROR_LEVEL_WARNING); free(page_json); } @@ -288,14 +222,15 @@ static bool load_remote_preview(const Entry_s * entry, C2D_Image * preview_image char * preview_buf = malloc(preview_size); u32 preview_buf_size = preview_size; memcpy(preview_buf, preview_png, preview_size); + u32 height = 480; - if (!(preview_buf_size = png_to_abgr(&preview_buf, preview_buf_size))) + if (!(preview_buf_size = png_to_abgr(&preview_buf, preview_buf_size, &height))) { free(preview_buf); return false; } - bool ret = load_preview_from_buffer(preview_buf, preview_buf_size, preview_image, preview_offset); + bool ret = load_preview_from_buffer(preview_buf, preview_buf_size, preview_image, preview_offset, height); free(preview_buf); if (ret && not_cached) // only save the preview if it loaded correctly - isn't corrupted @@ -380,12 +315,12 @@ jump_menu_callback(void * page_number, const char ** ppMessage, const char * tex int typed_value = atoi(text); if (typed_value > *(json_int_t *)page_number) { - *ppMessage = "The new page has to be\nsmaller or equal to the\nnumber of pages!"; + *ppMessage = language.remote.new_page_big; return SWKBD_CALLBACK_CONTINUE; } else if (typed_value == 0) { - *ppMessage = "The new position has to\nbe positive!"; + *ppMessage = language.remote.new_page_zero; return SWKBD_CALLBACK_CONTINUE; } return SWKBD_CALLBACK_OK; @@ -408,11 +343,11 @@ static void jump_menu(Entry_List_s * list) JSON_INTEGER_FORMAT, list->tp_current_page); swkbdSetInitialText(&swkbd, numbuf); - sprintf(numbuf, "Which page do you want to jump to?"); + sprintf(numbuf, language.remote.jump_page); swkbdSetHintText(&swkbd, numbuf); - swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Jump", true); + swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, language.remote.cancel, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, language.remote.jump, true); swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, max_chars); swkbdSetFilterCallback(&swkbd, jump_menu_callback, &list->tp_page_count); @@ -434,10 +369,10 @@ static void search_menu(Entry_List_s * list) SwkbdState swkbd; swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 2, max_chars); - swkbdSetHintText(&swkbd, "Which tags do you want to search for?"); + swkbdSetHintText(&swkbd, language.remote.tags); - swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Search", true); + swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, language.remote.cancel, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, language.remote.search, true); swkbdSetValidation(&swkbd, SWKBD_NOTBLANK, 0, max_chars); SwkbdButton button = swkbdInputText(&swkbd, search, max_chars); @@ -493,7 +428,7 @@ bool themeplaza_browser(EntryMode mode) SwkbdResult swkbd_res = swkbdGetResult(&swkbd); if (swkbd_res != SWKBD_PARENTAL_OK) { - throw_error("Parental Control validation failed!\nBrowser Access restricted.", ERROR_LEVEL_WARNING); + throw_error(language.remote.parental_fail, ERROR_LEVEL_WARNING); return downloaded; } } @@ -556,9 +491,9 @@ bool themeplaza_browser(EntryMode mode) } else { - Instructions_s instructions = browser_instructions[mode]; + Instructions_s instructions = language.remote_instructions[mode]; if (extra_mode) - instructions = extra_instructions; + instructions = language.remote_extra_instructions; draw_grid_interface(current_list, instructions); } @@ -950,7 +885,6 @@ static ParseResult parse_header(struct header * out, httpcContext * context, con return SUCCESS; } -#define ZIP_NOT_AVAILABLE "ZIP not found at this URL\nIf you believe this is an error, please\ncontact the site administrator" /* * call example: written = http_get("url", &filename, &buffer_to_download_to, &filesize, INSTALL_DOWNLOAD, "application/json"); @@ -962,6 +896,7 @@ Result http_get(const char * url, char ** filename, char ** buf, u32 * size, Ins static Result http_get_with_not_found_flag(const char * url, char ** filename, char ** buf, u32 * size, InstallType install_type, const char * acceptable_mime_types, bool not_found_is_error) { + const char *zip_not_available = language.remote.zip_not_found; Result ret; httpcContext context; char redirect_url[0x824] = {0}; @@ -1005,7 +940,7 @@ redirect: // goto here if we need to redirect break; case HTTPC_ERROR: DEBUG("httpc error %lx\n", _header.result_code); - snprintf(err_buf, ERROR_BUFFER_SIZE, "Error in HTTPC sysmodule - 0x%08lx.\nIf you are seeing this, please contact an\nAnemone developer on the Theme Plaza Discord.", _header.result_code); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.generic_httpc_error, _header.result_code); throw_error(err_buf, ERROR_LEVEL_ERROR); quit = true; httpcCloseContext(&context); @@ -1013,12 +948,12 @@ redirect: // goto here if we need to redirect case SEE_OTHER: if (strstr(url, THEMEPLAZA_BASE_URL)) { - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 303 See Other (Theme Plaza)\nHas this theme been approved?"); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http303_tp); goto error; } else { - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 303 See Other\nDownload the resource directly\nor contact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http303); goto error; } case REDIRECT: @@ -1040,7 +975,7 @@ redirect: // goto here if we need to redirect goto redirect; case SERVER_IS_MISBEHAVING: DEBUG("Server is misbehaving (provided resource with incorrect MIME)\n"); - snprintf(err_buf, ERROR_BUFFER_SIZE, ZIP_NOT_AVAILABLE); + snprintf(err_buf, ERROR_BUFFER_SIZE, zip_not_available); goto error; case HTTP_NOT_FOUND: if (!not_found_is_error) @@ -1050,59 +985,59 @@ redirect: // goto here if we need to redirect const char * http_error = parse == HTTP_NOT_FOUND ? "404 Not Found" : "410 Gone"; DEBUG("HTTP %s; URL: %s\n", http_error, url); if (strstr(url, THEMEPLAZA_BASE_URL) && parse == HTTP_NOT_FOUND) - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 404 Not Found\nHas this theme been approved?"); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http404); else - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP %s\nCheck that the URL is correct.", http_error); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http_err_url, http_error); goto error; case HTTP_UNACCEPTABLE: DEBUG("HTTP 406 Unacceptable; Accept: %s\n", acceptable_mime_types); - snprintf(err_buf, ERROR_BUFFER_SIZE, ZIP_NOT_AVAILABLE); + snprintf(err_buf, ERROR_BUFFER_SIZE, zip_not_available); goto error; case HTTP_UNAUTHORIZED: case HTTP_FORBIDDEN: case HTTP_PROXY_UNAUTHORIZED: DEBUG("HTTP %u: device not authenticated\n", parse); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP %s\nContact the site administrator.", parse == HTTP_UNAUTHORIZED - ? "401 Unauthorized" + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http_errcode_generic, parse == HTTP_UNAUTHORIZED + ? language.remote.http401 : parse == HTTP_FORBIDDEN - ? "403 Forbidden" - : "407 Proxy Authentication Required"); + ? language.remote.http403 + : language.remote.http407); goto error; case HTTP_URI_TOO_LONG: DEBUG("HTTP 414; URL is too long, maybe too many redirects?\n"); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 414 URI Too Long\nThe QR code points to a really long URL.\nDownload the file directly."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http414); goto error; case HTTP_IM_A_TEAPOT: DEBUG("HTTP 418 I'm a teapot\n"); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 418 I'm a teapot\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http418); goto error; case HTTP_UPGRADE_REQUIRED: DEBUG("HTTP 426; HTTP/2 required\n"); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 426 Upgrade Required\nThe 3DS cannot connect to this server.\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http426); goto error; case HTTP_LEGAL_REASONS: DEBUG("HTTP 451; URL: %s\n", url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 451 Unavailable for Legal Reasons\nSome entity is preventing access\nto the host server for legal reasons."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http451); goto error; case HTTP_INTERNAL_SERVER_ERROR: DEBUG("HTTP 500; URL: %s\n", url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 500 Internal Server Error\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http500); goto error; case HTTP_BAD_GATEWAY: DEBUG("HTTP 502; URL: %s\n", url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 502 Bad Gateway\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http502); goto error; case HTTP_SERVICE_UNAVAILABLE: DEBUG("HTTP 503; URL: %s\n", url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 503 Service Unavailable\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http503); goto error; case HTTP_GATEWAY_TIMEOUT: DEBUG("HTTP 504; URL: %s\n", url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP 504 Gateway Timeout\nContact the site administrator."); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http504); goto error; default: DEBUG("HTTP %u; URL: %s\n", parse, url); - snprintf(err_buf, ERROR_BUFFER_SIZE, "HTTP %u\nIf you believe this is unexpected, please\ncontact the site administrator.", parse); + snprintf(err_buf, ERROR_BUFFER_SIZE, language.remote.http_unexpected, parse); goto error; } diff --git a/source/splashes.c b/source/splashes.c index 477fd7d..c2056d8 100644 --- a/source/splashes.c +++ b/source/splashes.c @@ -27,6 +27,7 @@ #include "unicode.h" #include "fs.h" #include "draw.h" +#include "ui_strings.h" void splash_delete(void) { @@ -54,7 +55,7 @@ void splash_install(const Entry_s * splash) if(size == 0 && bottom_size == 0) { - throw_error("No splash.bin or splashbottom.bin found.\nIs this a splash?", ERROR_LEVEL_WARNING); + throw_error(language.splashes.no_splash_found, ERROR_LEVEL_WARNING); } else { @@ -65,7 +66,7 @@ void splash_install(const Entry_s * splash) if(config_buf[0xC] == 0) { free(config_buf); - throw_error("WARNING: Splashes are disabled in Luma Config", ERROR_LEVEL_WARNING); + throw_error(language.splashes.splash_disabled, ERROR_LEVEL_WARNING); } } } @@ -127,4 +128,4 @@ void splash_check_installed(void * void_arg) } } #endif -} \ No newline at end of file +} diff --git a/source/themes.c b/source/themes.c index 9075587..337852e 100644 --- a/source/themes.c +++ b/source/themes.c @@ -28,6 +28,7 @@ #include "unicode.h" #include "fs.h" #include "draw.h" +#include "ui_strings.h" #define BODY_CACHE_SIZE 0x150000 #define BGM_MAX_SIZE 0x337000 @@ -81,7 +82,7 @@ static Result install_theme_internal(const Entry_List_s * themes, int installmod { free(body); DEBUG("body not found\n"); - throw_error("No body_LZ.bin found - is this a theme?", ERROR_LEVEL_WARNING); + throw_error(language.themes.no_body_found, ERROR_LEVEL_WARNING); return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND); } @@ -118,9 +119,12 @@ static Result install_theme_internal(const Entry_List_s * themes, int installmod return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_TOO_LARGE); } - if (music[0x62] == 1) + if (music_size > 0) { - mono_audio = true; + if (music[0x62] == 1) + { + mono_audio = true; + } } } @@ -177,7 +181,7 @@ static Result install_theme_internal(const Entry_List_s * themes, int installmod { free(body); DEBUG("body not found\n"); - throw_error("No body_LZ.bin found - is this a theme?", ERROR_LEVEL_WARNING); + throw_error(language.themes.no_body_found, ERROR_LEVEL_WARNING); return MAKERESULT(RL_PERMANENT, RS_CANCELED, RM_APPLICATION, RD_NOT_FOUND); } @@ -298,7 +302,7 @@ static Result install_theme_internal(const Entry_List_s * themes, int installmod //---------------------------------------- if (mono_audio) { - throw_error("One or more installed themes use mono audio.\nMono audio causes a number of issues.\nCheck the wiki for more information.", ERROR_LEVEL_WARNING); + throw_error(language.themes.mono_warn, ERROR_LEVEL_WARNING); } return 0; } @@ -342,7 +346,7 @@ dir_name_callback(void * data, const char ** ppMessage, const char * text, size_ (void)data; if(strpbrk(text, "><\"?;:/\\+,.|[=]")) { - *ppMessage = "Illegal character used."; + *ppMessage = language.themes.illegal_char; return SWKBD_CALLBACK_CONTINUE; } return SWKBD_CALLBACK_OK; @@ -356,10 +360,10 @@ Result dump_current_theme(void) SwkbdState swkbd; swkbdInit(&swkbd, SWKBD_TYPE_WESTERN, 2, max_chars); - swkbdSetHintText(&swkbd, "Name of output folder"); + swkbdSetHintText(&swkbd, language.themes.name_folder); - swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, "Cancel", false); - swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, "Done", true); + swkbdSetButton(&swkbd, SWKBD_BUTTON_LEFT, language.themes.cancel, false); + swkbdSetButton(&swkbd, SWKBD_BUTTON_RIGHT, language.themes.done, true); swkbdSetValidation(&swkbd, SWKBD_NOTEMPTY_NOTBLANK, 0, max_chars); swkbdSetFilterCallback(&swkbd, dir_name_callback, NULL); diff --git a/source/ui_strings.c b/source/ui_strings.c new file mode 100644 index 0000000..1a452f1 --- /dev/null +++ b/source/ui_strings.c @@ -0,0 +1,381 @@ +/* +* This file is part of Anemone3DS +* Copyright (C) 2016-2024 Contributors in CONTRIBUTORS.md +* +* 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 "ui_strings.h" +#include "fs.h" + +const Language_s language_english = { + .normal_instructions = + { + { + .info_line = NULL, + .instructions = { + { + "\uE000 Install Theme(s)", + "\uE001 Queue shuffle theme" + }, + { + "\uE002 More options", + "\uE003 Preview theme" + }, + { + "\uE004 Switch to splashes", + "\uE005 Scan QR code" + }, + { + "Exit", + "Delete from SD" + } + } + }, + { + .info_line = NULL, + .instructions = { + { + "\uE000 Install splash", + "\uE001 Delete installed splash" + }, + { + "\uE002 More options", + "\uE003 Preview splash" + }, + { + "\uE004 Switch to themes", + "\uE005 Scan QR code" + }, + { + "Exit", + "Delete from SD" + } + } + } + }, + + .install_instructions = + { + .info_line = "\uE001 Cancel theme install", + .instructions = { + { + "\uE079 Normal install", + "\uE07A Shuffle install" + }, + { + "\uE07B BGM-only install", + "\uE07C No-BGM install" + }, + { + NULL, + NULL + }, + { + "Exit", + NULL + } + } + }, + + .extra_instructions = + { + { + .info_line = "\uE001 Leave sorting menu", + .instructions = { + { + "\uE079 Sort by name", + "\uE07A Sort by author" + }, + { + "\uE07B Sort by filename", + NULL + }, + { + NULL, + NULL + }, + { + "Exit", + NULL + } + } + }, + { + .info_line = "\uE001 Leave extra menu", + .instructions = { + { + "\uE079 Jump in the list", + "\uE07A Reload broken icons" + }, + { + "\uE07B Browse ThemePlaza", + NULL + }, + { + "\uE004 Sorting menu", + "\uE005 Dumping menu" + }, + { + "Exit", + NULL + } + } + }, + { + .info_line = "\uE001 Leave dump menu", + .instructions = { + { + "\uE079 Dump Current Theme", + "\uE07A Dump All Themes" + }, + { + NULL, + NULL + }, + { + NULL, + NULL + }, + { + "Exit", + NULL + } + } + } + }, + .camera = + { + .quit = "Press \uE005 To Quit", + .thread_error = "Capture cam thread creation failed\nPlease report this to the developers", + .zip_not_theme_splash = "Zip downloaded is neither\na splash nor a theme", + .file_not_zip = "File downloaded isn't a zip.", + .download_failed = "Download failed.", + }, + .draw = + { + .theme_mode = "Theme mode", + .splash_mode = "Splash mode", + .no_themes = "No theme found", + .no_splashes = "No splash found", + .qr_download = "Press \uE005 to download from QR", + .switch_splashes = "Or \uE004 to switch to splashes", + .switch_themes = "Or \uE004 to switch to themes", + .quit = "Or to quit", + .start_pos = 162, // Adjust x pos of start glyph to line up with quit string + .by = "By ", + .selected = "Selected:", + .sel = "Sel.:", + .tp_theme_mode = "ThemePlaza Theme mode", + .tp_splash_mode = "ThemePlaza Splash mode", + .search = "Search...", + .page = "Page:", + .err_quit = "Press \uE000 to quit.", + .warn_continue = "Press \uE000 to continue.", + .yes_no = "\uE000 Yes \uE001 No", + .load_themes = "Loading themes, please wait...", + .load_splash = "Loading splashes, please wait...", + .load_icons = "Loading icons, please wait...", + .install_splash = "Installing a splash...", + .delete_splash = "Deleting installed splash...", + .install_theme = "Installing a single theme...", + .install_shuffle = "Installing shuffle themes...", + .install_bgm = "Installing BGM-only theme...", + .install_no_bgm = "Installing theme without BGM...", + .downloading = "Downloading...", + .checking_dl = "Checking downloaded file...", + .delete_sd = "Deleting from SD...", + .download_themes = "Downloading theme list, please wait...", + .download_splashes = "Downloading splash list, please wait...", + .download_preview = "Downloading preview, please wait...", + .download_bgm = "Downloading BGM, please wait...", + .dump_single = "Dumping theme, please wait...", + .dump_all_official = "Dumping official themes, please wait...", + }, + .fs = + { + .illegal_input = "Input must not contain:\n" ILLEGAL_CHARS, + .new_or_overwrite = "Choose a new filename or tap Overwrite", + .cancel = "Cancel", + .overwrite = "Overwrite", + .rename = "Rename", + .swkbd_fail = "???\nTry a USB keyboard", // Should never be used + .sd_full = "SD card is full.\nDelete some themes to make space.", + .fs_error = "Error:\nGet a new SD card.", + }, + .loading = + { + .no_preview = "No preview found.", + }, + .main = + { + .position_too_big = "The new position has to be\nsmaller or equal to the\nnumber of entries!", + .position_zero = "The new position has to\nbe positive!", + .jump_q = "Where do you want to jump to?\nMay cause icons to reload.", + .cancel = "Cancel", + .jump = "Jump", + .no_theme_extdata = "Theme extdata does not exist!\nSet a default theme from the home menu.", + .loading_qr = "Loading QR Scanner...", + .no_wifi = "Please connect to Wi-Fi before scanning QR codes", + .qr_homebrew = "QR scanning doesnt work from the Homebrew\nLauncher, use the ThemePlaza browser instead.", + .camera_broke = "Your camera seems to have a problem,\nunable to scan QR codes.", + .too_many_themes = "You have too many themes selected.", + .not_enough_themes = "You don't have enough themes selected.", + .uninstall_confirm = "Are you sure you would like to delete\nthe installed splash?", + .delete_confirm = "Are you sure you would like to delete this?", + }, + .remote = + { + .no_results = "No results for this search.", + .check_wifi = "Couldn't download Theme Plaza data.\nMake sure WiFi is on.", + .new_page_big = "The new page has to be\nsmaller or equal to the\nnumber of pages!", + .new_page_zero = "The new position has to\nbe positive!", + .jump_page = "Which page do you want to jump to?", + .cancel = "Cancel", + .jump = "Jump", + .tags = "Which tags do you want to search for?", + .search = "Search", + .parental_fail = "Parental Control validation failed!\nBrowser Access restricted.", + .zip_not_found = "ZIP not found at this URL\nIf you believe this is an error, please\ncontact the site administrator", + .generic_httpc_error = "Error in HTTPC sysmodule - 0x%08lx.\nIf you are seeing this, please contact an\nAnemone developer on the Theme Plaza Discord.", + .http303_tp = "HTTP 303 See Other (Theme Plaza)\nHas this theme been approved?", + .http303 = "HTTP 303 See Other\nDownload the resource directly\nor contact the site administrator.", + .http404 = "HTTP 404 Not Found\nHas this theme been approved?", + .http_err_url = "HTTP %s\nCheck that the URL is correct.", + .http_errcode_generic = "HTTP %s\nContact the site administrator.", + .http401 = "401 Unauthorized", + .http403 = "403 Forbidden", + .http407 = "407 Proxy Authentication Required", + .http414 = "HTTP 414 URI Too Long\nThe QR code points to a really long URL.\nDownload the file directly.", + .http418 = "HTTP 418 I'm a teapot\nContact the site administrator.", + .http426 = "HTTP 426 Upgrade Required\nThe 3DS cannot connect to this server.\nContact the site administrator.", + .http451 = "HTTP 451 Unavailable for Legal Reasons\nSome entity is preventing access\nto the host server for legal reasons.", + .http500 = "HTTP 500 Internal Server Error\nContact the site administrator.", + .http502 = "HTTP 502 Bad Gateway\nContact the site administrator.", + .http503 = "HTTP 503 Service Unavailable\nContact the site administrator.", + .http504 = "HTTP 504 Gateway Timeout\nContact the site administrator.", + .http_unexpected = "HTTP %u\nIf you believe this is unexpected, please\ncontact the site administrator.", + }, + .remote_instructions = + { + { + .info_line = NULL, + .instructions = { + { + "\uE000 Download theme", + "\uE001 Go back" + }, + { + "\uE002 Hold for more", + "\uE003 Preview theme" + }, + { + "\uE004 Previous page", + "\uE005 Next page" + }, + { + "Exit", + NULL + } + } + }, + { + .info_line = NULL, + .instructions = { + { + "\uE000 Download splash", + "\uE001 Go back" + }, + { + "\uE002 Hold for more", + "\uE003 Preview splash" + }, + { + "\uE004 Previous page", + "\uE005 Next page" + }, + { + "Exit", + NULL + } + } + } + }, + .remote_extra_instructions = + { + .info_line = "Release \uE002 to cancel or hold \uE006 and release \uE002 to do stuff", + .instructions = { + { + "\uE079 Jump to page", + "\uE07A Search tags" + }, + { + "\uE07B Toggle splash/theme", + "\uE07C Reload without cache" + }, + { + NULL, + NULL + }, + { + "Exit", + NULL + } + } + }, + .splashes = + { + .no_splash_found = "No splash.bin or splashbottom.bin found.\nIs this a splash?", + .splash_disabled = "WARNING: Splashes are disabled in Luma Config", + }, + .themes = + { + .no_body_found = "No body_LZ.bin found - is this a theme?", + .mono_warn = "One or more installed themes use mono audio.\nMono audio causes a number of issues.\nCheck the wiki for more information.", + .illegal_char = "Illegal character used.", + .name_folder = "Name of output folder", + .cancel = "Cancel", + .done = "Done" + } +}; + +Language_s init_strings(CFG_Language lang) +{ + switch (lang) + { + case CFG_LANGUAGE_JP: + case CFG_LANGUAGE_FR: + case CFG_LANGUAGE_DE: + case CFG_LANGUAGE_IT: + case CFG_LANGUAGE_ES: + case CFG_LANGUAGE_ZH: + case CFG_LANGUAGE_KO: + case CFG_LANGUAGE_NL: + case CFG_LANGUAGE_PT: + case CFG_LANGUAGE_RU: + case CFG_LANGUAGE_TW: + case CFG_LANGUAGE_EN: + return language_english; + default: + return language_english; + } +}