mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
daybreak: various ux improvements (#1080)
This commit is contained in:
parent
8d6e076b77
commit
084dd3232e
5 changed files with 281 additions and 21 deletions
|
@ -26,10 +26,6 @@ extern "C" {
|
|||
void userAppInit(void) {
|
||||
Result rc = 0;
|
||||
|
||||
if (R_FAILED(rc = amssuInitialize())) {
|
||||
fatalThrow(rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = romfsInit())) {
|
||||
fatalThrow(rc);
|
||||
}
|
||||
|
@ -42,6 +38,10 @@ extern "C" {
|
|||
fatalThrow(rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = splInitialize())) {
|
||||
fatalThrow(rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = hiddbgInitialize())) {
|
||||
fatalThrow(rc);
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ extern "C" {
|
|||
|
||||
void userAppExit(void) {
|
||||
hiddbgExit();
|
||||
splExit();
|
||||
plExit();
|
||||
spsmExit();
|
||||
romfsExit();
|
||||
|
|
|
@ -26,6 +26,10 @@ namespace dbk {
|
|||
|
||||
namespace {
|
||||
|
||||
static constexpr u32 ExosphereApiVersionConfigItem = 65000;
|
||||
static constexpr u32 ExosphereHasRcmBugPatch = 65004;
|
||||
static constexpr u32 ExosphereEmummcType = 65007;
|
||||
|
||||
u32 g_screen_width;
|
||||
u32 g_screen_height;
|
||||
|
||||
|
@ -313,6 +317,132 @@ namespace dbk {
|
|||
return m_prev_menu;
|
||||
}
|
||||
|
||||
ErrorMenu::ErrorMenu(const char *text, const char *subtext, Result rc) : Menu(nullptr), m_text{}, m_subtext{}, m_result_text{}, m_rc(rc) {
|
||||
const float window_height = WindowHeight + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - window_height / 2.0f;
|
||||
|
||||
/* Copy the input text. */
|
||||
strncpy(m_text, text, sizeof(m_text)-1);
|
||||
strncpy(m_subtext, subtext, sizeof(m_subtext)-1);
|
||||
|
||||
/* Copy result text if there is a result. */
|
||||
if (R_FAILED(rc)) {
|
||||
snprintf(m_result_text, sizeof(m_result_text)-1, "Result: 0x%08x", rc);
|
||||
}
|
||||
|
||||
const float button_y = y + TitleGap + SubTextHeight + VerticalGap + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
this->AddButton(ExitButtonId, "Exit", x + HorizontalGap, button_y, ButtonWidth, ButtonHeight);
|
||||
this->SetButtonSelected(ExitButtonId, true);
|
||||
}
|
||||
|
||||
void ErrorMenu::Update(u64 ns) {
|
||||
u64 k_down = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
/* Go back if B is pressed. */
|
||||
if (k_down & KEY_B) {
|
||||
g_exit_requested = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take action if a button has been activated. */
|
||||
if (const Button *activated_button = this->GetActivatedButton(); activated_button != nullptr) {
|
||||
switch (activated_button->id) {
|
||||
case ExitButtonId:
|
||||
g_exit_requested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->UpdateButtons();
|
||||
|
||||
/* Fallback on selecting the exfat button. */
|
||||
if (const Button *selected_button = this->GetSelectedButton(); k_down && selected_button == nullptr) {
|
||||
this->SetButtonSelected(ExitButtonId, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorMenu::Draw(NVGcontext *vg, u64 ns) {
|
||||
const float window_height = WindowHeight + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - window_height / 2.0f;
|
||||
|
||||
DrawWindow(vg, m_text, x, y, WindowWidth, window_height);
|
||||
DrawText(vg, x + HorizontalGap, y + TitleGap, WindowWidth - HorizontalGap * 2.0f, m_subtext);
|
||||
|
||||
/* Draw the result if there is one. */
|
||||
if (R_FAILED(m_rc)) {
|
||||
DrawText(vg, x + HorizontalGap, y + TitleGap + SubTextHeight, WindowWidth - HorizontalGap * 2.0f, m_result_text);
|
||||
}
|
||||
|
||||
this->DrawButtons(vg, ns);
|
||||
}
|
||||
|
||||
WarningMenu::WarningMenu(std::shared_ptr<Menu> prev_menu, std::shared_ptr<Menu> next_menu, const char *text, const char *subtext, Result rc) : Menu(prev_menu), m_next_menu(next_menu), m_text{}, m_subtext{}, m_result_text{}, m_rc(rc) {
|
||||
const float window_height = WindowHeight + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - window_height / 2.0f;
|
||||
|
||||
/* Copy the input text. */
|
||||
strncpy(m_text, text, sizeof(m_text)-1);
|
||||
strncpy(m_subtext, subtext, sizeof(m_subtext)-1);
|
||||
|
||||
/* Copy result text if there is a result. */
|
||||
if (R_FAILED(rc)) {
|
||||
snprintf(m_result_text, sizeof(m_result_text)-1, "Result: 0x%08x", rc);
|
||||
}
|
||||
|
||||
const float button_y = y + TitleGap + SubTextHeight + VerticalGap + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
this->AddButton(BackButtonId, "Back", x + HorizontalGap, button_y, ButtonWidth, ButtonHeight);
|
||||
this->AddButton(ContinueButtonId, "Continue", x + HorizontalGap + ButtonWidth + ButtonHorizontalGap, button_y, ButtonWidth, ButtonHeight);
|
||||
this->SetButtonSelected(ContinueButtonId, true);
|
||||
}
|
||||
|
||||
void WarningMenu::Update(u64 ns) {
|
||||
u64 k_down = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
/* Go back if B is pressed. */
|
||||
if (k_down & KEY_B) {
|
||||
ReturnToPreviousMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Take action if a button has been activated. */
|
||||
if (const Button *activated_button = this->GetActivatedButton(); activated_button != nullptr) {
|
||||
switch (activated_button->id) {
|
||||
case BackButtonId:
|
||||
ReturnToPreviousMenu();
|
||||
return;
|
||||
case ContinueButtonId:
|
||||
ChangeMenu(m_next_menu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->UpdateButtons();
|
||||
|
||||
/* Fallback on selecting the exfat button. */
|
||||
if (const Button *selected_button = this->GetSelectedButton(); k_down && selected_button == nullptr) {
|
||||
this->SetButtonSelected(ContinueButtonId, true);
|
||||
}
|
||||
}
|
||||
|
||||
void WarningMenu::Draw(NVGcontext *vg, u64 ns) {
|
||||
const float window_height = WindowHeight + (R_FAILED(m_rc) ? SubTextHeight : 0.0f);
|
||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - window_height / 2.0f;
|
||||
|
||||
DrawWindow(vg, m_text, x, y, WindowWidth, window_height);
|
||||
DrawText(vg, x + HorizontalGap, y + TitleGap, WindowWidth - HorizontalGap * 2.0f, m_subtext);
|
||||
|
||||
/* Draw the result if there is one. */
|
||||
if (R_FAILED(m_rc)) {
|
||||
DrawText(vg, x + HorizontalGap, y + TitleGap + SubTextHeight, WindowWidth - HorizontalGap * 2.0f, m_result_text);
|
||||
}
|
||||
|
||||
this->DrawButtons(vg, ns);
|
||||
}
|
||||
|
||||
MainMenu::MainMenu() : Menu(nullptr) {
|
||||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||
|
@ -333,11 +463,42 @@ namespace dbk {
|
|||
if (const Button *activated_button = this->GetActivatedButton(); activated_button != nullptr) {
|
||||
switch (activated_button->id) {
|
||||
case InstallButtonId:
|
||||
ChangeMenu(std::make_shared<FileMenu>(g_current_menu, "/"));
|
||||
break;
|
||||
{
|
||||
const auto file_menu = std::make_shared<FileMenu>(g_current_menu, "/");
|
||||
|
||||
Result rc = 0;
|
||||
u64 hardware_type;
|
||||
u64 has_rcm_bug_patch;
|
||||
u64 is_emummc;
|
||||
|
||||
if (R_FAILED(rc = splGetConfig(SplConfigItem_HardwareType, &hardware_type))) {
|
||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to get hardware type.", rc));
|
||||
return;
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereHasRcmBugPatch), &has_rcm_bug_patch))) {
|
||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to check RCM bug status.", rc));
|
||||
return;
|
||||
}
|
||||
|
||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereEmummcType), &is_emummc))) {
|
||||
ChangeMenu(std::make_shared<ErrorMenu>("An error has occurred", "Failed to chech emuMMC status.", rc));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Warn if we're working with a patched unit. */
|
||||
const bool is_erista = hardware_type == 0 || hardware_type == 1;
|
||||
if (is_erista && has_rcm_bug_patch && !is_emummc) {
|
||||
ChangeMenu(std::make_shared<WarningMenu>(g_current_menu, file_menu, "Warning: Patched unit detected", "You may burn fuses or render your switch inoperable."));
|
||||
} else {
|
||||
ChangeMenu(file_menu);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case ExitButtonId:
|
||||
g_exit_requested = true;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -737,9 +898,18 @@ namespace dbk {
|
|||
const float x = g_screen_width / 2.0f - WindowWidth / 2.0f;
|
||||
const float y = g_screen_height / 2.0f - WindowHeight / 2.0f;
|
||||
|
||||
this->AddButton(Fat32ButtonId, "FAT32", x + ButtonHorizontalInset, y + TitleGap, ButtonWidth, ButtonHeight);
|
||||
this->AddButton(ExFatButtonId, "exFAT", x + ButtonHorizontalInset + ButtonWidth + ButtonHorizontalGap, y + TitleGap, ButtonWidth, ButtonHeight);
|
||||
this->SetButtonSelected(ExFatButtonId, true);
|
||||
this->AddButton(Fat32ButtonId, "Install (FAT32)", x + ButtonHorizontalInset, y + TitleGap, ButtonWidth, ButtonHeight);
|
||||
this->AddButton(ExFatButtonId, "Install (exFAT/FAT32)", x + ButtonHorizontalInset + ButtonWidth + ButtonHorizontalGap, y + TitleGap, ButtonWidth, ButtonHeight);
|
||||
|
||||
/* Set the default selected button based on the user's current install. We aren't particularly concerned if fsIsExFatSupported fails. */
|
||||
bool exfat_supported = false;
|
||||
fsIsExFatSupported(&exfat_supported);
|
||||
|
||||
if (exfat_supported) {
|
||||
this->SetButtonSelected(ExFatButtonId, true);
|
||||
} else {
|
||||
this->SetButtonSelected(Fat32ButtonId, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ChooseExfatMenu::Update(u64 ns) {
|
||||
|
@ -930,15 +1100,40 @@ namespace dbk {
|
|||
}
|
||||
|
||||
void InitializeMenu(u32 screen_width, u32 screen_height) {
|
||||
Result rc = 0;
|
||||
|
||||
/* Set the screen width and height. */
|
||||
g_screen_width = screen_width;
|
||||
g_screen_height = screen_height;
|
||||
|
||||
/* Change the current menu to the main menu. */
|
||||
g_current_menu = std::make_shared<MainMenu>();
|
||||
|
||||
/* Mark as initialized. */
|
||||
g_initialized = true;
|
||||
|
||||
/* Attempt to get the exosphere version. */
|
||||
u64 version;
|
||||
if (R_FAILED(rc = splGetConfig(static_cast<SplConfigItem>(ExosphereApiVersionConfigItem), &version))) {
|
||||
ChangeMenu(std::make_shared<ErrorMenu>("Atmosphere not found", "Daybreak requires Atmosphere to be installed.", rc));
|
||||
return;
|
||||
}
|
||||
|
||||
const u32 version_micro = (version >> 40) & 0xff;
|
||||
const u32 version_minor = (version >> 48) & 0xff;
|
||||
const u32 version_major = (version >> 56) & 0xff;
|
||||
|
||||
/* Validate the exosphere version. */
|
||||
const bool ams_supports_sysupdate_api = version_major >= 0 && version_minor >= 14 && version_micro >= 0;
|
||||
if (!ams_supports_sysupdate_api) {
|
||||
ChangeMenu(std::make_shared<ErrorMenu>("Outdated Atmosphere version", "Daybreak requires Atmosphere 0.14.0 or later.", rc));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize ams:su. */
|
||||
if (R_FAILED(rc = amssuInitialize())) {
|
||||
fatalThrow(rc);
|
||||
}
|
||||
|
||||
/* Change the current menu to the main menu. */
|
||||
g_current_menu = std::make_shared<MainMenu>();
|
||||
}
|
||||
|
||||
void UpdateMenu(u64 ns) {
|
||||
|
|
|
@ -82,6 +82,58 @@ namespace dbk {
|
|||
virtual void Draw(NVGcontext *vg, u64 ns) = 0;
|
||||
};
|
||||
|
||||
class ErrorMenu : public Menu {
|
||||
private:
|
||||
static constexpr u32 ExitButtonId = 0;
|
||||
|
||||
static constexpr float WindowWidth = 600.0f;
|
||||
static constexpr float WindowHeight = 214.0f;
|
||||
static constexpr float TitleGap = 90.0f;
|
||||
static constexpr float SubTextHeight = 24.0f;
|
||||
static constexpr float HorizontalGap = 20.0f;
|
||||
static constexpr float VerticalGap = 20.0f;
|
||||
static constexpr float ButtonHeight = 60.0f;
|
||||
static constexpr float ButtonHorizontalGap = 10.0f;
|
||||
static constexpr float ButtonWidth = (WindowWidth - HorizontalGap * 2.0f);
|
||||
private:
|
||||
char m_text[0x100];
|
||||
char m_subtext[0x100];
|
||||
char m_result_text[0x20];
|
||||
Result m_rc;
|
||||
public:
|
||||
ErrorMenu(const char *text, const char *subtext, Result rc = 0);
|
||||
|
||||
virtual void Update(u64 ns) override;
|
||||
virtual void Draw(NVGcontext *vg, u64 ns) override;
|
||||
};
|
||||
|
||||
class WarningMenu : public Menu {
|
||||
private:
|
||||
static constexpr u32 BackButtonId = 0;
|
||||
static constexpr u32 ContinueButtonId = 1;
|
||||
|
||||
static constexpr float WindowWidth = 600.0f;
|
||||
static constexpr float WindowHeight = 214.0f;
|
||||
static constexpr float TitleGap = 90.0f;
|
||||
static constexpr float SubTextHeight = 24.0f;
|
||||
static constexpr float HorizontalGap = 20.0f;
|
||||
static constexpr float VerticalGap = 20.0f;
|
||||
static constexpr float ButtonHeight = 60.0f;
|
||||
static constexpr float ButtonHorizontalGap = 10.0f;
|
||||
static constexpr float ButtonWidth = (WindowWidth - HorizontalGap * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||
private:
|
||||
std::shared_ptr<Menu> m_next_menu;
|
||||
char m_text[0x100];
|
||||
char m_subtext[0x100];
|
||||
char m_result_text[0x20];
|
||||
Result m_rc;
|
||||
public:
|
||||
WarningMenu(std::shared_ptr<Menu> prev_menu, std::shared_ptr<Menu> next_menu, const char *text, const char *subtext, Result rc = 0);
|
||||
|
||||
virtual void Update(u64 ns) override;
|
||||
virtual void Draw(NVGcontext *vg, u64 ns) override;
|
||||
};
|
||||
|
||||
class MainMenu : public Menu {
|
||||
private:
|
||||
static constexpr u32 InstallButtonId = 0;
|
||||
|
@ -148,8 +200,8 @@ namespace dbk {
|
|||
static constexpr float BottomGap = 20.0f;
|
||||
static constexpr float HorizontalGap = 20.0f;
|
||||
static constexpr float TextAreaHeight = 410.0f;
|
||||
static constexpr float TextHorizontalInset = 6.0f;
|
||||
static constexpr float TextVerticalInset = 6.0f;
|
||||
static constexpr float TextHorizontalInset = 8.0f;
|
||||
static constexpr float TextVerticalInset = 8.0f;
|
||||
static constexpr float ButtonHeight = 60.0f;
|
||||
static constexpr float ButtonHorizontalGap = 10.0f;
|
||||
static constexpr float ButtonWidth = (WindowWidth - HorizontalGap * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||
|
@ -211,8 +263,8 @@ namespace dbk {
|
|||
static constexpr float ProgressBarHeight = 30.0f;
|
||||
static constexpr float VerticalGap = 10.0f;
|
||||
static constexpr float TextAreaHeight = 320.0f;
|
||||
static constexpr float TextHorizontalInset = 6.0f;
|
||||
static constexpr float TextVerticalInset = 6.0f;
|
||||
static constexpr float TextHorizontalInset = 8.0f;
|
||||
static constexpr float TextVerticalInset = 8.0f;
|
||||
static constexpr float ButtonHeight = 60.0f;
|
||||
static constexpr float ButtonHorizontalGap = 10.0f;
|
||||
static constexpr float ButtonWidth = (WindowWidth - HorizontalGap * 2.0f) / 2.0f - ButtonHorizontalGap;
|
||||
|
|
|
@ -30,9 +30,9 @@ namespace dbk {
|
|||
/* Calculate the rgb values for the breathing colour effect. */
|
||||
const double t = static_cast<double>(ns) / 1'000'000'000.0d;
|
||||
const float d = -0.5 * cos(3.0f*t) + 0.5f;
|
||||
const int r2 = 83 + (float)(144 - 83) * (d * 0.7f + 0.3f);
|
||||
const int g2 = 71 + (float)(185 - 71) * (d * 0.7f + 0.3f);
|
||||
const int b2 = 185 + (float)(217 - 185) * (d * 0.7f + 0.3f);
|
||||
const int r2 = 83 + (float)(128 - 83) * (d * 0.7f + 0.3f);
|
||||
const int g2 = 71 + (float)(126 - 71) * (d * 0.7f + 0.3f);
|
||||
const int b2 = 185 + (float)(230 - 185) * (d * 0.7f + 0.3f);
|
||||
return nvgRGB(r2, g2, b2);
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,16 @@ namespace dbk {
|
|||
nvgFill(vg);
|
||||
}
|
||||
|
||||
void DrawText(NVGcontext *vg, float x, float y, float w, const char *text) {
|
||||
nvgFontSize(vg, 20.0f);
|
||||
nvgFontFace(vg, SwitchStandardFont);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgFillColor(vg, nvgRGB(0, 0, 0));
|
||||
|
||||
const float tw = nvgTextBounds(vg, 0, 0, text, nullptr, nullptr);
|
||||
nvgText(vg, x + w * 0.5f - tw * 0.5f, y, text, nullptr);
|
||||
}
|
||||
|
||||
void DrawProgressText(NVGcontext *vg, float x, float y, float progress) {
|
||||
char progress_text[32] = {};
|
||||
snprintf(progress_text, sizeof(progress_text)-1, "%d%% complete", static_cast<int>(progress * 100.0f));
|
||||
|
@ -155,7 +165,7 @@ namespace dbk {
|
|||
|
||||
/* Draw the progress bar fill. */
|
||||
if (progress > 0.0f) {
|
||||
NVGpaint progress_fill_paint = nvgLinearGradient(vg, x, y + 0.5f * h, x + w, y + 0.5f * h, nvgRGB(83, 71, 185), nvgRGB(144, 185, 217));
|
||||
NVGpaint progress_fill_paint = nvgLinearGradient(vg, x, y + 0.5f * h, x + w, y + 0.5f * h, nvgRGB(83, 71, 185), nvgRGB(128, 126, 230));
|
||||
nvgBeginPath(vg);
|
||||
nvgRoundedRect(vg, x, y, WindowCornerRadius + (w - WindowCornerRadius) * progress, h, WindowCornerRadius);
|
||||
nvgFillPaint(vg, progress_fill_paint);
|
||||
|
@ -171,6 +181,7 @@ namespace dbk {
|
|||
/* Configure the text. */
|
||||
nvgFontSize(vg, 18.0f);
|
||||
nvgFontFace(vg, SwitchStandardFont);
|
||||
nvgTextLineHeight(vg, 1.3f);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_TOP);
|
||||
nvgFillColor(vg, nvgRGB(0, 0, 0));
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace dbk {
|
|||
void DrawWindow(NVGcontext *vg, const char *title, float x, float y, float w, float h);
|
||||
void DrawButton(NVGcontext *vg, const char *text, float x, float y, float w, float h, ButtonStyle style, u64 ns);
|
||||
void DrawTextBackground(NVGcontext *vg, float x, float y, float w, float h);
|
||||
void DrawText(NVGcontext *vg, float x, float y, float w, const char *text);
|
||||
void DrawProgressText(NVGcontext *vg, float x, float y, float progress);
|
||||
void DrawProgressBar(NVGcontext *vg, float x, float y, float w, float h, float progress);
|
||||
void DrawTextBlock(NVGcontext *vg, const char *text, float x, float y, float w, float h);
|
||||
|
|
Loading…
Reference in a new issue