mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-19 12:09:15 +01:00
added quit button and confirmation prompt
This commit is contained in:
parent
17aa09506b
commit
c06889c3bb
@ -72,15 +72,23 @@
|
|||||||
<template src="config-menu__debug" />
|
<template src="config-menu__debug" />
|
||||||
</panel>
|
</panel>
|
||||||
</tabset>
|
</tabset>
|
||||||
<!-- Close button absolutely positioned on top right of modal -->
|
<div class="config__icon-buttons">
|
||||||
<button
|
<button
|
||||||
class="icon-button config__exit-button"
|
class="icon-button"
|
||||||
|
onclick="open_quit_game_prompt"
|
||||||
|
id="config__quit-game-button"
|
||||||
|
>
|
||||||
|
<svg src="icons/Quit.svg" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="icon-button"
|
||||||
onclick="close_config_menu"
|
onclick="close_config_menu"
|
||||||
style="z-index: 10000;"
|
id="config__close-menu-button"
|
||||||
>
|
>
|
||||||
<svg src="icons/X.svg" />
|
<svg src="icons/X.svg" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="centered-page__controls"
|
class="centered-page__controls"
|
||||||
data-model="nav_help_model"
|
data-model="nav_help_model"
|
||||||
|
11
assets/icons/Quit.svg
Normal file
11
assets/icons/Quit.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M29 16L25 21" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M25 11L29 16" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M12 16L27 16" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M7 5L20 5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M7 27L7 5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M7 27L20 27" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M20 27V22" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
<path d="M20 10V5" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
|
After Width: | Height: | Size: 781 B |
File diff suppressed because one or more lines are too long
@ -37,9 +37,9 @@
|
|||||||
border-radius: $border-radius-md;
|
border-radius: $border-radius-md;
|
||||||
|
|
||||||
// Setting it by default for convenience
|
// Setting it by default for convenience
|
||||||
// &--primary {
|
&--primary {
|
||||||
// @include create-button-variation($color-primary);
|
@include create-button-variation($color-primary);
|
||||||
// }
|
}
|
||||||
|
|
||||||
&--large {
|
&--large {
|
||||||
@extend %label-lg;
|
@extend %label-lg;
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
|
|
||||||
.config__exit-button {
|
.config__icon-buttons {
|
||||||
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: space(8);
|
top: space(8);
|
||||||
right: space(8);
|
right: space(0);
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: auto;
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
margin: 0 space(8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.config__form {
|
.config__form {
|
||||||
|
@ -54,6 +54,16 @@ namespace recomp {
|
|||||||
Count
|
Count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class ButtonVariant {
|
||||||
|
Primary,
|
||||||
|
Secondary,
|
||||||
|
Tertiary,
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
Warning,
|
||||||
|
NumVariants,
|
||||||
|
};
|
||||||
|
|
||||||
void set_config_submenu(ConfigSubmenu submenu);
|
void set_config_submenu(ConfigSubmenu submenu);
|
||||||
|
|
||||||
void destroy_ui();
|
void destroy_ui();
|
||||||
@ -63,15 +73,21 @@ namespace recomp {
|
|||||||
void update_supported_options();
|
void update_supported_options();
|
||||||
void toggle_fullscreen();
|
void toggle_fullscreen();
|
||||||
|
|
||||||
|
extern const std::unordered_map<ButtonVariant, std::string> button_variants;
|
||||||
|
|
||||||
struct PromptContext {
|
struct PromptContext {
|
||||||
Rml::DataModelHandle model_handle;
|
Rml::DataModelHandle model_handle;
|
||||||
std::string header = "";
|
std::string header = "";
|
||||||
std::string content = "";
|
std::string content = "";
|
||||||
std::string confirmLabel = "Confirm";
|
std::string confirmLabel = "Confirm";
|
||||||
std::string cancelLabel = "Cancel";
|
std::string cancelLabel = "Cancel";
|
||||||
|
ButtonVariant confirmVariant = ButtonVariant::Success;
|
||||||
|
ButtonVariant cancelVariant = ButtonVariant::Error;
|
||||||
std::function<void()> onConfirm;
|
std::function<void()> onConfirm;
|
||||||
std::function<void()> onCancel;
|
std::function<void()> onCancel;
|
||||||
|
|
||||||
|
std::string returnElementId = "";
|
||||||
|
|
||||||
bool open = false;
|
bool open = false;
|
||||||
bool shouldFocus = false;
|
bool shouldFocus = false;
|
||||||
bool focusOnCancel = true;
|
bool focusOnCancel = true;
|
||||||
@ -86,7 +102,10 @@ namespace recomp {
|
|||||||
const std::string& cancelLabelText,
|
const std::string& cancelLabelText,
|
||||||
std::function<void()> confirmCb,
|
std::function<void()> confirmCb,
|
||||||
std::function<void()> cancelCb,
|
std::function<void()> cancelCb,
|
||||||
bool shouldFocusOnCancel = true
|
ButtonVariant _confirmVariant = ButtonVariant::Success,
|
||||||
|
ButtonVariant _cancelVariant = ButtonVariant::Error,
|
||||||
|
bool _focusOnCancel = true,
|
||||||
|
const std::string& _returnElementId = ""
|
||||||
);
|
);
|
||||||
void on_confirm(void);
|
void on_confirm(void);
|
||||||
void on_cancel(void);
|
void on_cancel(void);
|
||||||
|
@ -19,6 +19,15 @@ Rml::DataModelHandle sound_options_model_handle;
|
|||||||
recomp::PromptContext prompt_context;
|
recomp::PromptContext prompt_context;
|
||||||
|
|
||||||
namespace recomp {
|
namespace recomp {
|
||||||
|
const std::unordered_map<ButtonVariant, std::string> button_variants {
|
||||||
|
{ButtonVariant::Primary, "primary"},
|
||||||
|
{ButtonVariant::Secondary, "secondary"},
|
||||||
|
{ButtonVariant::Tertiary, "tertiary"},
|
||||||
|
{ButtonVariant::Success, "success"},
|
||||||
|
{ButtonVariant::Error, "error"},
|
||||||
|
{ButtonVariant::Warning, "warning"}
|
||||||
|
};
|
||||||
|
|
||||||
void PromptContext::close_prompt() {
|
void PromptContext::close_prompt() {
|
||||||
open = false;
|
open = false;
|
||||||
model_handle.DirtyVariable("prompt__open");
|
model_handle.DirtyVariable("prompt__open");
|
||||||
@ -31,7 +40,10 @@ namespace recomp {
|
|||||||
const std::string& cancelLabelText,
|
const std::string& cancelLabelText,
|
||||||
std::function<void()> confirmCb,
|
std::function<void()> confirmCb,
|
||||||
std::function<void()> cancelCb,
|
std::function<void()> cancelCb,
|
||||||
bool shouldFocusOnCancel
|
ButtonVariant _confirmVariant,
|
||||||
|
ButtonVariant _cancelVariant,
|
||||||
|
bool _focusOnCancel,
|
||||||
|
const std::string& _returnElementId
|
||||||
) {
|
) {
|
||||||
open = true;
|
open = true;
|
||||||
header = headerText;
|
header = headerText;
|
||||||
@ -40,7 +52,10 @@ namespace recomp {
|
|||||||
cancelLabel = cancelLabelText;
|
cancelLabel = cancelLabelText;
|
||||||
onConfirm = confirmCb;
|
onConfirm = confirmCb;
|
||||||
onCancel = cancelCb;
|
onCancel = cancelCb;
|
||||||
focusOnCancel = shouldFocusOnCancel;
|
confirmVariant = _confirmVariant;
|
||||||
|
cancelVariant = _cancelVariant;
|
||||||
|
focusOnCancel = _focusOnCancel;
|
||||||
|
returnElementId = _returnElementId;
|
||||||
|
|
||||||
model_handle.DirtyVariable("prompt__open");
|
model_handle.DirtyVariable("prompt__open");
|
||||||
model_handle.DirtyVariable("prompt__header");
|
model_handle.DirtyVariable("prompt__header");
|
||||||
@ -201,7 +216,11 @@ void close_config_menu() {
|
|||||||
new_options = ultramodern::get_graphics_config();
|
new_options = ultramodern::get_graphics_config();
|
||||||
graphics_model_handle.DirtyAllVariables();
|
graphics_model_handle.DirtyAllVariables();
|
||||||
close_config_menu_impl();
|
close_config_menu_impl();
|
||||||
}
|
},
|
||||||
|
recomp::ButtonVariant::Success,
|
||||||
|
recomp::ButtonVariant::Error,
|
||||||
|
true,
|
||||||
|
"config__close-menu-button"
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -209,6 +228,23 @@ void close_config_menu() {
|
|||||||
close_config_menu_impl();
|
close_config_menu_impl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void open_quit_game_prompt() {
|
||||||
|
prompt_context.open_prompt(
|
||||||
|
"Are you sure you want to quit?",
|
||||||
|
"Any progress since your last save will be lost.",
|
||||||
|
"Quit",
|
||||||
|
"Cancel",
|
||||||
|
[]() {
|
||||||
|
ultramodern::quit();
|
||||||
|
},
|
||||||
|
[]() {},
|
||||||
|
recomp::ButtonVariant::Error,
|
||||||
|
recomp::ButtonVariant::Tertiary,
|
||||||
|
true,
|
||||||
|
"config__quit-game-button"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
struct ControlOptionsContext {
|
struct ControlOptionsContext {
|
||||||
int rumble_strength = 50; // 0 to 100
|
int rumble_strength = 50; // 0 to 100
|
||||||
int gyro_sensitivity = 50; // 0 to 200
|
int gyro_sensitivity = 50; // 0 to 200
|
||||||
@ -344,7 +380,7 @@ public:
|
|||||||
});
|
});
|
||||||
recomp::register_event(listener, "config_keydown",
|
recomp::register_event(listener, "config_keydown",
|
||||||
[](const std::string& param, Rml::Event& event) {
|
[](const std::string& param, Rml::Event& event) {
|
||||||
if (event.GetId() == Rml::EventId::Keydown) {
|
if (!prompt_context.open && event.GetId() == Rml::EventId::Keydown) {
|
||||||
if (event.GetParameter<Rml::Input::KeyIdentifier>("key_identifier", Rml::Input::KeyIdentifier::KI_UNKNOWN) == Rml::Input::KeyIdentifier::KI_ESCAPE) {
|
if (event.GetParameter<Rml::Input::KeyIdentifier>("key_identifier", Rml::Input::KeyIdentifier::KI_UNKNOWN) == Rml::Input::KeyIdentifier::KI_ESCAPE) {
|
||||||
close_config_menu();
|
close_config_menu();
|
||||||
}
|
}
|
||||||
@ -362,6 +398,11 @@ public:
|
|||||||
close_config_menu();
|
close_config_menu();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
recomp::register_event(listener, "open_quit_game_prompt",
|
||||||
|
[](const std::string& param, Rml::Event& event) {
|
||||||
|
open_quit_game_prompt();
|
||||||
|
});
|
||||||
|
|
||||||
recomp::register_event(listener, "toggle_input_device",
|
recomp::register_event(listener, "toggle_input_device",
|
||||||
[](const std::string& param, Rml::Event& event) {
|
[](const std::string& param, Rml::Event& event) {
|
||||||
cur_device = cur_device == recomp::InputDevice::Controller
|
cur_device = cur_device == recomp::InputDevice::Controller
|
||||||
|
@ -987,7 +987,36 @@ struct UIContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void update_prompt_loop(void) {
|
void update_prompt_loop(void) {
|
||||||
|
static bool wasShowingPrompt = false;
|
||||||
|
|
||||||
recomp::PromptContext *ctx = recomp::get_prompt_context();
|
recomp::PromptContext *ctx = recomp::get_prompt_context();
|
||||||
|
if (!ctx->open && wasShowingPrompt) {
|
||||||
|
Rml::Element* focused = current_document->GetFocusLeafNode();
|
||||||
|
if (focused) focused->Blur();
|
||||||
|
|
||||||
|
bool didFocus = false;
|
||||||
|
|
||||||
|
if (ctx->returnElementId.size() > 0) {
|
||||||
|
Rml::Element *retEl = current_document->GetElementById(ctx->returnElementId);
|
||||||
|
if (retEl != nullptr && retEl->IsVisible()) {
|
||||||
|
retEl->Focus(true);
|
||||||
|
didFocus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!didFocus) {
|
||||||
|
Rml::ElementList tabs;
|
||||||
|
current_document->GetElementsByTagName(tabs, "tab");
|
||||||
|
for (const auto& tab : tabs) {
|
||||||
|
if (tab->IsVisible()) {
|
||||||
|
tab->Focus(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wasShowingPrompt = ctx->open;
|
||||||
|
|
||||||
if (!ctx->shouldFocus) return;
|
if (!ctx->shouldFocus) return;
|
||||||
|
|
||||||
Rml::Element* focused = current_document->GetFocusLeafNode();
|
Rml::Element* focused = current_document->GetFocusLeafNode();
|
||||||
@ -999,6 +1028,11 @@ struct UIContext {
|
|||||||
targetButton->Focus(true);
|
targetButton->Focus(true);
|
||||||
|
|
||||||
ctx->shouldFocus = false;
|
ctx->shouldFocus = false;
|
||||||
|
|
||||||
|
Rml::Element *confirmButton = current_document->GetElementById("prompt__confirm-button");
|
||||||
|
Rml::Element *cancelButton = current_document->GetElementById("prompt__cancel-button");
|
||||||
|
if (confirmButton != nullptr) confirmButton->SetClassNames("button button--" + recomp::button_variants.at(ctx->confirmVariant));
|
||||||
|
if (cancelButton != nullptr) cancelButton->SetClassNames( "button button--" + recomp::button_variants.at(ctx->cancelVariant));
|
||||||
}
|
}
|
||||||
} rml;
|
} rml;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user