diff --git a/.gitignore b/.gitignore index 1c0b063..46a00b4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ host/__pycache__ host/build host/dist host/nxdumptool -romfs/shaders *.elf *.nacp *.nro @@ -16,4 +15,4 @@ romfs/shaders *.spec *.exe /code_templates/tmp/* -/source/main.c + diff --git a/.gitmodules b/.gitmodules index 3b33f29..625a3bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ -[submodule "borealis"] - path = libs/borealis - url = https://github.com/natinusala/borealis - branch = legacy [submodule "libusbhsfs"] path = libs/libusbhsfs url = https://github.com/DarkMatterCore/libusbhsfs branch = dev +[submodule "borealis"] + path = libs/borealis + url = https://github.com/DarkMatterCore/borealis + branch = legacy diff --git a/build.sh b/build.sh deleted file mode 100644 index 6feffa9..0000000 --- a/build.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -cd "$(dirname "${BASH_SOURCE[0]}")" - -tar_filename="nxdumptool-rewrite_poc_$(git rev-parse --short HEAD).tar.bz2" - -rm -f ./*.tar.bz2 - -rm -rf ./code_templates/tmp -mkdir ./code_templates/tmp - -make clean_all - -for f in ./code_templates/*.c; do - basename="$(basename "$f")" - filename="${basename%.*}" - - if [[ $filename == "dump_title_infos" ]]; then - continue - fi - - echo $filename - - rm -f ./source/main.c - cp $f ./source/main.c - - make -j$(nproc) - - mkdir ./code_templates/tmp/$filename - cp ./nxdumptool.nro ./code_templates/tmp/$filename/nxdumptool.nro - #cp ./nxdumptool.elf ./code_templates/tmp/$filename/nxdumptool.elf - - rm -f ./build/main.o ./build/main.d ./build/nxdt_utils.o ./build/nxdt_utils.d ./build/usb.o ./build/usb.d ./build/nxdt_log.o ./build/nxdt_log.d ./nxdumptool.* -done - -make clean_all - -cd ./code_templates/tmp -tar -cjf ../../$tar_filename * - -cd ../.. -rm -f ./source/main.c -rm -rf ./code_templates/tmp - -read -p "Press any key to finish ..." diff --git a/include/core/bfttf.h b/include/core/bfttf.h index 214ce44..e987941 100644 --- a/include/core/bfttf.h +++ b/include/core/bfttf.h @@ -42,9 +42,9 @@ typedef enum { /// Loosely based on PlFontData. typedef struct { - u8 type; ///< BfttfFontType. - u32 size; ///< Decoded BFTFF font size. - void *ptr; ///< Pointer to font data. + u8 type; ///< BfttfFontType. + u32 size; ///< Decoded BFTFF font size. + void *address; ///< Font data address. } BfttfFontData; /// Initializes the BFTTF interface. diff --git a/include/core/common.h b/include/core/common.h index 40cc7d0..e212732 100644 --- a/include/core/common.h +++ b/include/core/common.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #ifndef __cplusplus diff --git a/include/core/nxdt_utils.h b/include/core/nxdt_utils.h index d661ce3..ebad338 100644 --- a/include/core/nxdt_utils.h +++ b/include/core/nxdt_utils.h @@ -66,16 +66,6 @@ void utilsJoinThread(Thread *thread); /// Returns true if the application is running under a development unit. bool utilsIsDevelopmentUnit(void); -/// Functions to retrieve down/held buttons from all input controllers. -/// utilsScanPads() must be called before utilsGetButtonsDown() / utilsGetButtonsHeld(). -void utilsScanPads(void); -u64 utilsGetButtonsDown(void); -u64 utilsGetButtonsHeld(void); - -/// Waits until any button matching the provided input flag is pressed. -/// If 'flag' is set to zero, any button press will count. -void utilsWaitForButtonPress(u64 flag); - /// Formats a string and appends it to the provided buffer. /// If the buffer isn't big enough to hold both its current contents and the new formatted string, it will be resized. __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...); diff --git a/libs/borealis b/libs/borealis index cbdc1b6..64a92a7 160000 --- a/libs/borealis +++ b/libs/borealis @@ -1 +1 @@ -Subproject commit cbdc1b65314d1eeb2799deae5cf6f113d6d67b46 +Subproject commit 64a92a76125190104e44e8a1067ac74e74c0011f diff --git a/romfs/i18n/en-US/brls.json b/romfs/i18n/en-US/brls.json new file mode 100644 index 0000000..6fe8fb3 --- /dev/null +++ b/romfs/i18n/en-US/brls.json @@ -0,0 +1,15 @@ +{ + "hints": { + "ok": "OK", + "back": "Back", + "exit": "Exit" + }, + + "crash_frame": { + "button": "OK" + }, + + "thumbnail_sidebar": { + "save": "Save" + } +} diff --git a/romfs/i18n/en-US/custom_layout.json b/romfs/i18n/en-US/custom_layout.json new file mode 100644 index 0000000..86a6ba3 --- /dev/null +++ b/romfs/i18n/en-US/custom_layout.json @@ -0,0 +1,5 @@ +{ + "first_button": "First button", + "second_button": "Second button", + "third_button": "Third button" +} diff --git a/romfs/i18n/en-US/installer.json b/romfs/i18n/en-US/installer.json new file mode 100644 index 0000000..1fa8482 --- /dev/null +++ b/romfs/i18n/en-US/installer.json @@ -0,0 +1,18 @@ +{ + "open": "Open example installer", + + "title": "My great installer", + + "stage1": { + "text": "Here, you would normally do useful things", + "button": "Go to step 2" + }, + + "stage2": { + "text": "Example loading display" + }, + + "stage3": { + "button": "Finish" + } +} diff --git a/romfs/i18n/en-US/main.json b/romfs/i18n/en-US/main.json new file mode 100644 index 0000000..f265712 --- /dev/null +++ b/romfs/i18n/en-US/main.json @@ -0,0 +1,77 @@ +{ + "name": "Borealis Example App", + "tabs": { + "first": "First tab", + "second": "Second tab", + "third": "Third tab", + "fourth": "Fourth tab", + "custom_navigation_tab": "Custom Layout" + }, + + "pozznx": { + "open": "Open a dialog", + "warning": "Warning: PozzNX will wipe all data on your Switch and render it inoperable, do you want to proceed?", + "running": "Running PozzNX...", + "continue": "Continue" + }, + + "notify": "Post a random notification", + + "tv": { + "resolution": "TV Resolution", + "automatic": "Automatic" + }, + + "i18n": { + "title": "Language: {0} ({1})", + "lang": "English" + }, + + "jank": { + "jank": "User Interface Jankiness", + "native": "Native", + "minimal": "Minimal", + "regular": "Regular", + "maximum": "Maximum", + "saxophone": "SX OS", + "vista": "Windows Vista", + "ios": "iOS 14" + }, + + "divide": { + "title": "Divide by 0", + "description": "Can the Switch do it?", + "crash": "The software was closed because an error occured:\nSIGABRT (signal 6)" + }, + + "more": "For more information about how to use Nintendo Switch and its features, please refer to the Nintendo Support Website on your smart device or PC.", + + "actions": { + "title": "Custom Actions", + "notify": "Show notification", + "triggered": "Custom Action triggered" + }, + + "layers": { + "title": "Select Layer", + "layer1": "Layer 1", + "layer2": "Layer 2", + + "item1": "Item 1", + "item2": "Item 2", + "item3": "Item 3" + }, + + "keyboard": { + "string": { + "title": "Open Keyboard", + "default": "Default text", + "help": "Help message" + }, + "number": { + "title": "Open Num Keyboard", + "help": "Help message" + } + } +} + diff --git a/romfs/i18n/en-US/popup.json b/romfs/i18n/en-US/popup.json new file mode 100644 index 0000000..e1c0084 --- /dev/null +++ b/romfs/i18n/en-US/popup.json @@ -0,0 +1,13 @@ +{ + "open": "Open popup", + + "red": "Red", + "green": "Green", + "blue": "Blue", + + "title": "Popup title", + "subtitle": { + "left": "Subtitle left", + "right": "Subtitle right" + } +} diff --git a/romfs/i18n/fr/brls.json b/romfs/i18n/fr/brls.json new file mode 100644 index 0000000..9ed2173 --- /dev/null +++ b/romfs/i18n/fr/brls.json @@ -0,0 +1,15 @@ +{ + "hints": { + "ok": "OK", + "back": "Retour", + "exit": "Quitter" + }, + + "crash_frame": { + "button": "OK" + }, + + "thumbnail_sidebar": { + "save": "Sauvegarder" + } +} diff --git a/romfs/i18n/fr/custom_layout.json b/romfs/i18n/fr/custom_layout.json new file mode 100644 index 0000000..9f29306 --- /dev/null +++ b/romfs/i18n/fr/custom_layout.json @@ -0,0 +1,5 @@ +{ + "first_button": "Premier bouton", + "second_button": "Deuxième bouton", + "third_button": "Troisième bouton" +} diff --git a/romfs/i18n/fr/installer.json b/romfs/i18n/fr/installer.json new file mode 100644 index 0000000..5ef768e --- /dev/null +++ b/romfs/i18n/fr/installer.json @@ -0,0 +1,18 @@ +{ + "open": "Ouvrir l'installateur de démo", + + "title": "Mon super installateur", + + "stage1": { + "text": "Ici vous devriez normalement faire des choses utiles", + "button": "Aller à l'étape 2" + }, + + "stage2": { + "text": "Exemple de chargement" + }, + + "stage3": { + "button": "Terminer" + } +} diff --git a/romfs/i18n/fr/main.json b/romfs/i18n/fr/main.json new file mode 100644 index 0000000..160cb6f --- /dev/null +++ b/romfs/i18n/fr/main.json @@ -0,0 +1,77 @@ +{ + "name": "App de Démo Borealis", + "tabs": { + "first": "Premier onglet", + "second": "Deuxième onglet", + "third": "Troisième onglet", + "fourth": "Quatrième onglet", + "custom_navigation_tab": "Disposition personnalisée" + }, + + "pozznx": { + "open": "Ouvrir une boîte de dialogue", + "warning": "Avertissement: PozzNX va effacer toutes les données de votre Switch et la rendre inutilisable, voulez-vous continuer ?", + "running": "Exécution de PozzNX...", + "continue": "Continuer" + }, + + "notify": "Afficher une notification aléatoire", + + "tv": { + "resolution": "Résolution du téléviseur", + "automatic": "Automatique" + }, + + "i18n": { + "title": "Langue : {0} ({1})", + "lang": "Français" + }, + + "jank": { + "jank": "Bâclement de l'interface utilisateur", + "native": "Natif", + "minimal": "Minimal", + "regular": "Normal", + "maximum": "Maximum", + "saxophone": "SX OS", + "vista": "Windows Vista", + "ios": "iOS 14" + }, + + "divide": { + "title": "Diviser par 0", + "description": "Est-ce que la Switch peut le faire ?", + "crash": "Le logiciel a été arrêté à cause d'une erreur:\nSIGABRT (signal 6)" + }, + + "more": "Si vous désirez en savoir plus sur la console Nintendo Switch et ses fonctionnalités, visitez le site d'assistance Nintendo depuis un appareil connecté ou un ordinateur.", + + "actions": { + "title": "Actions personnalisées", + "notify": "Afficher une notification", + "triggered": "Action personnalisée déclenchée" + }, + + "layers": { + "title": "Choisir une couche", + "layer1": "Couche 1", + "layer2": "Couche 2", + + "item1": "Item 1", + "item2": "Item 2", + "item3": "Item 3" + }, + + "keyboard": { + "string": { + "title": "Ouvrir le clavier", + "default": "Texte par défaut", + "help": "Message d'aide" + }, + "number": { + "title": "Ouvrir le clavier numérique", + "help": "Message d'aide" + } + } +} + diff --git a/romfs/i18n/fr/popup.json b/romfs/i18n/fr/popup.json new file mode 100644 index 0000000..f1afbab --- /dev/null +++ b/romfs/i18n/fr/popup.json @@ -0,0 +1,13 @@ +{ + "open": "Ouvrir une popup", + + "red": "Rouge", + "green": "Vert", + "blue": "Bleu", + + "title": "Titre de la popup", + "subtitle": { + "left": "Sous-titre gauche", + "right": "Sous-titre right" + } +} diff --git a/romfs/material/LICENSE.txt b/romfs/material/LICENSE.txt new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/romfs/material/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/romfs/material/MaterialIcons-Regular.ttf b/romfs/material/MaterialIcons-Regular.ttf new file mode 100644 index 0000000..7015564 Binary files /dev/null and b/romfs/material/MaterialIcons-Regular.ttf differ diff --git a/source/core/bfttf.c b/source/core/bfttf.c index 6b4d561..89292d1 100644 --- a/source/core/bfttf.c +++ b/source/core/bfttf.c @@ -207,7 +207,7 @@ bool bfttfGetFontByType(BfttfFontData *font_data, u8 font_type) font_data->type = font_type; font_data->size = (font_info->size - 8); - font_data->ptr = (font_info->data + 8); + font_data->address = (font_info->data + 8); return true; } diff --git a/source/core/nxdt_utils.c b/source/core/nxdt_utils.c index 6c47c37..b07a2e4 100644 --- a/source/core/nxdt_utils.c +++ b/source/core/nxdt_utils.c @@ -36,8 +36,6 @@ static bool g_resourcesInit = false, g_isDevUnit = false; static Mutex g_resourcesMutex = 0; -static PadState g_padState = {0}; - static FsFileSystem *g_sdCardFileSystem = NULL; static FsStorage g_emmcBisSystemPartitionStorage = {0}; @@ -51,6 +49,8 @@ static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown; static AppletHookCookie g_systemOverclockCookie = {0}; +static int g_nxLinkSocketFd = -1; + static const char *g_sizeSuffixes[] = { "B", "KiB", "MiB", "GiB" }; static const u32 g_sizeSuffixesCount = MAX_ELEMENTS(g_sizeSuffixes); @@ -73,15 +73,11 @@ bool utilsInitializeResources(void) { mutexLock(&g_resourcesMutex); + Result rc = 0; + bool ret = g_resourcesInit; if (ret) goto end; - /* Configure input. */ - /* Up to 8 different, full controller inputs. */ - /* Individual Joy-Cons not supported. */ - padConfigureInput(8, HidNpadStyleSet_NpadFullCtrl); - padInitializeWithMask(&g_padState, 0x1000000FFUL); - /* Retrieve pointer to the application launch path. */ if (g_argc && g_argv) { @@ -183,6 +179,14 @@ bool utilsInitializeResources(void) /* Setup an applet hook to change the hardware clocks after a system mode change (docked <-> undocked). */ appletHook(&g_systemOverclockCookie, utilsOverclockSystemAppletHook, NULL); + /* Mount application RomFS. */ + romfsInit(); + + /* Redirect stdout and stderr over network to nxlink. */ + rc = socketInitializeDefault(); + if (R_SUCCEEDED(rc)) g_nxLinkSocketFd = nxlinkConnectToHost(true, true); + + /* Update flags. */ ret = g_resourcesInit = true; end: @@ -197,6 +201,18 @@ void utilsCloseResources(void) { mutexLock(&g_resourcesMutex); + /* Close nxlink socket. */ + if (g_nxLinkSocketFd >= 0) + { + close(g_nxLinkSocketFd); + g_nxLinkSocketFd = -1; + } + + socketExit(); + + /* Unmount application RomFS. */ + romfsExit(); + /* Unset our overclock applet hook. */ appletUnhook(&g_systemOverclockCookie); @@ -327,34 +343,6 @@ bool utilsIsDevelopmentUnit(void) return ret; } -void utilsScanPads(void) -{ - padUpdate(&g_padState); -} - -u64 utilsGetButtonsDown(void) -{ - return padGetButtonsDown(&g_padState); -} - -u64 utilsGetButtonsHeld(void) -{ - return padGetButtons(&g_padState); -} - -void utilsWaitForButtonPress(u64 flag) -{ - /* Don't consider stick movement as button inputs. */ - if (!flag) flag = ~(HidNpadButton_StickLLeft | HidNpadButton_StickLRight | HidNpadButton_StickLUp | HidNpadButton_StickLDown | HidNpadButton_StickRLeft | HidNpadButton_StickRRight | \ - HidNpadButton_StickRUp | HidNpadButton_StickRDown); - - while(appletMainLoop()) - { - utilsScanPads(); - if (utilsGetButtonsDown() & flag) break; - } -} - __attribute__((format(printf, 3, 4))) bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...) { if (!dst || !dst_size || (!*dst && *dst_size) || (*dst && !*dst_size) || !fmt || !*fmt) @@ -746,7 +734,20 @@ static void utilsOverclockSystemAppletHook(AppletHookType hook, void *param) static void utilsPrintConsoleError(void) { + PadState pad = {0}; char msg[0x100] = {0}; + + /* Don't consider stick movement as button inputs. */ + u64 flag = ~(HidNpadButton_StickLLeft | HidNpadButton_StickLRight | HidNpadButton_StickLUp | HidNpadButton_StickLDown | HidNpadButton_StickRLeft | HidNpadButton_StickRRight | \ + HidNpadButton_StickRUp | HidNpadButton_StickRDown); + + /* Configure input. */ + /* Up to 8 different, full controller inputs. */ + /* Individual Joy-Cons not supported. */ + padConfigureInput(8, HidNpadStyleSet_NpadFullCtrl); + padInitializeWithMask(&pad, 0x1000000FFUL); + + /* Get last log message. */ logGetLastMessage(msg, sizeof(msg)); consoleInit(NULL); @@ -757,7 +758,11 @@ static void utilsPrintConsoleError(void) consoleUpdate(NULL); - utilsWaitForButtonPress(0); + while(appletMainLoop()) + { + padUpdate(&pad); + if (padGetButtonsDown(&pad) & flag) break; + } consoleExit(NULL); } diff --git a/source/core/services.c b/source/core/services.c index 662952e..4c28d01 100644 --- a/source/core/services.c +++ b/source/core/services.c @@ -58,6 +58,8 @@ static ServiceInfo g_serviceInfo[] = { { false, "nifm:u", NULL, &servicesNifmUserInitialize, &nifmExit }, { false, "clk", &servicesClkGetServiceType, NULL, NULL }, /* Placeholder for pcv / clkrst. */ { false, "es", NULL, &esInitialize, &esExit }, + { false, "set", NULL, &setInitialize, &setExit }, + { false, "set:sys", NULL, &setsysInitialize, &setsysExit }, { false, "set:cal", NULL, &setcalInitialize, &setcalExit } }; diff --git a/source/custom_layout_tab.cpp b/source/custom_layout_tab.cpp new file mode 100644 index 0000000..6feb557 --- /dev/null +++ b/source/custom_layout_tab.cpp @@ -0,0 +1,97 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2020 natinusala + + 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 . +*/ + +#include "custom_layout_tab.hpp" + +using namespace brls::i18n::literals; + +CustomLayoutTab::CustomLayoutTab() +{ + // Create views + this->firstButton = new brls::Button(brls::ButtonStyle::REGULAR); + this->firstButton->setLabel("custom_layout/first_button"_i18n); + this->addView(this->firstButton); + + this->secondButton = new brls::Button(brls::ButtonStyle::REGULAR); + this->secondButton->setLabel("custom_layout/second_button"_i18n); + this->addView(this->secondButton); + + this->thirdButton = new brls::Button(brls::ButtonStyle::REGULAR); + this->thirdButton->setLabel("custom_layout/third_button"_i18n); + this->addView(this->thirdButton); + + // Populate custom navigation map + this->navigationMap.add( + this->firstButton, + brls::FocusDirection::RIGHT, + this->secondButton); + + this->navigationMap.add( + this->secondButton, + brls::FocusDirection::LEFT, + this->firstButton); + + this->navigationMap.add( + this->secondButton, + brls::FocusDirection::DOWN, + this->thirdButton); + + this->navigationMap.add( + this->thirdButton, + brls::FocusDirection::UP, + this->secondButton); +} + +#define BUTTON_WIDTH 300 +#define BUTTON_HEIGHT 50 +#define PADDING 75 + +void CustomLayoutTab::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) +{ + int x = this->getX(); + int y = this->getY(); + + // Fully custom layout + this->firstButton->setBoundaries( + x + PADDING, + y + PADDING, + BUTTON_WIDTH, + BUTTON_HEIGHT); + + this->secondButton->setBoundaries( + x + PADDING * 2 + BUTTON_WIDTH, + y + PADDING, + BUTTON_WIDTH, + BUTTON_HEIGHT); + + this->thirdButton->setBoundaries( + x + PADDING * 2 + BUTTON_WIDTH, + y + PADDING * 2 + BUTTON_HEIGHT, + BUTTON_WIDTH, + BUTTON_HEIGHT); +} + +brls::View* CustomLayoutTab::getDefaultFocus() +{ + return this->firstButton->getDefaultFocus(); +} + +brls::View* CustomLayoutTab::getNextFocus(brls::FocusDirection direction, brls::View* currentView) +{ + return this->navigationMap.getNextFocus(direction, currentView); +} diff --git a/source/custom_layout_tab.hpp b/source/custom_layout_tab.hpp new file mode 100644 index 0000000..da3e48b --- /dev/null +++ b/source/custom_layout_tab.hpp @@ -0,0 +1,36 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2020 natinusala + + 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 . +*/ + +#include + +class CustomLayoutTab : public brls::AbsoluteLayout +{ + public: + CustomLayoutTab(); + + brls::View* getDefaultFocus() override; + brls::View* getNextFocus(brls::FocusDirection direction, brls::View* currentView) override; + void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash); + + private: + brls::NavigationMap navigationMap; + + brls::Button* firstButton; + brls::Button* secondButton; + brls::Button* thirdButton; +}; diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..ed29e1f --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,213 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2019-2020 natinusala + Copyright (C) 2019 p-sam + + 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 . +*/ + +#include +#include + +#include +#include +#include + +#include "custom_layout_tab.hpp" +#include "sample_installer_page.hpp" +#include "sample_loading_page.hpp" + +int g_argc = 0; +char **g_argv = NULL; +const char *g_appLaunchPath = NULL; + +namespace i18n = brls::i18n; // for loadTranslations() and getStr() +using namespace i18n::literals; // for _i18n + +std::vector NOTIFICATIONS = { + "You have cool hair", + "I like your shoes", + "borealis is powered by nanovg", + "The Triforce is an inside job", + "Pozznx will trigger in one day and twelve hours", + "Aurora Borealis? At this time of day, at this time of year, in this part of the gaming market, located entirely within your Switch?!", + "May I see it?", + "Hmm, Steamed Hams!" +}; + +int main(int argc, char* argv[]) +{ + g_argc = argc; + g_argv = argv; + + if (!utilsInitializeResources()) + { + utilsCloseResources(); + return EXIT_FAILURE; + } + + // Init the app + brls::Logger::setLogLevel(brls::LogLevel::DEBUG); + + i18n::loadTranslations(); + if (!brls::Application::init("main/name"_i18n)) + { + brls::Logger::error("Unable to init Borealis application"); + utilsCloseResources(); + return EXIT_FAILURE; + } + + // Create a sample view + brls::TabFrame* rootFrame = new brls::TabFrame(); + rootFrame->setTitle("main/name"_i18n); + rootFrame->setIcon(BOREALIS_ASSET("icon/" APP_TITLE ".jpg" )); + + brls::List* testList = new brls::List(); + + brls::ListItem* dialogItem = new brls::ListItem("main/pozznx/open"_i18n); + dialogItem->getClickEvent()->subscribe([](brls::View* view) { + brls::Dialog* dialog = new brls::Dialog("main/pozznx/warning"_i18n); + + brls::GenericEvent::Callback closeCallback = [dialog](brls::View* view) { + dialog->close(); + brls::Application::notify("main/pozznx/running"_i18n); + }; + + std::string continueStr = "main/pozznx/continue"_i18n; + + dialog->addButton(continueStr, closeCallback); + dialog->addButton(continueStr, closeCallback); + dialog->addButton(continueStr, closeCallback); + + dialog->setCancelable(false); + + dialog->open(); + }); + + brls::ListItem* notificationItem = new brls::ListItem("main/notify"_i18n); + notificationItem->getClickEvent()->subscribe([](brls::View* view) { + std::string notification = NOTIFICATIONS[std::rand() % NOTIFICATIONS.size()]; + brls::Application::notify(notification); + }); + + brls::ListItem* themeItem = new brls::ListItem("main/tv/resolution"_i18n); + themeItem->setValue("main/tv/automatic"_i18n); + + brls::ListItem* i18nItem = new brls::ListItem(i18n::getStr("main/i18n/title", i18n::getCurrentLocale(), "main/i18n/lang"_i18n)); + + brls::SelectListItem* jankItem = new brls::SelectListItem( + "main/jank/jank"_i18n, + { + "main/jank/native"_i18n, + "main/jank/minimal"_i18n, + "main/jank/regular"_i18n, + "main/jank/maximum"_i18n, + "main/jank/saxophone"_i18n, + "main/jank/vista"_i18n, + "main/jank/ios"_i18n, + }); + + brls::ListItem* crashItem = new brls::ListItem("main/divide/title"_i18n, "main/divide/description"_i18n); + crashItem->getClickEvent()->subscribe([](brls::View* view) { brls::Application::crash("main/divide/crash"_i18n); }); + + brls::ListItem* popupItem = new brls::ListItem("popup/open"_i18n); + popupItem->getClickEvent()->subscribe([](brls::View* view) { + brls::TabFrame* popupTabFrame = new brls::TabFrame(); + popupTabFrame->addTab("popup/red"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0))); + popupTabFrame->addTab("popup/green"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0))); + popupTabFrame->addTab("popup/blue"_i18n, new brls::Rectangle(nvgRGB(0, 0, 255))); + brls::PopupFrame::open("popup/title"_i18n, BOREALIS_ASSET("icon/" APP_TITLE ".jpg"), popupTabFrame, "popup/subtitle/left"_i18n, "popup/subtitle/right"_i18n); + }); + + brls::ListItem* installerItem = new brls::ListItem("installer/open"_i18n); + installerItem->getClickEvent()->subscribe([](brls::View* view) { + brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame(); + stagedFrame->setTitle("installer/title"_i18n); + + stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "installer/stage1/button"_i18n)); + stagedFrame->addStage(new SampleLoadingPage(stagedFrame)); + stagedFrame->addStage(new SampleInstallerPage(stagedFrame, "installer/stage3/button"_i18n)); + + brls::Application::pushView(stagedFrame); + }); + + brls::SelectListItem* layerSelectItem = new brls::SelectListItem("main/layers/title"_i18n, { "main/layers/layer1"_i18n, "main/layers/layer2"_i18n }); + + brls::InputListItem* keyboardItem = new brls::InputListItem("main/keyboard/string/title"_i18n, "main/keyboard/string/default"_i18n, "main/keyboard/string/help"_i18n, "", 16); + + brls::IntegerInputListItem* keyboardNumberItem = new brls::IntegerInputListItem("main/keyboard/number/title"_i18n, 1337, "main/keyboard/number/help"_i18n, "", 10); + + testList->addView(dialogItem); + testList->addView(notificationItem); + testList->addView(themeItem); + testList->addView(i18nItem); + testList->addView(jankItem); + testList->addView(crashItem); + testList->addView(installerItem); + testList->addView(popupItem); + testList->addView(keyboardItem); + testList->addView(keyboardNumberItem); + + brls::Label* testLabel = new brls::Label(brls::LabelStyle::REGULAR, "main/more"_i18n, true); + testList->addView(testLabel); + + brls::ListItem* actionTestItem = new brls::ListItem("main/actions/title"_i18n); + actionTestItem->registerAction("main/actions/notify"_i18n, brls::Key::L, [] { + brls::Application::notify("main/actions/triggered"_i18n); + return true; + }); + testList->addView(actionTestItem); + + brls::LayerView* testLayers = new brls::LayerView(); + brls::List* layerList1 = new brls::List(); + brls::List* layerList2 = new brls::List(); + + layerList1->addView(new brls::Header("main/layers/layer1"_i18n, false)); + layerList1->addView(new brls::ListItem("main/layers/item1"_i18n)); + layerList1->addView(new brls::ListItem("main/layers/item2"_i18n)); + layerList1->addView(new brls::ListItem("main/layers/item3"_i18n)); + + layerList2->addView(new brls::Header("main/layers/layer2"_i18n, false)); + layerList2->addView(new brls::ListItem("main/layers/item1"_i18n)); + layerList2->addView(new brls::ListItem("main/layers/item2"_i18n)); + layerList2->addView(new brls::ListItem("main/layers/item3"_i18n)); + + testLayers->addLayer(layerList1); + testLayers->addLayer(layerList2); + + layerSelectItem->getValueSelectedEvent()->subscribe([=](size_t selection) { + testLayers->changeLayer(selection); + }); + + testList->addView(layerSelectItem); + + rootFrame->addTab("main/tabs/first"_i18n, testList); + rootFrame->addTab("main/tabs/second"_i18n, testLayers); + rootFrame->addSeparator(); + rootFrame->addTab("main/tabs/third"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0))); + rootFrame->addTab("main/tabs/fourth"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0))); + rootFrame->addSeparator(); + rootFrame->addTab("main/tabs/custom_navigation_tab"_i18n, new CustomLayoutTab()); + + // Add the root view to the stack + brls::Application::pushView(rootFrame); + + // Run the app + while (brls::Application::mainLoop()); + + utilsCloseResources(); + + // Exit + return EXIT_SUCCESS; +} diff --git a/source/sample_installer_page.cpp b/source/sample_installer_page.cpp new file mode 100644 index 0000000..697a016 --- /dev/null +++ b/source/sample_installer_page.cpp @@ -0,0 +1,77 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2019 natinusala + Copyright (C) 2019 Billy Laws + Copyright (C) 2019 p-sam + + 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 . +*/ + +#include "sample_installer_page.hpp" + +#include + +using namespace brls::i18n::literals; + +SampleInstallerPage::SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label) +{ + // Label + this->button = (new brls::Button(brls::ButtonStyle::BORDERLESS))->setLabel(label)->setImage(BOREALIS_ASSET("icon/" APP_TITLE ".jpg")); + this->button->setParent(this); + this->button->getClickEvent()->subscribe([frame](View* view) { + if (frame->isLastStage()) + brls::Application::popView(); + else + frame->nextStage(); + }); + this->label = new brls::Label(brls::LabelStyle::DIALOG, "installer/stage1/text"_i18n, true); + this->label->setHorizontalAlign(NVG_ALIGN_CENTER); + this->label->setParent(this); +} + +void SampleInstallerPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) +{ + this->label->frame(ctx); + this->button->frame(ctx); +} + +brls::View* SampleInstallerPage::getDefaultFocus() +{ + return this->button; +} + +void SampleInstallerPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) +{ + this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth)); + this->label->invalidate(true); + + this->label->setBoundaries( + this->x + this->width / 2 - this->label->getWidth() / 2, + this->y + (this->height - style->AppletFrame.footerHeight) / 2, + this->label->getWidth(), + this->label->getHeight()); + + this->button->setBoundaries( + this->x + this->width / 2 - style->CrashFrame.buttonWidth / 2, + this->y + this->height / 2 + style->CrashFrame.buttonHeight, + style->CrashFrame.buttonWidth, + style->CrashFrame.buttonHeight); + this->button->invalidate(); +} + +SampleInstallerPage::~SampleInstallerPage() +{ + delete this->label; + delete this->button; +} diff --git a/source/sample_installer_page.hpp b/source/sample_installer_page.hpp new file mode 100644 index 0000000..753f402 --- /dev/null +++ b/source/sample_installer_page.hpp @@ -0,0 +1,38 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2019 natinusala + Copyright (C) 2019 Billy Laws + Copyright (C) 2019 p-sam + + 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 . +*/ + +#pragma once + +#include + +class SampleInstallerPage : public brls::View +{ + private: + brls::Button* button; + brls::Label* label; + + public: + SampleInstallerPage(brls::StagedAppletFrame* frame, std::string label); + ~SampleInstallerPage(); + + void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override; + void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override; + brls::View* getDefaultFocus() override; +}; diff --git a/source/sample_loading_page.cpp b/source/sample_loading_page.cpp new file mode 100644 index 0000000..846a5fc --- /dev/null +++ b/source/sample_loading_page.cpp @@ -0,0 +1,82 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2019 natinusala + Copyright (C) 2019 Billy Laws + Copyright (C) 2019 p-sam + + 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 . +*/ + +#include "sample_loading_page.hpp" + +#include + +using namespace brls::i18n::literals; + +SampleLoadingPage::SampleLoadingPage(brls::StagedAppletFrame* frame) + : frame(frame) +{ + // Label + this->progressDisp = new brls::ProgressDisplay(); + this->progressDisp->setProgress(this->progressValue, 1000); + this->progressDisp->setParent(this); + this->label = new brls::Label(brls::LabelStyle::DIALOG, "installer/stage2/text"_i18n, true); + this->label->setHorizontalAlign(NVG_ALIGN_CENTER); + this->label->setParent(this); +} + +void SampleLoadingPage::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) +{ + if (progressValue == 500) + this->frame->nextStage(); + + this->progressValue++; + this->progressDisp->setProgress(this->progressValue, 500); + this->progressDisp->frame(ctx); + this->label->frame(ctx); +} + +void SampleLoadingPage::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) +{ + this->label->setWidth(roundf((float)this->width * style->CrashFrame.labelWidth)); + this->label->invalidate(true); + + this->label->setBoundaries( + this->x + this->width / 2 - this->label->getWidth() / 2, + this->y + (this->height - style->AppletFrame.footerHeight) / 2, + this->label->getWidth(), + this->label->getHeight()); + + this->progressDisp->setBoundaries( + this->x + this->width / 2 - style->CrashFrame.buttonWidth, + this->y + this->height / 2, + style->CrashFrame.buttonWidth * 2, + style->CrashFrame.buttonHeight); +} + +void SampleLoadingPage::willAppear(bool resetState) +{ + this->progressDisp->willAppear(resetState); +} + +void SampleLoadingPage::willDisappear(bool resetState) +{ + this->progressDisp->willDisappear(resetState); +} + +SampleLoadingPage::~SampleLoadingPage() +{ + delete this->progressDisp; + delete this->label; +} diff --git a/source/sample_loading_page.hpp b/source/sample_loading_page.hpp new file mode 100644 index 0000000..035e049 --- /dev/null +++ b/source/sample_loading_page.hpp @@ -0,0 +1,42 @@ +/* + Borealis, a Nintendo Switch UI Library + Copyright (C) 2019 natinusala + Copyright (C) 2019 Billy Laws + Copyright (C) 2019 p-sam + + 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 . +*/ + +#pragma once + +#include + +class SampleLoadingPage : public brls::View +{ + private: + brls::StagedAppletFrame* frame; + brls::ProgressDisplay* progressDisp; + brls::Label* label; + int progressValue = 0; + + public: + SampleLoadingPage(brls::StagedAppletFrame* frame); + ~SampleLoadingPage(); + + void draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) override; + void layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) override; + + void willAppear(bool resetState = false) override; + void willDisappear(bool resetState = false) override; +};