mirror of
https://github.com/Zelda64Recomp/Zelda64Recomp
synced 2026-08-01 00:18:31 -04:00
fix and improve kb/cont config tab > panel navigation
prompt component - wip
This commit is contained in:
+40
-2
@@ -8,6 +8,7 @@
|
||||
#include "recomp_ui.h"
|
||||
#include "recomp_input.h"
|
||||
#include "recomp_game.h"
|
||||
#include "ui_rml_hacks.hpp"
|
||||
|
||||
#include "concurrentqueue.h"
|
||||
|
||||
@@ -956,6 +957,39 @@ struct UIContext {
|
||||
void add_menu(recomp::Menu menu, std::unique_ptr<recomp::MenuController>&& controller) {
|
||||
menus.emplace(menu, std::move(controller));
|
||||
}
|
||||
|
||||
void update_config_menu_loop(bool menu_changed) {
|
||||
static int prevTab = -1;
|
||||
if (menu_changed) prevTab = -1;
|
||||
|
||||
Rml::ElementTabSet *tabset = (Rml::ElementTabSet *)current_document->GetElementById("config_tabset");
|
||||
if (tabset == nullptr) return;
|
||||
|
||||
int curTab = tabset->GetActiveTab();
|
||||
if (curTab == prevTab) return;
|
||||
prevTab = curTab;
|
||||
|
||||
Rml::ElementList panels;
|
||||
current_document->GetElementsByTagName(panels, "panel");
|
||||
|
||||
Rml::Element *firstFocus = nullptr;
|
||||
for (const auto& panel : panels) {
|
||||
if (panel->IsVisible()) {
|
||||
firstFocus = RecompRml::FindNextTabElement(panel, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!firstFocus) return;
|
||||
Rml::String id = firstFocus->GetId();
|
||||
if (id.empty()) return;
|
||||
|
||||
Rml::ElementList tabs;
|
||||
current_document->GetElementsByTagName(tabs, "tab");
|
||||
for (const auto& tab : tabs) {
|
||||
tab->SetProperty("nav-down", "#" + id);
|
||||
}
|
||||
}
|
||||
} rml;
|
||||
};
|
||||
|
||||
@@ -1079,7 +1113,6 @@ int cont_axis_to_key(SDL_ControllerAxisEvent& axis, float value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* swap_chain_framebuffer) {
|
||||
std::lock_guard lock {ui_context_mutex};
|
||||
|
||||
@@ -1104,7 +1137,8 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||
prev_menu = recomp::Menu::None;
|
||||
}
|
||||
|
||||
if (cur_menu != prev_menu) {
|
||||
bool menu_changed = cur_menu != prev_menu;
|
||||
if (menu_changed) {
|
||||
ui_context->rml.swap_document(cur_menu);
|
||||
}
|
||||
|
||||
@@ -1123,6 +1157,10 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
|
||||
bool cont_interacted = false;
|
||||
bool kb_interacted = false;
|
||||
|
||||
if (cur_menu == recomp::Menu::Config) {
|
||||
ui_context->rml.update_config_menu_loop(menu_changed);
|
||||
}
|
||||
|
||||
while (recomp::try_deque_event(cur_event)) {
|
||||
bool menu_is_open = cur_menu != recomp::Menu::None;
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "recomp_ui.h"
|
||||
#include "RmlUi/Core.h"
|
||||
#include "ui_rml_hacks.hpp"
|
||||
|
||||
//! 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)
|
||||
{
|
||||
if (!element->IsVisible())
|
||||
return CanFocus::NoAndNoChildren;
|
||||
|
||||
const Rml::ComputedValues& computed = element->GetComputedValues();
|
||||
|
||||
if (computed.focus() == Rml::Style::Focus::None)
|
||||
return CanFocus::NoAndNoChildren;
|
||||
|
||||
if (computed.tab_index() == Rml::Style::TabIndex::Auto)
|
||||
return CanFocus::Yes;
|
||||
|
||||
return CanFocus::No;
|
||||
}
|
||||
Rml::Element* SearchFocusSubtree(Rml::Element* element, bool forward)
|
||||
{
|
||||
auto can_focus = CanFocusElement(element);
|
||||
if (can_focus == CanFocus::Yes)
|
||||
return element;
|
||||
else if (can_focus == CanFocus::NoAndNoChildren)
|
||||
return nullptr;
|
||||
|
||||
for (int i = 0; i < element->GetNumChildren(); i++)
|
||||
{
|
||||
int child_index = i;
|
||||
if (!forward)
|
||||
child_index = element->GetNumChildren() - i - 1;
|
||||
if (Rml::Element* result = SearchFocusSubtree(element->GetChild(child_index), forward))
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Rml::Element* RecompRml::FindNextTabElement(Rml::Element* current_element, bool forward)
|
||||
{
|
||||
// This algorithm is quite sneaky, I originally thought a depth first search would work, but it appears not. What is
|
||||
// required is to cut the tree in half along the nodes from current_element up the root and then either traverse the
|
||||
// tree in a clockwise or anticlock wise direction depending if you're searching forward or backward respectively.
|
||||
|
||||
// If we're searching forward, check the immediate children of this node first off.
|
||||
if (forward)
|
||||
{
|
||||
for (int i = 0; i < current_element->GetNumChildren(); i++)
|
||||
if (Rml::Element* result = SearchFocusSubtree(current_element->GetChild(i), forward))
|
||||
return result;
|
||||
}
|
||||
|
||||
// Now walk up the tree, testing either the bottom or top
|
||||
// of the tree, depending on whether we're going forward
|
||||
// or backward respectively.
|
||||
bool search_enabled = false;
|
||||
Rml::Element* document = current_element->GetOwnerDocument();
|
||||
Rml::Element* child = current_element;
|
||||
Rml::Element* parent = current_element->GetParentNode();
|
||||
while (child != document)
|
||||
{
|
||||
const int num_children = parent->GetNumChildren();
|
||||
for (int i = 0; i < num_children; i++)
|
||||
{
|
||||
// Calculate index into children
|
||||
const int child_index = forward ? i : (num_children - i - 1);
|
||||
Rml::Element* search_child = parent->GetChild(child_index);
|
||||
|
||||
// Do a search if its enabled
|
||||
if (search_enabled)
|
||||
if (Rml::Element* result = SearchFocusSubtree(search_child, forward))
|
||||
return result;
|
||||
|
||||
// Enable searching when we reach the child.
|
||||
if (search_child == child)
|
||||
search_enabled = true;
|
||||
}
|
||||
|
||||
// Advance up the tree
|
||||
child = parent;
|
||||
parent = parent->GetParentNode();
|
||||
search_enabled = false;
|
||||
}
|
||||
|
||||
// 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)
|
||||
return document;
|
||||
|
||||
// Otherwise, search the entire document tree. This way we will wrap around.
|
||||
const int num_children = document->GetNumChildren();
|
||||
for (int i = 0; i < num_children; i++)
|
||||
{
|
||||
const int child_index = forward ? i : (num_children - i - 1);
|
||||
if (Rml::Element* result = SearchFocusSubtree(document->GetChild(child_index), forward))
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef UI_RML_HACKS_H
|
||||
#define UI_RML_HACKS_H
|
||||
|
||||
#include "RmlUi/Core.h"
|
||||
namespace RecompRml {
|
||||
Rml::Element* FindNextTabElement(Rml::Element* current_element, bool forward);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user