mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-06 09:22:31 -04:00
Begin scaffolding keyboard nav
This commit is contained in:
+126
-9
@@ -2,10 +2,14 @@
|
||||
|
||||
#include <RmlUi/Core.h>
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "button.hpp"
|
||||
#include "magic_enum.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
static aurora::Module Log{"dusk::ui::window"};
|
||||
|
||||
Window::Window() {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
@@ -17,6 +21,37 @@ Window::Window() {
|
||||
if (mDocument == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mKeyListener = std::make_unique<ScopedEventListener>(
|
||||
mDocument, Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
// 1-9 for quick switching tabs
|
||||
const auto key = static_cast<Rml::Input::KeyIdentifier>(
|
||||
event.GetParameter<int>("key_identifier", Rml::Input::KI_UNKNOWN));
|
||||
if (key >= Rml::Input::KeyIdentifier::KI_1 && key <= Rml::Input::KeyIdentifier::KI_9) {
|
||||
if (set_active_tab(key - Rml::Input::KeyIdentifier::KI_1)) {
|
||||
if (!mContentComponents.empty()) {
|
||||
mContentComponents.front()->focus();
|
||||
}
|
||||
event.StopPropagation();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::None) {
|
||||
return;
|
||||
}
|
||||
auto* target = event.GetTargetElement();
|
||||
if (target->Closest(".tab-bar")) {
|
||||
if (handle_tab_bar_nav(event, cmd)) {
|
||||
event.StopPropagation();
|
||||
}
|
||||
} else if (target->Closest(".content")) {
|
||||
if (handle_content_nav(event, cmd)) {
|
||||
event.StopPropagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
@@ -45,19 +80,23 @@ void Window::update() {
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_active_tab(int index) {
|
||||
bool Window::set_active_tab(int index) {
|
||||
if (index < 0 || index >= mTabs.size() || index == mSelectedTabIndex) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
clear_content();
|
||||
for (int i = 0; i < mTabs.size(); i++) {
|
||||
mTabs[i].button->set_selected(i == index);
|
||||
}
|
||||
mSelectedTabIndex = index;
|
||||
const auto& tab = mTabs[index];
|
||||
if (tab.builder) {
|
||||
tab.builder(mDocument->GetElementById("content"));
|
||||
if (tab.button->focus()) {
|
||||
clear_content();
|
||||
for (int i = 0; i < mTabs.size(); i++) {
|
||||
mTabs[i].button->set_selected(i == index);
|
||||
}
|
||||
mSelectedTabIndex = index;
|
||||
if (tab.builder) {
|
||||
tab.builder(mDocument->GetElementById("content"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Window::add_tab(const Rml::String& title, TabBuilder builder) {
|
||||
@@ -87,4 +126,82 @@ void Window::clear_content() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::focus_active_tab() noexcept {
|
||||
if (mTabs.empty()) {
|
||||
return false;
|
||||
}
|
||||
int i = mSelectedTabIndex;
|
||||
if (i < 0 || i >= mTabs.size()) {
|
||||
i = 0;
|
||||
}
|
||||
return mTabs[i].button->focus();
|
||||
}
|
||||
|
||||
bool Window::handle_tab_bar_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
if (cmd == NavCommand::Down) {
|
||||
if (!mContentComponents.empty()) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
} else if (cmd == NavCommand::Left || cmd == NavCommand::Right) {
|
||||
int currentComponent = -1;
|
||||
for (int i = 0; i < mTabs.size(); ++i) {
|
||||
if (mTabs[i].button->contains(event.GetTargetElement())) {
|
||||
currentComponent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int direction = cmd == NavCommand::Right ? 1 : -1;
|
||||
int i = currentComponent + direction;
|
||||
if (currentComponent == -1) {
|
||||
// If the container itself is focused and right is pressed, focus the first element
|
||||
if (cmd == NavCommand::Right) {
|
||||
i = 0;
|
||||
} else {
|
||||
// Otherwise, allow event to bubble
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (i >= 0 && i < static_cast<int>(mTabs.size())) {
|
||||
if (set_active_tab(i)) {
|
||||
return true;
|
||||
}
|
||||
i += direction;
|
||||
}
|
||||
} else if (cmd == NavCommand::Cancel) {
|
||||
// TODO: close window
|
||||
} else if (cmd == NavCommand::Confirm) {
|
||||
if (!mContentComponents.empty()) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Window::handle_content_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
if (cmd == NavCommand::Up || cmd == NavCommand::Cancel) {
|
||||
return focus_active_tab();
|
||||
} else if (cmd == NavCommand::Down) {
|
||||
if (!mContentComponents.empty()) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
} else if (cmd == NavCommand::Left || cmd == NavCommand::Right) {
|
||||
int currentComponent = -1;
|
||||
for (int i = 0; i < mContentComponents.size(); ++i) {
|
||||
if (mContentComponents[i]->contains(event.GetTargetElement())) {
|
||||
currentComponent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int direction = cmd == NavCommand::Right ? 1 : -1;
|
||||
int i = currentComponent + direction;
|
||||
if (currentComponent == -1) {
|
||||
if (cmd == NavCommand::Right) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
} else if (i >= 0 && i < mContentComponents.size()) {
|
||||
return mContentComponents[i]->focus();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
Reference in New Issue
Block a user