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 {
|
||||
@extend %nav-all;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex: 1 1 100%;
|
||||
|
|
|
@ -5,7 +5,7 @@ $prompt-space: 24;
|
|||
.prompt {
|
||||
&__overlay {
|
||||
background-color: $color-bg-overlay;
|
||||
pointer-events: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
&__overlay,
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace recomp {
|
|||
void stop_scanning_input();
|
||||
void finish_scanning_input(InputField scanned_field);
|
||||
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();
|
||||
|
||||
struct DefaultN64Mappings {
|
||||
|
|
|
@ -116,6 +116,8 @@ namespace recomp {
|
|||
PromptContext *get_prompt_context(void);
|
||||
|
||||
bool get_cont_active(void);
|
||||
void set_cont_active(bool active);
|
||||
void activate_mouse();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -139,6 +139,7 @@ bool sdl_event_filter(void* userdata, SDL_Event* event) {
|
|||
}
|
||||
|
||||
recomp::open_quit_game_prompt();
|
||||
recomp::activate_mouse();
|
||||
break;
|
||||
}
|
||||
case SDL_EventType::SDL_MOUSEWHEEL:
|
||||
|
|
|
@ -181,18 +181,20 @@ void recomp::cancel_scanning_input() {
|
|||
controls_model_handle.DirtyVariable("active_binding_slot");
|
||||
}
|
||||
|
||||
void recomp::set_cont_or_kb(bool cont_interacted) {
|
||||
if (nav_help_model_handle && cont_active != cont_interacted) {
|
||||
void recomp::config_menu_set_cont_or_kb(bool cont_interacted) {
|
||||
if (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() {
|
||||
return cont_active;
|
||||
if (nav_help_model_handle) {
|
||||
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() {
|
||||
|
@ -890,6 +892,8 @@ public:
|
|||
}
|
||||
|
||||
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_general_bindings(context);
|
||||
make_controls_bindings(context);
|
||||
|
|
|
@ -786,6 +786,7 @@ struct UIContext {
|
|||
public:
|
||||
bool mouse_is_active_initialized = false;
|
||||
bool mouse_is_active = false;
|
||||
bool cont_is_active = false;
|
||||
bool await_stick_return_x = false;
|
||||
bool await_stick_return_y = false;
|
||||
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) {
|
||||
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 (mouse_is_active) {
|
||||
if (mouse_is_active_changed) {
|
||||
|
@ -1034,14 +1049,38 @@ struct UIContext {
|
|||
}
|
||||
wasShowingPrompt = ctx->open;
|
||||
|
||||
if (!ctx->shouldFocus) return;
|
||||
if (!ctx->open) {
|
||||
return;
|
||||
}
|
||||
|
||||
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(
|
||||
ctx->focusOnCancel ? "prompt__cancel-button" : "prompt__confirm-button");
|
||||
|
||||
if (targetButton == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
targetButton->Focus(true);
|
||||
|
||||
ctx->shouldFocus = false;
|
||||
|
@ -1189,6 +1228,19 @@ void apply_background_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) {
|
||||
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{};
|
||||
|
||||
bool mouse_moved = false;
|
||||
bool mouse_clicked = false;
|
||||
bool non_mouse_interacted = false;
|
||||
bool cont_interacted = false;
|
||||
bool kb_interacted = false;
|
||||
|
@ -1269,6 +1322,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||
// fallthrough
|
||||
case SDL_EventType::SDL_MOUSEBUTTONDOWN:
|
||||
mouse_moved = true;
|
||||
mouse_clicked = true;
|
||||
break;
|
||||
|
||||
case SDL_EventType::SDL_CONTROLLERBUTTONDOWN: {
|
||||
|
@ -1342,9 +1396,10 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
|||
}
|
||||
} // end dequeue event loop
|
||||
|
||||
if (cont_interacted || kb_interacted) {
|
||||
recomp::set_cont_or_kb(cont_interacted);
|
||||
if (cont_interacted || kb_interacted || mouse_clicked) {
|
||||
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();
|
||||
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_focus(mouse_moved);
|
||||
ui_context->rml.update_focus(mouse_moved, non_mouse_interacted);
|
||||
|
||||
if (cur_menu != recomp::Menu::None) {
|
||||
int width = swap_chain_framebuffer->getWidth();
|
||||
|
|
|
@ -5,28 +5,28 @@
|
|||
//! these are hidden methods not exposed by RmlUi
|
||||
//! they may need to be updated eventually with RmlUi
|
||||
|
||||
enum class CanFocus { Yes, No, NoAndNoChildren };
|
||||
CanFocus CanFocusElement(Rml::Element* element)
|
||||
RecompRml::CanFocus RecompRml::CanFocusElement(Rml::Element* element)
|
||||
{
|
||||
if (!element->IsVisible())
|
||||
return CanFocus::NoAndNoChildren;
|
||||
return RecompRml::CanFocus::NoAndNoChildren;
|
||||
|
||||
const Rml::ComputedValues& computed = element->GetComputedValues();
|
||||
|
||||
if (computed.focus() == Rml::Style::Focus::None)
|
||||
return CanFocus::NoAndNoChildren;
|
||||
return RecompRml::CanFocus::NoAndNoChildren;
|
||||
|
||||
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)
|
||||
{
|
||||
auto can_focus = CanFocusElement(element);
|
||||
if (can_focus == CanFocus::Yes)
|
||||
auto can_focus = RecompRml::CanFocusElement(element);
|
||||
if (can_focus == RecompRml::CanFocus::Yes)
|
||||
return element;
|
||||
else if (can_focus == CanFocus::NoAndNoChildren)
|
||||
else if (can_focus == RecompRml::CanFocus::NoAndNoChildren)
|
||||
return nullptr;
|
||||
|
||||
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.
|
||||
|
||||
// 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;
|
||||
|
||||
// Otherwise, search the entire document tree. This way we will wrap around.
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#include "RmlUi/Core.h"
|
||||
namespace RecompRml {
|
||||
Rml::Element* FindNextTabElement(Rml::Element* current_element, bool forward);
|
||||
|
||||
enum class CanFocus { Yes, No, NoAndNoChildren };
|
||||
|
||||
CanFocus CanFocusElement(Rml::Element* element);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue