mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-24 06:50:43 -04:00
UI: Extract a Document class
This commit is contained in:
@@ -1466,6 +1466,8 @@ set(DUSK_FILES
|
||||
src/dusk/ui/button.hpp
|
||||
src/dusk/ui/component.cpp
|
||||
src/dusk/ui/component.hpp
|
||||
src/dusk/ui/document.cpp
|
||||
src/dusk/ui/document.hpp
|
||||
src/dusk/ui/editor.cpp
|
||||
src/dusk/ui/editor.hpp
|
||||
src/dusk/ui/event.cpp
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "document.hpp"
|
||||
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
|
||||
Rml::ElementDocument* load_document(const Rml::String& path) {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
if (context == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return context->LoadDocument(path);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Document::Document(const Rml::String& path) : mDocument(load_document(path)) {
|
||||
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd != NavCommand::None && handle_nav_command(event, cmd)) {
|
||||
event.StopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Document::~Document() {
|
||||
mListeners.clear();
|
||||
if (mDocument != nullptr) {
|
||||
mDocument->Close();
|
||||
mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Document::show() {
|
||||
if (mDocument != nullptr) {
|
||||
mDocument->Show();
|
||||
focus();
|
||||
}
|
||||
}
|
||||
|
||||
void Document::hide() {
|
||||
if (mDocument != nullptr) {
|
||||
mDocument->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void Document::update() {}
|
||||
|
||||
bool Document::focus() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Document::listen(Rml::Element* element, Rml::EventId event,
|
||||
ScopedEventListener::Callback callback, bool capture) {
|
||||
if (element == nullptr) {
|
||||
element = mDocument;
|
||||
}
|
||||
if (element == nullptr || !callback) {
|
||||
return;
|
||||
}
|
||||
mListeners.emplace_back(
|
||||
std::make_unique<ScopedEventListener>(element, event, std::move(callback), capture));
|
||||
}
|
||||
|
||||
bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "component.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class Document {
|
||||
public:
|
||||
Document(const Rml::String& path);
|
||||
virtual ~Document();
|
||||
|
||||
Document(const Document&) = delete;
|
||||
Document& operator=(const Document&) = delete;
|
||||
|
||||
virtual void show();
|
||||
virtual void hide();
|
||||
virtual void update();
|
||||
virtual bool focus();
|
||||
|
||||
void listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback,
|
||||
bool capture = false);
|
||||
void listen(Rml::EventId event, ScopedEventListener::Callback callback, bool capture = false) {
|
||||
listen(mDocument, event, std::move(callback), capture);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool handle_nav_command(Rml::Event& event, NavCommand cmd);
|
||||
|
||||
Rml::ElementDocument* mDocument;
|
||||
std::vector<std::unique_ptr<ScopedEventListener> > mListeners;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
+44
-70
@@ -3,6 +3,8 @@
|
||||
#include <RmlUi/Core.h>
|
||||
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "editor.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "tab_button.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "window.hpp"
|
||||
@@ -10,22 +12,10 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
Popup::Popup(Window& settingsWindow, Window& editorWindow)
|
||||
: mSettingsWindow(settingsWindow), mEditorWindow(editorWindow) {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDocument = context->LoadDocument("res/rml/popup.rml");
|
||||
if (mDocument == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Popup::Popup() : Document("res/rml/popup.rml") {
|
||||
auto* tabBar = mDocument->GetElementById("tab-bar");
|
||||
if (tabBar == nullptr) {
|
||||
return;
|
||||
@@ -43,72 +33,32 @@ Popup::Popup(Window& settingsWindow, Window& editorWindow)
|
||||
mTabActions = {
|
||||
[this] {
|
||||
hide();
|
||||
mSettingsWindow.show();
|
||||
mSettingsWindow.focus_for_input();
|
||||
// TODO: make this better
|
||||
auto& settingsWindow = add_document(std::make_unique<SettingsWindow>());
|
||||
settingsWindow.show();
|
||||
set_selected_tab(0);
|
||||
},
|
||||
[this] {
|
||||
set_selected_tab(1);
|
||||
},
|
||||
[this] { set_selected_tab(1); },
|
||||
[this] {
|
||||
hide();
|
||||
mEditorWindow.show();
|
||||
mEditorWindow.focus_for_input();
|
||||
// TODO: make this better
|
||||
auto& editorWindow = add_document(std::make_unique<EditorWindow>());
|
||||
editorWindow.show();
|
||||
set_selected_tab(2);
|
||||
},
|
||||
[this] {
|
||||
set_selected_tab(3);
|
||||
},
|
||||
[this] {
|
||||
set_selected_tab(4);
|
||||
},
|
||||
[this] { set_selected_tab(3); },
|
||||
[this] { set_selected_tab(4); },
|
||||
};
|
||||
|
||||
mTabs.reserve(tabLabels.size());
|
||||
for (int i = 0; i < static_cast<int>(tabLabels.size()); ++i) {
|
||||
mTabs.push_back(create_tab_button(tabBar, tabLabels[i], i == mSelectedTabIndex,
|
||||
[this, i](Rml::Event&) {
|
||||
mTabs.push_back(
|
||||
create_tab_button(tabBar, tabLabels[i], i == mSelectedTabIndex, [this, i](Rml::Event&) {
|
||||
if (i >= 0 && i < static_cast<int>(mTabActions.size())) {
|
||||
mTabActions[i]();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
mKeyListener = std::make_unique<ScopedEventListener>(
|
||||
mDocument, Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::None) {
|
||||
return;
|
||||
}
|
||||
if (cmd == NavCommand::Left || cmd == NavCommand::Previous) {
|
||||
focus_tab(std::max(0, mSelectedTabIndex - 1));
|
||||
event.StopPropagation();
|
||||
return;
|
||||
}
|
||||
if (cmd == NavCommand::Right || cmd == NavCommand::Next) {
|
||||
focus_tab(std::min(static_cast<int>(mTabs.size()) - 1, mSelectedTabIndex + 1));
|
||||
event.StopPropagation();
|
||||
return;
|
||||
}
|
||||
if (cmd == NavCommand::Confirm && mSelectedTabIndex >= 0 &&
|
||||
mSelectedTabIndex < static_cast<int>(mTabActions.size()))
|
||||
{
|
||||
mTabActions[mSelectedTabIndex]();
|
||||
event.StopPropagation();
|
||||
return;
|
||||
}
|
||||
if (cmd == NavCommand::Cancel) {
|
||||
hide();
|
||||
event.StopPropagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Popup::~Popup() {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
if (context != nullptr && mDocument != nullptr) {
|
||||
context->UnloadDocument(mDocument);
|
||||
}
|
||||
}
|
||||
|
||||
void Popup::show() {
|
||||
@@ -117,7 +67,7 @@ void Popup::show() {
|
||||
}
|
||||
|
||||
mHideDeadline.reset();
|
||||
mDocument->Show();
|
||||
Document::show();
|
||||
mVisible = true;
|
||||
}
|
||||
|
||||
@@ -129,9 +79,11 @@ void Popup::hide() {
|
||||
|
||||
if (auto* popup = mDocument->GetElementById("popup")) {
|
||||
popup->SetClass("popup-hidden", true);
|
||||
mHideDeadline = std::chrono::steady_clock::now() + std::chrono::milliseconds(500); // Must match the transition duration in popup.rcss
|
||||
mHideDeadline =
|
||||
std::chrono::steady_clock::now() +
|
||||
std::chrono::milliseconds(500); // Must match the transition duration in popup.rcss
|
||||
} else {
|
||||
mDocument->Hide();
|
||||
Document::hide();
|
||||
}
|
||||
mVisible = false;
|
||||
}
|
||||
@@ -148,7 +100,29 @@ bool Popup::is_visible() const {
|
||||
return mVisible;
|
||||
}
|
||||
|
||||
void Popup::update() noexcept {
|
||||
bool Popup::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
if (cmd == NavCommand::Left || cmd == NavCommand::Previous) {
|
||||
focus_tab(std::max(0, mSelectedTabIndex - 1));
|
||||
return true;
|
||||
}
|
||||
if (cmd == NavCommand::Right || cmd == NavCommand::Next) {
|
||||
focus_tab(std::min(static_cast<int>(mTabs.size()) - 1, mSelectedTabIndex + 1));
|
||||
return true;
|
||||
}
|
||||
if (cmd == NavCommand::Confirm && mSelectedTabIndex >= 0 &&
|
||||
mSelectedTabIndex < static_cast<int>(mTabActions.size()))
|
||||
{
|
||||
mTabActions[mSelectedTabIndex]();
|
||||
return true;
|
||||
}
|
||||
if (cmd == NavCommand::Cancel) {
|
||||
hide();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Popup::update() {
|
||||
if (mDocument == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -164,7 +138,7 @@ void Popup::update() noexcept {
|
||||
for (const auto& tab : mTabs) {
|
||||
tabs.push_back(tab.get());
|
||||
}
|
||||
dusk::ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
}
|
||||
|
||||
void Popup::set_selected_tab(int index) {
|
||||
@@ -177,7 +151,7 @@ void Popup::set_selected_tab(int index) {
|
||||
for (const auto& tab : mTabs) {
|
||||
tabs.push_back(tab.get());
|
||||
}
|
||||
dusk::ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
}
|
||||
|
||||
bool Popup::focus_tab(int index) {
|
||||
|
||||
+10
-14
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/ElementDocument.h>
|
||||
|
||||
#include "button.hpp"
|
||||
#include "document.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
#include <chrono>
|
||||
@@ -12,36 +11,33 @@
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class Window;
|
||||
|
||||
class Popup {
|
||||
class Popup : public Document {
|
||||
public:
|
||||
Popup(Window& settingsWindow, Window& editorWindow);
|
||||
~Popup();
|
||||
Popup();
|
||||
|
||||
Popup(const Popup&) = delete;
|
||||
Popup& operator=(const Popup&) = delete;
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
void show() override;
|
||||
void hide() override;
|
||||
void update() override;
|
||||
|
||||
void toggle();
|
||||
bool is_visible() const;
|
||||
void update() noexcept;
|
||||
|
||||
protected:
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
|
||||
private:
|
||||
void set_selected_tab(int index);
|
||||
bool focus_tab(int index);
|
||||
|
||||
Window& mSettingsWindow;
|
||||
Window& mEditorWindow;
|
||||
Rml::ElementDocument* mDocument = nullptr;
|
||||
std::vector<std::unique_ptr<Button> > mTabs;
|
||||
std::vector<std::function<void()> > mTabActions;
|
||||
std::unique_ptr<Button> mCloseButton;
|
||||
int mSelectedTabIndex = 0;
|
||||
bool mVisible = false;
|
||||
std::optional<std::chrono::steady_clock::time_point> mHideDeadline;
|
||||
std::unique_ptr<ScopedEventListener> mKeyListener;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
+49
-20
@@ -4,9 +4,10 @@
|
||||
#include <SDL3/SDL_filesystem.h>
|
||||
#include <aurora/rmlui.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
#include "popup.hpp"
|
||||
#include "aurora/lib/window.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
@@ -17,8 +18,7 @@ void load_font(const char* filename, bool fallback = false) {
|
||||
}
|
||||
|
||||
bool sInitialized = false;
|
||||
std::vector<std::unique_ptr<Window> > sWindows;
|
||||
std::unique_ptr<Popup> sPopup;
|
||||
std::vector<std::unique_ptr<Document> > sDocuments;
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -39,8 +39,7 @@ bool initialize() noexcept {
|
||||
}
|
||||
|
||||
void shutdown() noexcept {
|
||||
sPopup.reset();
|
||||
sWindows.clear();
|
||||
sDocuments.clear();
|
||||
sInitialized = false;
|
||||
}
|
||||
|
||||
@@ -48,27 +47,23 @@ void handle_event(const SDL_Event& event) noexcept {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Window& add_window(std::unique_ptr<Window> window) noexcept {
|
||||
Window& ret = *window;
|
||||
sWindows.push_back(std::move(window));
|
||||
Document& add_document(std::unique_ptr<Document> doc) noexcept {
|
||||
Document& ret = *doc;
|
||||
sDocuments.push_back(std::move(doc));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void remove_window(Window& window) noexcept {
|
||||
// TODO
|
||||
}
|
||||
|
||||
Popup& add_popup(std::unique_ptr<Popup> popupMenu) noexcept {
|
||||
sPopup = std::move(popupMenu);
|
||||
return *sPopup;
|
||||
void remove_document(Document& doc) noexcept {
|
||||
const auto it = std::find_if(sDocuments.begin(), sDocuments.end(),
|
||||
[&doc](const std::unique_ptr<Document>& current) { return current.get() == &doc; });
|
||||
if (it != sDocuments.end()) {
|
||||
sDocuments.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void update() noexcept {
|
||||
for (const auto& window : sWindows) {
|
||||
window->update();
|
||||
}
|
||||
if (sPopup != nullptr) {
|
||||
sPopup->update();
|
||||
for (const auto& doc : sDocuments) {
|
||||
doc->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,4 +128,38 @@ NavCommand map_nav_event(const Rml::Event& event) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
Insets safe_area_insets(Rml::Context* context) noexcept {
|
||||
if (context == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* window = aurora::window::get_sdl_window();
|
||||
if (window == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const AuroraWindowSize windowSize = aurora::window::get_window_size();
|
||||
if (windowSize.width == 0 || windowSize.height == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_Rect safeRect{};
|
||||
if (!SDL_GetWindowSafeArea(window, &safeRect)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Rml::Vector2i contextSize = context->GetDimensions();
|
||||
const float scaleX = static_cast<float>(contextSize.x) / static_cast<float>(windowSize.width);
|
||||
const float scaleY = static_cast<float>(contextSize.y) / static_cast<float>(windowSize.height);
|
||||
|
||||
const float safeRight = static_cast<float>(safeRect.x + safeRect.w);
|
||||
const float safeBottom = static_cast<float>(safeRect.y + safeRect.h);
|
||||
return {
|
||||
.top = std::max(0.0f, static_cast<float>(safeRect.y)) * scaleY,
|
||||
.right = std::max(0.0f, static_cast<float>(windowSize.width) - safeRight) * scaleX,
|
||||
.bottom = std::max(0.0f, static_cast<float>(windowSize.height) - safeBottom) * scaleY,
|
||||
.left = std::max(0.0f, static_cast<float>(safeRect.x)) * scaleX,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
+21
-4
@@ -1,23 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/Event.h>
|
||||
#include <RmlUi/Core.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "nav_types.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
class Window;
|
||||
class Document;
|
||||
class Popup;
|
||||
|
||||
struct Insets {
|
||||
float top = 0.0f;
|
||||
float right = 0.0f;
|
||||
float bottom = 0.0f;
|
||||
float left = 0.0f;
|
||||
|
||||
bool operator==(const Insets& other) const noexcept {
|
||||
return top == other.top && right == other.right && bottom == other.bottom &&
|
||||
left == other.left;
|
||||
}
|
||||
};
|
||||
|
||||
bool initialize() noexcept;
|
||||
void shutdown() noexcept;
|
||||
|
||||
void handle_event(const SDL_Event& event) noexcept;
|
||||
void update() noexcept;
|
||||
|
||||
Window& add_window(std::unique_ptr<Window> window) noexcept;
|
||||
void remove_window(Window& window) noexcept;
|
||||
Document& add_document(std::unique_ptr<Document> doc) noexcept;
|
||||
void remove_document(Document& doc) noexcept;
|
||||
|
||||
Popup& add_popup(std::unique_ptr<Popup> popup) noexcept;
|
||||
|
||||
@@ -25,5 +41,6 @@ std::filesystem::path resource_path(const std::filesystem::path& filename) noexc
|
||||
std::string escape(std::string_view str) noexcept;
|
||||
|
||||
NavCommand map_nav_event(const Rml::Event& event) noexcept;
|
||||
Insets safe_area_insets(Rml::Context* context) noexcept;
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
+27
-110
@@ -1,8 +1,5 @@
|
||||
#include "window.hpp"
|
||||
|
||||
#include <RmlUi/Core.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include "aurora/lib/window.hpp"
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "magic_enum.hpp"
|
||||
@@ -27,113 +24,22 @@ float base_body_padding(Rml::Context* context) noexcept {
|
||||
return 64.0f * dpRatio;
|
||||
}
|
||||
|
||||
Window::Insets safe_area_insets(Rml::Context* context) noexcept {
|
||||
if (context == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto* window = aurora::window::get_sdl_window();
|
||||
if (window == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const AuroraWindowSize windowSize = aurora::window::get_window_size();
|
||||
if (windowSize.width == 0 || windowSize.height == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
SDL_Rect safeRect{};
|
||||
if (!SDL_GetWindowSafeArea(window, &safeRect)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const Rml::Vector2i contextSize = context->GetDimensions();
|
||||
const float scaleX = static_cast<float>(contextSize.x) / static_cast<float>(windowSize.width);
|
||||
const float scaleY = static_cast<float>(contextSize.y) / static_cast<float>(windowSize.height);
|
||||
|
||||
const float safeRight = static_cast<float>(safeRect.x + safeRect.w);
|
||||
const float safeBottom = static_cast<float>(safeRect.y + safeRect.h);
|
||||
return {
|
||||
.top = std::max(0.0f, static_cast<float>(safeRect.y)) * scaleY,
|
||||
.right = std::max(0.0f, static_cast<float>(windowSize.width) - safeRight) * scaleX,
|
||||
.bottom = std::max(0.0f, static_cast<float>(windowSize.height) - safeBottom) * scaleY,
|
||||
.left = std::max(0.0f, static_cast<float>(safeRect.x)) * scaleX,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Window::Window() {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
if (context == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDocument = context->LoadDocument("res/rml/window.rml");
|
||||
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;
|
||||
Window::Window() : Document("res/rml/window.rml") {
|
||||
listen(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();
|
||||
}
|
||||
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::None) {
|
||||
return;
|
||||
}
|
||||
auto* target = event.GetTargetElement();
|
||||
if (cmd == NavCommand::Next || cmd == NavCommand::Previous ||
|
||||
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() {
|
||||
auto* context = aurora::rmlui::get_context();
|
||||
if (context != nullptr && mDocument != nullptr) {
|
||||
context->UnloadDocument(mDocument);
|
||||
mDocument = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::show() {
|
||||
if (mDocument != nullptr) {
|
||||
mDocument->Show();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::hide() {
|
||||
if (mDocument != nullptr) {
|
||||
mDocument->Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::focus_for_input() noexcept {
|
||||
if (!mContentComponents.empty()) {
|
||||
if (mContentComponents.front()->focus()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
focus_active_tab();
|
||||
});
|
||||
}
|
||||
|
||||
void Window::update() {
|
||||
@@ -141,6 +47,7 @@ void Window::update() {
|
||||
for (const auto& component : mContentComponents) {
|
||||
component->update();
|
||||
}
|
||||
Document::update();
|
||||
}
|
||||
|
||||
void Window::update_safe_area() noexcept {
|
||||
@@ -208,9 +115,6 @@ void Window::add_tab(const Rml::String& title, TabBuilder builder) {
|
||||
}),
|
||||
.builder = std::move(builder),
|
||||
});
|
||||
if (index == mSelectedTabIndex) {
|
||||
focus_active_tab();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::clear_content() noexcept {
|
||||
@@ -221,7 +125,7 @@ void Window::clear_content() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::focus_active_tab() noexcept {
|
||||
bool Window::focus() {
|
||||
if (mTabs.empty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -232,6 +136,19 @@ bool Window::focus_active_tab() noexcept {
|
||||
return mTabs[i].button->focus();
|
||||
}
|
||||
|
||||
bool Window::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
auto* target = event.GetTargetElement();
|
||||
if (cmd != NavCommand::Next && cmd != NavCommand::Previous && target->Closest(".content")) {
|
||||
if (handle_content_nav(event, cmd)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (handle_tab_bar_nav(event, cmd)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Window::handle_tab_bar_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
if (cmd == NavCommand::Down) {
|
||||
if (!mContentComponents.empty()) {
|
||||
@@ -277,7 +194,7 @@ bool Window::handle_tab_bar_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
|
||||
bool Window::handle_content_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
if (cmd == NavCommand::Up || cmd == NavCommand::Cancel) {
|
||||
return focus_active_tab();
|
||||
return focus();
|
||||
} else if (cmd == NavCommand::Left || cmd == NavCommand::Right) {
|
||||
int currentComponent = -1;
|
||||
for (int i = 0; i < mContentComponents.size(); ++i) {
|
||||
|
||||
+6
-24
@@ -1,15 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <RmlUi/Core/DataModelHandle.h>
|
||||
#include <RmlUi/Core/ElementDocument.h>
|
||||
|
||||
#include "button.hpp"
|
||||
#include "component.hpp"
|
||||
#include "document.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "nav_types.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class Window {
|
||||
class Window : public Document {
|
||||
public:
|
||||
using TabBuilder = std::function<void(Rml::Element*)>;
|
||||
struct Tab {
|
||||
@@ -17,37 +16,21 @@ public:
|
||||
std::unique_ptr<Button> button;
|
||||
TabBuilder builder;
|
||||
};
|
||||
struct Insets {
|
||||
float top = 0.0f;
|
||||
float right = 0.0f;
|
||||
float bottom = 0.0f;
|
||||
float left = 0.0f;
|
||||
|
||||
bool operator==(const Insets& other) const noexcept {
|
||||
return top == other.top && right == other.right && bottom == other.bottom &&
|
||||
left == other.left;
|
||||
}
|
||||
};
|
||||
|
||||
Window();
|
||||
~Window();
|
||||
|
||||
Window(const Window&) = delete;
|
||||
Window& operator=(const Window&) = delete;
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
|
||||
void focus_for_input() noexcept;
|
||||
|
||||
void update();
|
||||
void update() override;
|
||||
bool focus() override;
|
||||
bool set_active_tab(int index);
|
||||
|
||||
protected:
|
||||
void add_tab(const Rml::String& title, TabBuilder builder);
|
||||
void update_safe_area() noexcept;
|
||||
void clear_content() noexcept;
|
||||
bool focus_active_tab() noexcept;
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
bool handle_tab_bar_nav(Rml::Event& event, NavCommand cmd) noexcept;
|
||||
bool handle_content_nav(Rml::Event& event, NavCommand cmd) noexcept;
|
||||
|
||||
@@ -59,7 +42,6 @@ protected:
|
||||
return ref;
|
||||
}
|
||||
|
||||
Rml::ElementDocument* mDocument = nullptr;
|
||||
std::vector<Tab> mTabs;
|
||||
std::vector<std::unique_ptr<Component> > mContentComponents;
|
||||
Insets mBodyPadding;
|
||||
|
||||
@@ -589,11 +589,11 @@ int game_main(int argc, char* argv[]) {
|
||||
dusk::ui::initialize();
|
||||
|
||||
// TODO: just for testing
|
||||
auto& editorWindow = dusk::ui::add_window(std::make_unique<dusk::ui::EditorWindow>());
|
||||
// auto& editorWindow = dusk::ui::add_document(std::make_unique<dusk::ui::EditorWindow>());
|
||||
// editorWindow.show();
|
||||
auto& settingsWindow = dusk::ui::add_window(std::make_unique<dusk::ui::SettingsWindow>());
|
||||
// auto& settingsWindow = dusk::ui::add_document(std::make_unique<dusk::ui::SettingsWindow>());
|
||||
// settingsWindow.show();
|
||||
auto& popup = dusk::ui::add_popup(std::make_unique<dusk::ui::Popup>(settingsWindow, editorWindow));
|
||||
auto& popup = dusk::ui::add_document(std::make_unique<dusk::ui::Popup>());
|
||||
popup.show();
|
||||
|
||||
std::string dvd_path;
|
||||
|
||||
Reference in New Issue
Block a user