mirror of
https://github.com/Mr-Wiseguy/Zelda64Recomp.git
synced 2024-11-22 12:59:14 +01:00
Cont/kb/mouse focus priorities and behaviors reworked (#15)
* ensure focus after cont/kb input + enable mouse on SDL_QUIT + force focus to prompt while open * only force prompt focus if mouse is not active * default kb input, mouse click switches to kb focused input
This commit is contained in:
parent
956db3366f
commit
7491eabde0
File diff suppressed because one or more lines are too long
@ -13,7 +13,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.centered-page__modal {
|
.centered-page__modal {
|
||||||
@extend %nav-all;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
|
@ -5,7 +5,7 @@ $prompt-space: 24;
|
|||||||
.prompt {
|
.prompt {
|
||||||
&__overlay {
|
&__overlay {
|
||||||
background-color: $color-bg-overlay;
|
background-color: $color-bg-overlay;
|
||||||
pointer-events: none;
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__overlay,
|
&__overlay,
|
||||||
|
@ -78,7 +78,7 @@ namespace recomp {
|
|||||||
void stop_scanning_input();
|
void stop_scanning_input();
|
||||||
void finish_scanning_input(InputField scanned_field);
|
void finish_scanning_input(InputField scanned_field);
|
||||||
void cancel_scanning_input();
|
void cancel_scanning_input();
|
||||||
void set_cont_or_kb(bool cont_interacted);
|
void config_menu_set_cont_or_kb(bool cont_interacted);
|
||||||
InputField get_scanned_input();
|
InputField get_scanned_input();
|
||||||
|
|
||||||
struct DefaultN64Mappings {
|
struct DefaultN64Mappings {
|
||||||
|
@ -116,6 +116,8 @@ namespace recomp {
|
|||||||
PromptContext *get_prompt_context(void);
|
PromptContext *get_prompt_context(void);
|
||||||
|
|
||||||
bool get_cont_active(void);
|
bool get_cont_active(void);
|
||||||
|
void set_cont_active(bool active);
|
||||||
|
void activate_mouse();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,6 +139,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
recomp::open_quit_game_prompt();
|
recomp::open_quit_game_prompt();
|
||||||
|
recomp::activate_mouse();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_EventType::SDL_MOUSEWHEEL:
|
case SDL_EventType::SDL_MOUSEWHEEL:
|
||||||
|
@ -181,18 +181,20 @@ void recomp::cancel_scanning_input() {
|
|||||||
controls_model_handle.DirtyVariable("active_binding_slot");
|
controls_model_handle.DirtyVariable("active_binding_slot");
|
||||||
}
|
}
|
||||||
|
|
||||||
void recomp::set_cont_or_kb(bool cont_interacted) {
|
void recomp::config_menu_set_cont_or_kb(bool cont_interacted) {
|
||||||
if (nav_help_model_handle && cont_active != cont_interacted) {
|
if (cont_active != cont_interacted) {
|
||||||
cont_active = cont_interacted;
|
cont_active = cont_interacted;
|
||||||
nav_help_model_handle.DirtyVariable("nav_help__navigate");
|
|
||||||
nav_help_model_handle.DirtyVariable("nav_help__accept");
|
|
||||||
graphics_model_handle.DirtyVariable("gfx_help__apply");
|
|
||||||
nav_help_model_handle.DirtyVariable("nav_help__exit");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool recomp::get_cont_active() {
|
if (nav_help_model_handle) {
|
||||||
return cont_active;
|
nav_help_model_handle.DirtyVariable("nav_help__navigate");
|
||||||
|
nav_help_model_handle.DirtyVariable("nav_help__accept");
|
||||||
|
nav_help_model_handle.DirtyVariable("nav_help__exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (graphics_model_handle) {
|
||||||
|
graphics_model_handle.DirtyVariable("gfx_help__apply");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_config_menu_impl() {
|
void close_config_menu_impl() {
|
||||||
@ -890,6 +892,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void make_bindings(Rml::Context* context) override {
|
void make_bindings(Rml::Context* context) override {
|
||||||
|
// initially set cont state for ui help
|
||||||
|
recomp::config_menu_set_cont_or_kb(recomp::get_cont_active());
|
||||||
make_nav_help_bindings(context);
|
make_nav_help_bindings(context);
|
||||||
make_general_bindings(context);
|
make_general_bindings(context);
|
||||||
make_controls_bindings(context);
|
make_controls_bindings(context);
|
||||||
|
@ -786,6 +786,7 @@ struct UIContext {
|
|||||||
public:
|
public:
|
||||||
bool mouse_is_active_initialized = false;
|
bool mouse_is_active_initialized = false;
|
||||||
bool mouse_is_active = false;
|
bool mouse_is_active = false;
|
||||||
|
bool cont_is_active = false;
|
||||||
bool await_stick_return_x = false;
|
bool await_stick_return_x = false;
|
||||||
bool await_stick_return_y = false;
|
bool await_stick_return_y = false;
|
||||||
int last_active_mouse_position[2] = {0, 0};
|
int last_active_mouse_position[2] = {0, 0};
|
||||||
@ -929,11 +930,25 @@ struct UIContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_focus(bool mouse_moved) {
|
void update_focus(bool mouse_moved, bool non_mouse_interacted) {
|
||||||
if (current_document == nullptr) {
|
if (current_document == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cont_is_active || non_mouse_interacted) {
|
||||||
|
if (non_mouse_interacted) {
|
||||||
|
auto focusedEl = current_document->GetFocusLeafNode();
|
||||||
|
Rml::Variant* ti = focusedEl == nullptr ? nullptr : focusedEl->GetAttribute("tab-index");
|
||||||
|
if (focusedEl == nullptr || RecompRml::CanFocusElement(focusedEl) != RecompRml::CanFocus::Yes) {
|
||||||
|
Rml::Element* element = find_autofocus_element(current_document);
|
||||||
|
if (element != nullptr) {
|
||||||
|
element->Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If there was mouse motion, get the current hovered element (or its target if it points to one) and focus that if applicable.
|
// If there was mouse motion, get the current hovered element (or its target if it points to one) and focus that if applicable.
|
||||||
if (mouse_is_active) {
|
if (mouse_is_active) {
|
||||||
if (mouse_is_active_changed) {
|
if (mouse_is_active_changed) {
|
||||||
@ -1034,14 +1049,38 @@ struct UIContext {
|
|||||||
}
|
}
|
||||||
wasShowingPrompt = ctx->open;
|
wasShowingPrompt = ctx->open;
|
||||||
|
|
||||||
if (!ctx->shouldFocus) return;
|
if (!ctx->open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Rml::Element* focused = current_document->GetFocusLeafNode();
|
Rml::Element* focused = current_document->GetFocusLeafNode();
|
||||||
if (focused) focused->Blur();
|
// Check if unfocused or current focus isn't either prompt button
|
||||||
|
if (mouse_is_active == false) {
|
||||||
|
if (
|
||||||
|
focused == nullptr || (
|
||||||
|
focused != current_document->GetElementById("prompt__cancel-button") &&
|
||||||
|
focused != current_document->GetElementById("prompt__confirm-button")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
ctx->shouldFocus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->shouldFocus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (focused != nullptr) {
|
||||||
|
focused->Blur();
|
||||||
|
}
|
||||||
|
|
||||||
Rml::Element *targetButton = current_document->GetElementById(
|
Rml::Element *targetButton = current_document->GetElementById(
|
||||||
ctx->focusOnCancel ? "prompt__cancel-button" : "prompt__confirm-button");
|
ctx->focusOnCancel ? "prompt__cancel-button" : "prompt__confirm-button");
|
||||||
|
|
||||||
|
if (targetButton == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
targetButton->Focus(true);
|
targetButton->Focus(true);
|
||||||
|
|
||||||
ctx->shouldFocus = false;
|
ctx->shouldFocus = false;
|
||||||
@ -1189,6 +1228,19 @@ void apply_background_input_mode() {
|
|||||||
last_input_mode = cur_input_mode;
|
last_input_mode = cur_input_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool recomp::get_cont_active() {
|
||||||
|
return ui_context->rml.cont_is_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::set_cont_active(bool active) {
|
||||||
|
ui_context->rml.cont_is_active = active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recomp::activate_mouse() {
|
||||||
|
ui_context->rml.update_primary_input(true, false);
|
||||||
|
ui_context->rml.update_focus(true, false);
|
||||||
|
}
|
||||||
|
|
||||||
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* swap_chain_framebuffer) {
|
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* swap_chain_framebuffer) {
|
||||||
std::lock_guard lock {ui_context_mutex};
|
std::lock_guard lock {ui_context_mutex};
|
||||||
|
|
||||||
@ -1231,6 +1283,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||||||
SDL_Event cur_event{};
|
SDL_Event cur_event{};
|
||||||
|
|
||||||
bool mouse_moved = false;
|
bool mouse_moved = false;
|
||||||
|
bool mouse_clicked = false;
|
||||||
bool non_mouse_interacted = false;
|
bool non_mouse_interacted = false;
|
||||||
bool cont_interacted = false;
|
bool cont_interacted = false;
|
||||||
bool kb_interacted = false;
|
bool kb_interacted = false;
|
||||||
@ -1269,6 +1322,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||||||
// fallthrough
|
// fallthrough
|
||||||
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
|
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
|
||||||
mouse_moved = true;
|
mouse_moved = true;
|
||||||
|
mouse_clicked = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN: {
|
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN: {
|
||||||
@ -1342,9 +1396,10 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||||||
}
|
}
|
||||||
} // end dequeue event loop
|
} // end dequeue event loop
|
||||||
|
|
||||||
if (cont_interacted || kb_interacted) {
|
if (cont_interacted || kb_interacted || mouse_clicked) {
|
||||||
recomp::set_cont_or_kb(cont_interacted);
|
recomp::set_cont_active(cont_interacted);
|
||||||
}
|
}
|
||||||
|
recomp::config_menu_set_cont_or_kb(ui_context->rml.cont_is_active);
|
||||||
|
|
||||||
recomp::InputField scanned_field = recomp::get_scanned_input();
|
recomp::InputField scanned_field = recomp::get_scanned_input();
|
||||||
if (scanned_field != recomp::InputField{}) {
|
if (scanned_field != recomp::InputField{}) {
|
||||||
@ -1352,7 +1407,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||||||
}
|
}
|
||||||
|
|
||||||
ui_context->rml.update_primary_input(mouse_moved, non_mouse_interacted);
|
ui_context->rml.update_primary_input(mouse_moved, non_mouse_interacted);
|
||||||
ui_context->rml.update_focus(mouse_moved);
|
ui_context->rml.update_focus(mouse_moved, non_mouse_interacted);
|
||||||
|
|
||||||
if (cur_menu != recomp::Menu::None) {
|
if (cur_menu != recomp::Menu::None) {
|
||||||
int width = swap_chain_framebuffer->getWidth();
|
int width = swap_chain_framebuffer->getWidth();
|
||||||
|
@ -5,28 +5,28 @@
|
|||||||
//! these are hidden methods not exposed by RmlUi
|
//! these are hidden methods not exposed by RmlUi
|
||||||
//! they may need to be updated eventually with RmlUi
|
//! they may need to be updated eventually with RmlUi
|
||||||
|
|
||||||
enum class CanFocus { Yes, No, NoAndNoChildren };
|
RecompRml::CanFocus RecompRml::CanFocusElement(Rml::Element* element)
|
||||||
CanFocus CanFocusElement(Rml::Element* element)
|
|
||||||
{
|
{
|
||||||
if (!element->IsVisible())
|
if (!element->IsVisible())
|
||||||
return CanFocus::NoAndNoChildren;
|
return RecompRml::CanFocus::NoAndNoChildren;
|
||||||
|
|
||||||
const Rml::ComputedValues& computed = element->GetComputedValues();
|
const Rml::ComputedValues& computed = element->GetComputedValues();
|
||||||
|
|
||||||
if (computed.focus() == Rml::Style::Focus::None)
|
if (computed.focus() == Rml::Style::Focus::None)
|
||||||
return CanFocus::NoAndNoChildren;
|
return RecompRml::CanFocus::NoAndNoChildren;
|
||||||
|
|
||||||
if (computed.tab_index() == Rml::Style::TabIndex::Auto)
|
if (computed.tab_index() == Rml::Style::TabIndex::Auto)
|
||||||
return CanFocus::Yes;
|
return RecompRml::CanFocus::Yes;
|
||||||
|
|
||||||
return CanFocus::No;
|
return RecompRml::CanFocus::No;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rml::Element* SearchFocusSubtree(Rml::Element* element, bool forward)
|
Rml::Element* SearchFocusSubtree(Rml::Element* element, bool forward)
|
||||||
{
|
{
|
||||||
auto can_focus = CanFocusElement(element);
|
auto can_focus = RecompRml::CanFocusElement(element);
|
||||||
if (can_focus == CanFocus::Yes)
|
if (can_focus == RecompRml::CanFocus::Yes)
|
||||||
return element;
|
return element;
|
||||||
else if (can_focus == CanFocus::NoAndNoChildren)
|
else if (can_focus == RecompRml::CanFocus::NoAndNoChildren)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
for (int i = 0; i < element->GetNumChildren(); i++)
|
for (int i = 0; i < element->GetNumChildren(); i++)
|
||||||
@ -90,7 +90,7 @@ Rml::Element* RecompRml::FindNextTabElement(Rml::Element* current_element, bool
|
|||||||
// We could not find anything to focus along this direction.
|
// We could not find anything to focus along this direction.
|
||||||
|
|
||||||
// If we can focus the document, then focus that now.
|
// If we can focus the document, then focus that now.
|
||||||
if (current_element != document && CanFocusElement(document) == CanFocus::Yes)
|
if (current_element != document && RecompRml::CanFocusElement(document) == RecompRml::CanFocus::Yes)
|
||||||
return document;
|
return document;
|
||||||
|
|
||||||
// Otherwise, search the entire document tree. This way we will wrap around.
|
// Otherwise, search the entire document tree. This way we will wrap around.
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#include "RmlUi/Core.h"
|
#include "RmlUi/Core.h"
|
||||||
namespace RecompRml {
|
namespace RecompRml {
|
||||||
Rml::Element* FindNextTabElement(Rml::Element* current_element, bool forward);
|
Rml::Element* FindNextTabElement(Rml::Element* current_element, bool forward);
|
||||||
|
|
||||||
|
enum class CanFocus { Yes, No, NoAndNoChildren };
|
||||||
|
|
||||||
|
CanFocus CanFocusElement(Rml::Element* element);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user