mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-14 21:39:01 -04:00
Extract TabBar component
This commit is contained in:
+4
-4
@@ -1485,12 +1485,12 @@ set(DUSK_FILES
|
||||
src/dusk/ui/settings.hpp
|
||||
src/dusk/ui/string_button.cpp
|
||||
src/dusk/ui/string_button.hpp
|
||||
src/dusk/ui/tab_button.cpp
|
||||
src/dusk/ui/tab_button.hpp
|
||||
src/dusk/ui/ui.hpp
|
||||
src/dusk/ui/tab_bar.cpp
|
||||
src/dusk/ui/tab_bar.hpp
|
||||
src/dusk/ui/ui.cpp
|
||||
src/dusk/ui/window.hpp
|
||||
src/dusk/ui/ui.hpp
|
||||
src/dusk/ui/window.cpp
|
||||
src/dusk/ui/window.hpp
|
||||
src/dusk/achievements.cpp
|
||||
src/dusk/iso_validate.cpp
|
||||
src/dusk/livesplit.cpp
|
||||
|
||||
+1
-3
@@ -4,8 +4,6 @@
|
||||
<link type="text/rcss" href="popup.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="popup" class="popup">
|
||||
<div id="tab-bar" class="tab-bar"></div>
|
||||
</div>
|
||||
<div id="popup" class="popup"></div>
|
||||
</body>
|
||||
</rml>
|
||||
|
||||
+1
-4
@@ -4,9 +4,6 @@
|
||||
<link type="text/rcss" href="window.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="window" class="window">
|
||||
<div id="tab-bar" class="tab-bar"></div>
|
||||
<div id="content" class="content"></div>
|
||||
</div>
|
||||
<div id="window" class="window"></div>
|
||||
</body>
|
||||
</rml>
|
||||
|
||||
+26
-89
@@ -5,60 +5,36 @@
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "editor.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "tab_button.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
Popup::Popup() : Document("res/rml/popup.rml") {
|
||||
auto* tabBar = mDocument->GetElementById("tab-bar");
|
||||
if (tabBar == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::array<Rml::String, 5> tabLabels = {
|
||||
"Settings",
|
||||
"Warp",
|
||||
"Editor",
|
||||
"Reset",
|
||||
"Exit",
|
||||
};
|
||||
|
||||
// TODO: Make warp, reset, and exit buttons work
|
||||
mTabActions = {
|
||||
[this] {
|
||||
hide();
|
||||
// TODO: make this better
|
||||
auto& settingsWindow = add_document(std::make_unique<SettingsWindow>());
|
||||
settingsWindow.show();
|
||||
set_selected_tab(0);
|
||||
},
|
||||
[this] { set_selected_tab(1); },
|
||||
[this] {
|
||||
hide();
|
||||
// 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); },
|
||||
};
|
||||
|
||||
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&) {
|
||||
if (i >= 0 && i < static_cast<int>(mTabActions.size())) {
|
||||
mTabActions[i]();
|
||||
}
|
||||
}));
|
||||
}
|
||||
Popup::Popup() : Document("res/rml/popup.rml"), mRoot(mDocument->GetElementById("popup")) {
|
||||
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{.autoSelect = false});
|
||||
mTabBar->add_tab("Settings", [this] {
|
||||
hide();
|
||||
// TODO: make this better
|
||||
auto& settingsWindow = add_document(std::make_unique<SettingsWindow>());
|
||||
settingsWindow.show();
|
||||
});
|
||||
mTabBar->add_tab("Warp", [] {
|
||||
// TODO
|
||||
});
|
||||
mTabBar->add_tab("Editor", [this] {
|
||||
hide();
|
||||
// TODO: make this better
|
||||
auto& editorWindow = add_document(std::make_unique<EditorWindow>());
|
||||
editorWindow.show();
|
||||
});
|
||||
mTabBar->add_tab("Reset", [] {
|
||||
// TODO
|
||||
});
|
||||
mTabBar->add_tab("Exit", [] {
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
void Popup::show() {
|
||||
@@ -101,20 +77,6 @@ bool Popup::is_visible() const {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -130,36 +92,11 @@ void Popup::update() {
|
||||
mDocument->Hide();
|
||||
mHideDeadline.reset();
|
||||
}
|
||||
if (mTabs.empty()) {
|
||||
return;
|
||||
}
|
||||
std::vector<Button*> tabs;
|
||||
tabs.reserve(mTabs.size());
|
||||
for (const auto& tab : mTabs) {
|
||||
tabs.push_back(tab.get());
|
||||
}
|
||||
ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
Document::update();
|
||||
}
|
||||
|
||||
void Popup::set_selected_tab(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(mTabs.size())) {
|
||||
return;
|
||||
}
|
||||
mSelectedTabIndex = index;
|
||||
std::vector<Button*> tabs;
|
||||
tabs.reserve(mTabs.size());
|
||||
for (const auto& tab : mTabs) {
|
||||
tabs.push_back(tab.get());
|
||||
}
|
||||
ui::set_selected_tab(tabs, mSelectedTabIndex);
|
||||
}
|
||||
|
||||
bool Popup::focus_tab(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(mTabs.size())) {
|
||||
return false;
|
||||
}
|
||||
set_selected_tab(index);
|
||||
return mTabs[index]->focus();
|
||||
bool Popup::focus() {
|
||||
return mTabBar->focus();
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
#include "button.hpp"
|
||||
#include "document.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "tab_bar.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
class Popup : public Document {
|
||||
@@ -21,6 +22,7 @@ public:
|
||||
void show() override;
|
||||
void hide() override;
|
||||
void update() override;
|
||||
bool focus() override;
|
||||
|
||||
void toggle();
|
||||
bool is_visible() const;
|
||||
@@ -29,13 +31,9 @@ protected:
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||
|
||||
private:
|
||||
void set_selected_tab(int index);
|
||||
bool focus_tab(int index);
|
||||
|
||||
std::vector<std::unique_ptr<Button> > mTabs;
|
||||
std::vector<std::function<void()> > mTabActions;
|
||||
Rml::Element* mRoot;
|
||||
std::unique_ptr<TabBar> mTabBar;
|
||||
std::unique_ptr<Button> mCloseButton;
|
||||
int mSelectedTabIndex = 0;
|
||||
bool mVisible = false;
|
||||
std::optional<std::chrono::steady_clock::time_point> mHideDeadline;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "tab_bar.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
|
||||
Rml::Element* createRoot(Rml::Element* parent) {
|
||||
auto* doc = parent->GetOwnerDocument();
|
||||
auto elem = doc->CreateElement("div");
|
||||
elem->SetClass("tab-bar", true);
|
||||
return parent->AppendChild(std::move(elem));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TabBar::TabBar(Rml::Element* parent, Props props)
|
||||
: Component(createRoot(parent)), mProps(std::move(props)) {
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool TabBar::focus() {
|
||||
if (mProps.selectedTabIndex >= 0 && mProps.selectedTabIndex < mTabs.size()) {
|
||||
// Try to focus the currently selected tab
|
||||
if (mTabs[mProps.selectedTabIndex].button.focus()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Otherwise, focus the first enabled tab
|
||||
for (const auto& tab : mTabs) {
|
||||
if (tab.button.focus()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TabBar::add_tab(const Rml::String& title, TabCallback callback) {
|
||||
const int index = static_cast<int>(mTabs.size());
|
||||
const bool selected = index == mProps.selectedTabIndex;
|
||||
if (selected && callback) {
|
||||
callback();
|
||||
}
|
||||
mTabs.emplace_back(Tab{
|
||||
.title = title,
|
||||
.button = add_child<Button>(mRoot,
|
||||
Button::Props{
|
||||
.text = title,
|
||||
.onPressed = [this, index](Rml::Event&) { set_active_tab(index); },
|
||||
.selected = selected,
|
||||
},
|
||||
"tab"),
|
||||
.callback = std::move(callback),
|
||||
});
|
||||
}
|
||||
|
||||
bool TabBar::set_active_tab(int index) {
|
||||
if (index < 0 || index >= mTabs.size() || index == mProps.selectedTabIndex) {
|
||||
return false;
|
||||
}
|
||||
const auto& tab = mTabs[index];
|
||||
if (tab.button.focus()) {
|
||||
for (int i = 0; i < static_cast<int>(mTabs.size()); ++i) {
|
||||
mTabs[i].button.set_selected(i == index);
|
||||
}
|
||||
mProps.selectedTabIndex = index;
|
||||
if (tab.callback) {
|
||||
tab.callback();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TabBar::focus_tab(int index) {
|
||||
if (index < 0 || index >= mTabs.size() || index == mProps.selectedTabIndex) {
|
||||
return false;
|
||||
}
|
||||
const auto& tab = mTabs[index];
|
||||
return tab.button.focus();
|
||||
}
|
||||
|
||||
int TabBar::tab_containing(Rml::Element* element) const {
|
||||
for (int i = 0; i < mTabs.size(); ++i) {
|
||||
if (mTabs[i].button.contains(element)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool TabBar::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
if (cmd == NavCommand::Left || cmd == NavCommand::Right || cmd == NavCommand::Next ||
|
||||
cmd == NavCommand::Previous)
|
||||
{
|
||||
bool isNext = cmd == NavCommand::Right || cmd == NavCommand::Next;
|
||||
int currentComponent = tab_containing(event.GetTargetElement());
|
||||
int direction = isNext ? 1 : -1;
|
||||
int i = currentComponent + direction;
|
||||
if (currentComponent == -1) {
|
||||
// If the container itself is focused and right is pressed, focus the first element
|
||||
if (isNext) {
|
||||
i = 0;
|
||||
} else {
|
||||
// Otherwise, allow event to bubble
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (i >= 0 && i < mTabs.size()) {
|
||||
if (mProps.autoSelect ? set_active_tab(i) : focus_tab(i)) {
|
||||
return true;
|
||||
}
|
||||
i += direction;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "button.hpp"
|
||||
#include "component.hpp"
|
||||
#include "select_button.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
using TabCallback = std::function<void()>;
|
||||
|
||||
struct Tab {
|
||||
Rml::String title;
|
||||
Button& button;
|
||||
TabCallback callback;
|
||||
};
|
||||
|
||||
class TabBar : public Component {
|
||||
public:
|
||||
struct Props {
|
||||
std::function<void()> onClose;
|
||||
int selectedTabIndex = -1;
|
||||
bool autoSelect = true;
|
||||
};
|
||||
|
||||
explicit TabBar(Rml::Element* parent, Props props);
|
||||
|
||||
bool focus() override;
|
||||
|
||||
void add_tab(const Rml::String& title, TabCallback callback);
|
||||
bool set_active_tab(int index);
|
||||
bool focus_tab(int index);
|
||||
int tab_containing(Rml::Element* element) const;
|
||||
int count() const { return mTabs.size(); }
|
||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd);
|
||||
|
||||
private:
|
||||
Props mProps;
|
||||
std::vector<Tab> mTabs;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "tab_button.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
std::unique_ptr<Button> create_tab_button(Rml::Element* tabBar, const Rml::String& title,
|
||||
bool selected, std::function<void(Rml::Event&)> onPressed) {
|
||||
return std::make_unique<Button>(tabBar,
|
||||
Button::Props{
|
||||
.text = title,
|
||||
.onPressed = std::move(onPressed),
|
||||
.selected = selected,
|
||||
},
|
||||
"tab");
|
||||
}
|
||||
|
||||
void set_selected_tab(std::vector<Button*>& tabs, int selectedIndex) {
|
||||
for (int i = 0; i < static_cast<int>(tabs.size()); ++i) {
|
||||
tabs[i]->set_selected(i == selectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dusk::ui
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "button.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
std::unique_ptr<Button> create_tab_button(Rml::Element* tabBar, const Rml::String& title, bool selected, std::function<void(Rml::Event&)> onPressed);
|
||||
void set_selected_tab(std::vector<Button*>& tabs, int selectedIndex);
|
||||
|
||||
} // namespace dusk::ui
|
||||
+22
-87
@@ -3,7 +3,6 @@
|
||||
#include "aurora/lib/window.hpp"
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "magic_enum.hpp"
|
||||
#include "tab_button.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -26,7 +25,17 @@ float base_body_padding(Rml::Context* context) noexcept {
|
||||
|
||||
} // namespace
|
||||
|
||||
Window::Window() : Document("res/rml/window.rml") {
|
||||
Window::Window() : Document("res/rml/window.rml"), mRoot(mDocument->GetElementById("window")) {
|
||||
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{
|
||||
.selectedTabIndex = 0,
|
||||
.autoSelect = true,
|
||||
});
|
||||
|
||||
auto elem = mDocument->CreateElement("div");
|
||||
elem->SetAttribute("id", "content");
|
||||
elem->SetClass("content", true);
|
||||
mContentRoot = mRoot->AppendChild(std::move(elem));
|
||||
|
||||
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
// 1-9 for quick switching tabs
|
||||
const auto key = static_cast<Rml::Input::KeyIdentifier>(
|
||||
@@ -80,60 +89,27 @@ void Window::update_safe_area() noexcept {
|
||||
}
|
||||
|
||||
bool Window::set_active_tab(int index) {
|
||||
if (index < 0 || index >= mTabs.size() || index == mSelectedTabIndex) {
|
||||
return false;
|
||||
}
|
||||
const auto& tab = mTabs[index];
|
||||
if (tab.button->focus()) {
|
||||
clear_content();
|
||||
std::vector<Button*> buttons;
|
||||
buttons.reserve(mTabs.size());
|
||||
for (auto& tab : mTabs) {
|
||||
buttons.push_back(tab.button.get());
|
||||
}
|
||||
set_selected_tab(buttons, index);
|
||||
mSelectedTabIndex = index;
|
||||
if (tab.builder) {
|
||||
tab.builder(mDocument->GetElementById("content"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return mTabBar->set_active_tab(index);
|
||||
}
|
||||
|
||||
void Window::add_tab(const Rml::String& title, TabBuilder builder) {
|
||||
const int index = static_cast<int>(mTabs.size());
|
||||
if (index == mSelectedTabIndex && builder) {
|
||||
builder(mDocument->GetElementById("content"));
|
||||
}
|
||||
auto* tabBar = mDocument->GetElementById("tab-bar");
|
||||
mTabs.emplace_back(Tab{
|
||||
.title = title,
|
||||
.button = create_tab_button(
|
||||
tabBar, title, index == mSelectedTabIndex, [this, index](Rml::Event&) {
|
||||
set_active_tab(index);
|
||||
}),
|
||||
.builder = std::move(builder),
|
||||
mTabBar->add_tab(title, [this, builder = std::move(builder)] {
|
||||
clear_content();
|
||||
if (builder) {
|
||||
builder(mContentRoot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Window::clear_content() noexcept {
|
||||
mContentComponents.clear();
|
||||
auto* content = mDocument->GetElementById("content");
|
||||
while (content->GetNumChildren() != 0) {
|
||||
content->RemoveChild(content->GetFirstChild());
|
||||
while (mContentRoot->GetNumChildren() != 0) {
|
||||
mContentRoot->RemoveChild(mContentRoot->GetFirstChild());
|
||||
}
|
||||
}
|
||||
|
||||
bool Window::focus() {
|
||||
if (mTabs.empty()) {
|
||||
return false;
|
||||
}
|
||||
int i = mSelectedTabIndex;
|
||||
if (i < 0 || i >= mTabs.size()) {
|
||||
i = 0;
|
||||
}
|
||||
return mTabs[i].button->focus();
|
||||
return mTabBar->focus();
|
||||
}
|
||||
|
||||
bool Window::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||
@@ -143,53 +119,12 @@ bool Window::handle_nav_command(Rml::Event& event, NavCommand 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()) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
} else if (cmd == NavCommand::Left || cmd == NavCommand::Right || cmd == NavCommand::Next ||
|
||||
cmd == NavCommand::Previous)
|
||||
{
|
||||
bool isNext = cmd == NavCommand::Right || cmd == NavCommand::Next;
|
||||
int currentComponent = -1;
|
||||
for (int i = 0; i < mTabs.size(); ++i) {
|
||||
if (mTabs[i].button->contains(event.GetTargetElement())) {
|
||||
currentComponent = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int direction = isNext ? 1 : -1;
|
||||
int i = currentComponent + direction;
|
||||
if (currentComponent == -1) {
|
||||
// If the container itself is focused and right is pressed, focus the first element
|
||||
if (isNext) {
|
||||
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 (cmd == NavCommand::Confirm || cmd == NavCommand::Down) {
|
||||
if (!mContentComponents.empty()) {
|
||||
return mContentComponents.front()->focus();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return mTabBar->handle_nav_command(event, cmd);
|
||||
}
|
||||
|
||||
bool Window::handle_content_nav(Rml::Event& event, NavCommand cmd) noexcept {
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#include "button.hpp"
|
||||
#include "component.hpp"
|
||||
#include "document.hpp"
|
||||
#include "ui.hpp"
|
||||
#include "nav_types.hpp"
|
||||
#include "tab_bar.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
namespace dusk::ui {
|
||||
|
||||
@@ -31,7 +32,6 @@ protected:
|
||||
void update_safe_area() noexcept;
|
||||
void clear_content() 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;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
@@ -42,11 +42,11 @@ protected:
|
||||
return ref;
|
||||
}
|
||||
|
||||
std::vector<Tab> mTabs;
|
||||
Rml::Element* mRoot;
|
||||
Rml::Element* mContentRoot;
|
||||
std::unique_ptr<TabBar> mTabBar;
|
||||
std::vector<std::unique_ptr<Component> > mContentComponents;
|
||||
Insets mBodyPadding;
|
||||
int mSelectedTabIndex = 0;
|
||||
std::unique_ptr<ScopedEventListener> mKeyListener;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
Reference in New Issue
Block a user