From ac647310ade3c9eda9f62daef4d90a4ab66b79a9 Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Sun, 13 Jun 2021 02:18:14 -0400 Subject: [PATCH] UI: added ErrorFrame and GameCardTab classes. --- include/core/gamecard.h | 9 ++-- include/error_frame.hpp | 51 ++++++++++++++++++ include/gamecard_tab.hpp | 54 +++++++++++++++++++ include/root_view.hpp | 10 +++- include/tasks.hpp | 22 +++++--- source/core/gamecard.c | 2 +- source/error_frame.cpp | 97 ++++++++++++++++++++++++++++++++++ source/gamecard_tab.cpp | 111 +++++++++++++++++++++++++++++++++++++++ source/root_view.cpp | 15 +++++- 9 files changed, 355 insertions(+), 16 deletions(-) create mode 100644 include/error_frame.hpp create mode 100644 include/gamecard_tab.hpp create mode 100644 source/error_frame.cpp create mode 100644 source/gamecard_tab.cpp diff --git a/include/core/gamecard.h b/include/core/gamecard.h index 014dfcd..5f7f155 100644 --- a/include/core/gamecard.h +++ b/include/core/gamecard.h @@ -191,12 +191,13 @@ NXDT_ASSERT(GameCardHeader, 0x200); typedef enum { GameCardStatus_NotInserted = 0, ///< No gamecard is inserted. - GameCardStatus_NoGameCardPatchEnabled = 1, ///< A gamecard has been inserted, but the running CFW enabled the "nogc" patch at boot. + GameCardStatus_Processing = 1, ///< A gamecard has been inserted and it's being processed. + GameCardStatus_NoGameCardPatchEnabled = 2, ///< A gamecard has been inserted, but the running CFW enabled the "nogc" patch at boot. ///< This triggers an error whenever fsDeviceOperatorGetGameCardHandle is called. Nothing at all can be done with the inserted gamecard. - GameCardStatus_LotusAsicFirmwareUpdateRequired = 2, ///< A gamecard has been inserted, but a LAFW update is needed before being able to read the secure storage area. + GameCardStatus_LotusAsicFirmwareUpdateRequired = 3, ///< A gamecard has been inserted, but a LAFW update is needed before being able to read the secure storage area. ///< Operations on the normal storage area are still possible, though. - GameCardStatus_InsertedAndInfoNotLoaded = 3, ///< A gamecard has been inserted, but an unexpected error unrelated to both "nogc" patch and LAFW version occurred. - GameCardStatus_InsertedAndInfoLoaded = 4 ///< A gamecard has been inserted and all required information could be successfully retrieved from it. + GameCardStatus_InsertedAndInfoNotLoaded = 4, ///< A gamecard has been inserted, but an unexpected error unrelated to both "nogc" patch and LAFW version occurred. + GameCardStatus_InsertedAndInfoLoaded = 5 ///< A gamecard has been inserted and all required information could be successfully retrieved from it. } GameCardStatus; typedef enum { diff --git a/include/error_frame.hpp b/include/error_frame.hpp new file mode 100644 index 0000000..1a2680f --- /dev/null +++ b/include/error_frame.hpp @@ -0,0 +1,51 @@ +/* + * error_frame.hpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * Based on crash_frame.hpp from Borealis. + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 + +#ifndef __ERROR_FRAME_HPP__ +#define __ERROR_FRAME_HPP__ + +#include + +namespace nxdt::views +{ + class ErrorFrame: public brls::View + { + private: + brls::Label *label = nullptr; + bool print_dbg = false; + + protected: + 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; + + public: + ErrorFrame(std::string msg); + ~ErrorFrame(void); + + void SetMessage(std::string msg); + }; +} + +#endif /* __ERROR_FRAME_HPP__ */ diff --git a/include/gamecard_tab.hpp b/include/gamecard_tab.hpp new file mode 100644 index 0000000..1a10814 --- /dev/null +++ b/include/gamecard_tab.hpp @@ -0,0 +1,54 @@ +/* + * gamecard_tab.hpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 + +#ifndef __GAMECARD_TAB_HPP__ +#define __GAMECARD_TAB_HPP__ + +#include "tasks.hpp" +#include "error_frame.hpp" + +namespace nxdt::views +{ + class GameCardTab: public brls::LayerView + { + private: + nxdt::tasks::GameCardTask *gc_status_task = nullptr; + nxdt::tasks::GameCardStatusEvent::Subscription gc_status_task_sub; + GameCardStatus gc_status = GameCardStatus_NotInserted; + + ErrorFrame *error_frame = nullptr; + brls::List *list = nullptr; + + std::vector views; + int view_index = -1; + + void addLayerWrapper(brls::View* view); + void changeLayerWrapper(brls::View* view); + + public: + GameCardTab(nxdt::tasks::GameCardTask *gc_status_task); + ~GameCardTab(void); + }; +} + +#endif /* __GAMECARD_TAB_HPP__ */ diff --git a/include/root_view.hpp b/include/root_view.hpp index 309fd5f..c20ee6d 100644 --- a/include/root_view.hpp +++ b/include/root_view.hpp @@ -19,7 +19,12 @@ * along with this program. If not, see . */ -#include +#pragma once + +#ifndef __ROOT_VIEW_HPP__ +#define __ROOT_VIEW_HPP__ + +#include "tasks.hpp" namespace nxdt::views { @@ -33,5 +38,8 @@ namespace nxdt::views public: RootView(void); + ~RootView(void); }; } + +#endif /* __ROOT_VIEW_HPP__ */ diff --git a/include/tasks.hpp b/include/tasks.hpp index 4c02236..949c764 100644 --- a/include/tasks.hpp +++ b/include/tasks.hpp @@ -53,12 +53,13 @@ namespace nxdt::tasks GameCardStatus cur_gc_status = GameCardStatus_NotInserted; GameCardStatus prev_gc_status = GameCardStatus_NotInserted; + protected: + void run(retro_time_t current_time) override; + public: GameCardTask(void); ~GameCardTask(void); - void run(retro_time_t current_time) override; - ALWAYS_INLINE GameCardStatusEvent::Subscription RegisterListener(GameCardStatusEvent::Callback cb) { return this->gc_status_event.subscribe(cb); @@ -81,12 +82,13 @@ namespace nxdt::tasks void PopulateApplicationMetadataVector(bool is_system); + protected: + void run(retro_time_t current_time) override; + public: TitleTask(void); ~TitleTask(void); - void run(retro_time_t current_time) override; - TitleApplicationMetadataVector* GetApplicationMetadata(bool is_system); ALWAYS_INLINE VoidEvent::Subscription RegisterListener(VoidEvent::Callback cb) @@ -109,12 +111,14 @@ namespace nxdt::tasks UmsDeviceVector ums_devices; void PopulateUmsDeviceVector(void); + + protected: + void run(retro_time_t current_time) override; + public: UmsTask(void); ~UmsTask(void); - void run(retro_time_t current_time) override; - UmsDeviceVector* GetUmsDevices(void); ALWAYS_INLINE VoidEvent::Subscription RegisterListener(VoidEvent::Callback cb) @@ -136,12 +140,14 @@ namespace nxdt::tasks bool cur_usb_host_status = false; bool prev_usb_host_status = false; + + protected: + void run(retro_time_t current_time) override; + public: UsbHostTask(void); ~UsbHostTask(void); - void run(retro_time_t current_time) override; - ALWAYS_INLINE BooleanEvent::Subscription RegisterListener(BooleanEvent::Callback cb) { return this->usb_host_event.subscribe(cb); diff --git a/source/core/gamecard.c b/source/core/gamecard.c index 97cd63a..885070c 100644 --- a/source/core/gamecard.c +++ b/source/core/gamecard.c @@ -305,7 +305,7 @@ UEvent *gamecardGetStatusChangeUserEvent(void) u8 gamecardGetStatus(void) { - u8 status = GameCardStatus_NotInserted; + u8 status = GameCardStatus_Processing; SCOPED_TRY_LOCK(&g_gameCardMutex) { diff --git a/source/error_frame.cpp b/source/error_frame.cpp new file mode 100644 index 0000000..18365d9 --- /dev/null +++ b/source/error_frame.cpp @@ -0,0 +1,97 @@ +/* + * error_frame.cpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * Based on crash_frame.cpp from Borealis. + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 + +namespace nxdt::views +{ + ErrorFrame::ErrorFrame(std::string msg): brls::View() + { + this->label = new brls::Label(brls::LabelStyle::REGULAR, msg, true); + this->label->setHorizontalAlign(NVG_ALIGN_CENTER); + this->label->setParent(this); + } + + ErrorFrame::~ErrorFrame(void) + { + delete this->label; + } + + void ErrorFrame::draw(NVGcontext* vg, int x, int y, unsigned width, unsigned height, brls::Style* style, brls::FrameContext* ctx) + { + nvgSave(vg); + + /* Background. */ + nvgFillColor(vg, brls::Application::getTheme()->backgroundColorRGB); + nvgBeginPath(vg); + nvgRect(vg, x, y, width, height); + nvgFill(vg); + + /* Scale. */ + float scale = (this->alpha + 2.0f) / 3.0f; + nvgTranslate(vg, (1.0f - scale) * width * 0.5f, (1.0f - scale) * height * 0.5f); + nvgScale(vg, scale, scale); + + /* Label. */ + this->label->frame(ctx); + + /* [!] box. */ + unsigned boxSize = style->CrashFrame.boxSize; + nvgStrokeColor(vg, RGB(255, 255, 255)); + nvgStrokeWidth(vg, style->CrashFrame.boxStrokeWidth); + nvgBeginPath(vg); + nvgRect(vg, x + (width - boxSize) / 2, y + style->CrashFrame.boxSpacing, boxSize, boxSize); + nvgStroke(vg); + + nvgFillColor(vg, RGB(255, 255, 255)); + + nvgFontSize(vg, (float)style->CrashFrame.boxSize / 1.25f); + nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgBeginPath(vg); + nvgText(vg, x + width / 2, y + style->CrashFrame.boxSpacing + boxSize / 2, "!", nullptr); + nvgFill(vg); + + /* End scale. */ + nvgResetTransform(vg); + nvgRestore(vg); + } + + void ErrorFrame::layout(NVGcontext* vg, brls::Style* style, brls::FontStash* stash) + { + this->label->setWidth(roundf((float)this->width * 0.90f)); + 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()); + } + + void ErrorFrame::SetMessage(std::string msg) + { + this->label->setText(msg); + this->invalidate(true); + } +} diff --git a/source/gamecard_tab.cpp b/source/gamecard_tab.cpp new file mode 100644 index 0000000..7cb0b42 --- /dev/null +++ b/source/gamecard_tab.cpp @@ -0,0 +1,111 @@ +/* + * gamecard_tab.cpp + * + * Copyright (c) 2020-2021, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool 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. + * + * nxdumptool 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 + +using namespace brls::i18n::literals; /* For _i18n. */ + +namespace nxdt::views +{ + GameCardTab::GameCardTab(nxdt::tasks::GameCardTask *gc_status_task) : brls::LayerView(), gc_status_task(gc_status_task) + { + /* Add error frame. */ + this->error_frame = new ErrorFrame("No gamecard inserted."); + this->addLayer(this->error_frame); + + /* Add list. */ + this->list = new brls::List(); + this->list->addView(new brls::ListItem("Placeholder")); + this->addLayer(this->list); + + /* Setup gamecard status task. */ + this->gc_status_task_sub = this->gc_status_task->RegisterListener([this](GameCardStatus gc_status) { + switch(gc_status) + { + case GameCardStatus_NotInserted: + this->error_frame->SetMessage("No gamecard inserted."); + break; + case GameCardStatus_Processing: + this->error_frame->SetMessage("Processing gamecard, please wait..."); + break; + case GameCardStatus_NoGameCardPatchEnabled: + this->error_frame->SetMessage("A gamecard has been inserted, but the \"nogc\" patch is enabled.\n" \ + "Nothing at all can be done with the inserted gamecard.\n" \ + "Disabling this patch *will* update the Lotus ASIC firmware if it's outdated.\n" \ + "Consider disabling this patch if you wish to use gamecard dumping features."); + break; + case GameCardStatus_LotusAsicFirmwareUpdateRequired: + this->error_frame->SetMessage("A gamecard has been inserted, but a Lotus ASIC firmware update is required.\n" \ + "Update your console using the inserted gamecard and try again."); + break; + case GameCardStatus_InsertedAndInfoNotLoaded: + this->error_frame->SetMessage("A gamecard has been inserted, but an unexpected I/O error occurred.\n" \ + "Please check the logfile and report this issue to " APP_AUTHOR "."); + break; + case GameCardStatus_InsertedAndInfoLoaded: + this->changeLayer(1); + this->list->invalidate(true); + break; + default: + break; + } + + if (gc_status < GameCardStatus_InsertedAndInfoLoaded) this->changeLayer(0); + + this->gc_status = gc_status; + }); + } + + GameCardTab::~GameCardTab(void) + { + /* Unregister gamecard task listener. */ + this->gc_status_task->UnregisterListener(this->gc_status_task_sub); + } + + void GameCardTab::addLayerWrapper(brls::View* view) + { + this->views.push_back(view); + this->addLayer(view); + if (this->view_index == -1) this->view_index = 0; + } + + void GameCardTab::changeLayerWrapper(brls::View* view) + { + int index = -1; + + for(size_t i = 0; i < this->views.size(); i++) + { + if (this->views[i] == view) + { + index = (int)i; + break; + } + } + + if (index == -1 || index == this->view_index) return; + + //reinterpret_cast(this->getParent())->onCancel(); + this->changeLayer(index); + this->view_index = index; + view->invalidate(true); + } +} diff --git a/source/root_view.cpp b/source/root_view.cpp index 4673336..e6a44c5 100644 --- a/source/root_view.cpp +++ b/source/root_view.cpp @@ -21,7 +21,7 @@ #include #include -//#include +#include //#include //#include //#include @@ -45,10 +45,21 @@ namespace nxdt::views this->setFooterText("v" APP_VERSION); /* Add tabs. */ - this->addTab("root_view/tabs/gamecard"_i18n, new brls::Rectangle(nvgRGB(255, 0, 0))); + this->addTab("root_view/tabs/gamecard"_i18n, new GameCardTab(this->gc_status_task)); + this->addSeparator(); this->addTab("root_view/tabs/user_titles"_i18n, new brls::Rectangle(nvgRGB(0, 255, 0))); this->addTab("root_view/tabs/system_titles"_i18n, new brls::Rectangle(nvgRGB(0, 0, 255))); + this->addSeparator(); this->addTab("root_view/tabs/options"_i18n, new brls::Rectangle(nvgRGB(255, 255, 0))); this->addTab("root_view/tabs/about"_i18n, new brls::Rectangle(nvgRGB(255, 0, 255))); } + + RootView::~RootView(void) + { + /* Stop background tasks. */ + this->gc_status_task->stop(); + this->title_task->stop(); + this->ums_task->stop(); + this->usb_host_task->stop(); + } }