diff --git a/extern/aurora b/extern/aurora
index 1bd972429e..285c11a13c 160000
--- a/extern/aurora
+++ b/extern/aurora
@@ -1 +1 @@
-Subproject commit 1bd972429ebba4e486012b1acd08d4d7580eb917
+Subproject commit 285c11a13c9200be196a3c407e31a642824658a9
diff --git a/res/rml/popup.rcss b/res/rml/popup.rcss
index 852ab2ce39..0ebe05f640 100644
--- a/res/rml/popup.rcss
+++ b/res/rml/popup.rcss
@@ -19,7 +19,7 @@ button {
focus: auto;
}
-.popup {
+popup {
width: 100%;
display: flex;
align-items: stretch;
@@ -28,15 +28,15 @@ button {
background-color: rgba(21, 22, 16, 80%);
border-bottom: 2dp #92875B;
backdrop-filter: blur(5dp);
- transform: translateY(0);
+ transform: translateY(-64dp);
transition: transform 0.2s cubic-in-out;
}
-.popup.popup-hidden {
- transform: translateY(-64dp);
+popup[open] {
+ transform: translateY(0);
}
-.popup .tab-bar {
+popup tab-bar {
display: flex;
flex: 1 1 0;
min-width: 0;
@@ -44,7 +44,7 @@ button {
text-transform: uppercase;
}
-.popup .tab-bar .tab {
+popup tab-bar tab {
flex: 0 0 auto;
padding: 0 24dp;
line-height: 64dp;
@@ -55,19 +55,19 @@ button {
transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out;
}
-.popup .tab-bar .tab.selected {
+popup tab-bar tab.selected {
opacity: 1;
border-bottom: 4dp #C2A42D;
font-effect: glow(0dp 4dp 0dp 4dp black);
}
-.popup .tab-bar .tab:focus-visible,
-.popup .tab-bar .tab:hover {
+popup tab-bar tab:focus-visible,
+popup tab-bar tab:hover {
opacity: 1;
font-effect: glow(0dp 4dp 0dp 4dp black);
decorator: vertical-gradient(#c2a42d00 #c2a42d26);
}
-.popup .tab-bar .tab:active {
+popup tab-bar tab:active {
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
}
diff --git a/res/rml/popup.rml b/res/rml/popup.rml
deleted file mode 100644
index 05be1a5c2d..0000000000
--- a/res/rml/popup.rml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Popup
-
-
-
-
-
-
diff --git a/res/rml/window.rcss b/res/rml/window.rcss
index 7a14f55096..93e891f01d 100644
--- a/res/rml/window.rcss
+++ b/res/rml/window.rcss
@@ -13,12 +13,7 @@ body {
color: #E0DBC8;
}
-button {
- cursor: pointer;
- focus: auto;
-}
-
-.window {
+window {
display: flex;
flex-flow: column;
height: 100%;
@@ -31,18 +26,27 @@ button {
backdrop-filter: blur(5dp);
box-shadow: 0 0 25dp 5dp;
background-color: rgba(21, 22, 16, 90%);
+ filter: opacity(0);
+ transform: scale(0.9);
+ transform-origin: center;
+ transition: filter transform 0.2s cubic-in-out;
+}
+
+window[open] {
+ filter: opacity(1);
+ transform: scale(1);
}
@media (max-height: 640dp) {
body {
padding: 16dp;
}
- .window {
+ window {
box-shadow: none;
}
}
-.window .tab-bar {
+window tab-bar {
display: flex;
flex: 0 0 64dp;
height: 64dp;
@@ -56,7 +60,7 @@ button {
border-bottom: 2dp #92875B;
}
-.window .tab-bar .tab {
+window tab-bar tab {
flex: 0 0 auto;
padding: 0 24dp;
line-height: 64dp;
@@ -66,24 +70,24 @@ button {
transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out;
}
-.window .tab-bar .tab.selected {
+window tab-bar tab.selected {
opacity: 1;
border-bottom: 4dp #C2A42D;
font-effect: glow(0dp 4dp 0dp 4dp black);
}
-.window .tab-bar .tab:focus-visible,
-.window .tab-bar .tab:hover {
+window tab-bar tab:focus-visible,
+window tab-bar tab:hover {
opacity: 1;
font-effect: glow(0dp 4dp 0dp 4dp black);
decorator: vertical-gradient(#c2a42d00 #c2a42d26);
}
-.window .tab-bar .tab:active {
+window tab-bar tab:active {
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
}
-.window .content {
+window content {
display: flex;
flex: 1 1 0;
min-width: 0;
@@ -91,7 +95,7 @@ button {
overflow: hidden;
}
-.window .content .pane {
+window content pane {
display: flex;
flex-flow: column;
flex: 1 1 0;
@@ -104,15 +108,15 @@ button {
overflow: hidden auto;
}
-.window .content .pane:not(:last-of-type) {
+window content pane:not(:last-of-type) {
border-right: 1dp #92875B;
}
-.window .content .pane > * {
+window content pane > * {
flex: 0 0 auto;
}
-.window .content .pane > .spacer {
+window content pane > spacer {
display: block;
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
flex: 0 0 16dp;
@@ -176,7 +180,7 @@ scrollbarhorizontal sliderbar {
padding-top: 12dp;
}
-.button {
+button {
text-align: center;
background-color: rgba(17, 16, 10, 20%);
opacity: 0.9;
@@ -185,23 +189,25 @@ scrollbarhorizontal sliderbar {
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
font-size: 20dp;
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
+ cursor: pointer;
+ focus: auto;
}
-.button:not(:disabled).active,
-.button:not(:disabled):hover,
-.button:not(:disabled):focus-visible {
+button:not(:disabled).active,
+button:not(:disabled):hover,
+button:not(:disabled):focus-visible {
background-color: rgba(204, 184, 119, 20%);
box-shadow: #C2A42D 0 0 0 2dp;
}
-.button:not(:disabled).selected,
-.button:not(:disabled):active {
+button:not(:disabled).selected,
+button:not(:disabled):active {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
box-shadow: #C2A42D 0 0 0 2dp;
}
-.select-button {
+select-button {
display: flex;
align-items: center;
gap: 8dp;
@@ -211,28 +217,30 @@ scrollbarhorizontal sliderbar {
border-radius: 14dp;
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
+ cursor: pointer;
+ focus: auto;
}
-.select-button:not(:disabled).active,
-.select-button:not(:disabled):hover,
-.select-button:not(:disabled):focus-visible {
+select-button:not(:disabled).active,
+select-button:not(:disabled):hover,
+select-button:not(:disabled):focus-visible {
background-color: rgba(204, 184, 119, 20%);
box-shadow: #C2A42D 0 0 0 2dp;
}
-.select-button:not(:disabled).selected,
-.select-button:not(:disabled):active {
+select-button:not(:disabled).selected,
+select-button:not(:disabled):active {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
box-shadow: #C2A42D 0 0 0 2dp;
}
-.select-button:disabled {
+select-button:disabled {
opacity: 0.35;
cursor: default;
}
-.select-button .key {
+select-button key {
font-family: "Fira Sans Condensed";
font-weight: bold;
font-size: 18dp;
@@ -240,12 +248,12 @@ scrollbarhorizontal sliderbar {
flex: 1 0 auto;
}
-.select-button .value {
+select-button value {
margin-left: auto;
font-size: 20dp;
}
-.select-button input {
+select-button input {
text-align: right;
font-size: 20dp;
}
diff --git a/res/rml/window.rml b/res/rml/window.rml
deleted file mode 100644
index 4947c281c7..0000000000
--- a/res/rml/window.rml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
- Window
-
-
-
-
-
-
diff --git a/src/dusk/ui/button.cpp b/src/dusk/ui/button.cpp
index 832c2a9876..b315de1291 100644
--- a/src/dusk/ui/button.cpp
+++ b/src/dusk/ui/button.cpp
@@ -7,17 +7,16 @@
namespace dusk::ui {
namespace {
-Rml::Element* createRoot(Rml::Element* parent, const Rml::String& className) {
+Rml::Element* createRoot(Rml::Element* parent, const Rml::String& tagName) {
auto* doc = parent->GetOwnerDocument();
- auto elem = doc->CreateElement("button");
- elem->SetClass(className, true);
+ auto elem = doc->CreateElement(tagName);
return parent->AppendChild(std::move(elem));
}
} // namespace
-Button::Button(Rml::Element* parent, ButtonProps props, const Rml::String& className)
- : Component(createRoot(parent, className)) {
+Button::Button(Rml::Element* parent, ButtonProps props, const Rml::String& tagName)
+ : Component(createRoot(parent, tagName)) {
update_props(std::move(props));
listen(mRoot, Rml::EventId::Click, [this](Rml::Event& event) {
if (mProps.onPressed) {
diff --git a/src/dusk/ui/button.hpp b/src/dusk/ui/button.hpp
index deaadde12b..902a82a312 100644
--- a/src/dusk/ui/button.hpp
+++ b/src/dusk/ui/button.hpp
@@ -14,7 +14,7 @@ class Button : public Component {
public:
using Props = ButtonProps;
- Button(Rml::Element* parent, ButtonProps props, const Rml::String& className = "button");
+ Button(Rml::Element* parent, ButtonProps props, const Rml::String& tagName = "button");
void set_text(const Rml::String& text);
void set_selected(bool selected);
diff --git a/src/dusk/ui/document.cpp b/src/dusk/ui/document.cpp
index f6a73f8c42..b3eefc95ad 100644
--- a/src/dusk/ui/document.cpp
+++ b/src/dusk/ui/document.cpp
@@ -6,17 +6,17 @@
namespace dusk::ui {
namespace {
-Rml::ElementDocument* load_document(const Rml::String& path) {
+Rml::ElementDocument* load_document(const Rml::String& source) {
auto* context = aurora::rmlui::get_context();
if (context == nullptr) {
return nullptr;
}
- return context->LoadDocument(path);
+ return context->LoadDocumentFromMemory(source);
}
} // namespace
-Document::Document(const Rml::String& path) : mDocument(load_document(path)) {
+Document::Document(const Rml::String& source) : mDocument(load_document(source)) {
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
if (cmd != NavCommand::None && handle_nav_command(event, cmd)) {
diff --git a/src/dusk/ui/document.hpp b/src/dusk/ui/document.hpp
index 3827a147a1..d27d20c59d 100644
--- a/src/dusk/ui/document.hpp
+++ b/src/dusk/ui/document.hpp
@@ -7,7 +7,7 @@ namespace dusk::ui {
class Document {
public:
- Document(const Rml::String& path);
+ Document(const Rml::String& source);
virtual ~Document();
Document(const Document&) = delete;
diff --git a/src/dusk/ui/pane.cpp b/src/dusk/ui/pane.cpp
index 8fe05763d6..dd6ad9f27f 100644
--- a/src/dusk/ui/pane.cpp
+++ b/src/dusk/ui/pane.cpp
@@ -5,17 +5,16 @@
namespace dusk::ui {
namespace {
-Rml::Element* createRoot(Rml::Element* parent, const Rml::String& className) {
+Rml::Element* createRoot(Rml::Element* parent) {
auto* doc = parent->GetOwnerDocument();
- auto elem = doc->CreateElement("div");
- elem->SetClass(className, true);
+ auto elem = doc->CreateElement("pane");
return parent->AppendChild(std::move(elem));
}
} // namespace
-Pane::Pane(Rml::Element* parent, Direction direction, const Rml::String& className)
- : Component(createRoot(parent, className)), mDirection(direction) {
+Pane::Pane(Rml::Element* parent, Direction direction)
+ : Component(createRoot(parent)), mDirection(direction) {
listen(mRoot, Rml::EventId::Keydown, [this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
int direction = 0;
@@ -95,8 +94,7 @@ void Pane::finalize() {
// padding-bottom or margin-bottom on a scrollable flex container, so
// we need to create a fake spacer with an actual layout height to get
// padding at the bottom of a scrollable container.
- auto* elem = append(mRoot, "div");
- elem->SetClass("spacer", true);
+ append(mRoot, "spacer");
}
void Pane::clear() {
diff --git a/src/dusk/ui/pane.hpp b/src/dusk/ui/pane.hpp
index f354d6f106..ed9f0e6733 100644
--- a/src/dusk/ui/pane.hpp
+++ b/src/dusk/ui/pane.hpp
@@ -13,7 +13,7 @@ public:
Horizontal,
};
- explicit Pane(Rml::Element* parent, Direction direction, const Rml::String& className = "pane");
+ explicit Pane(Rml::Element* parent, Direction direction);
bool focus() override;
void update() override;
diff --git a/src/dusk/ui/popup.cpp b/src/dusk/ui/popup.cpp
index 000025b4c2..c95387b213 100644
--- a/src/dusk/ui/popup.cpp
+++ b/src/dusk/ui/popup.cpp
@@ -11,8 +11,22 @@
#include
namespace dusk::ui {
+namespace {
-Popup::Popup() : Document("res/rml/popup.rml"), mRoot(mDocument->GetElementById("popup")) {
+const Rml::String kDocumentSource = R"RML(
+
+
+
+
+
+
+)RML";
+
+}
+
+Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) {
mTabBar = std::make_unique(mRoot, TabBar::Props{.autoSelect = false});
mTabBar->add_tab("Settings", [] { push_document(std::make_unique()); });
mTabBar->add_tab("Warp", [] {
@@ -48,7 +62,7 @@ void Popup::show() {
}
Document::show();
- mRoot->SetClass("popup-hidden", false);
+ mRoot->SetAttribute("open", "");
mTabBar->set_active_tab(-1);
mVisible = true;
}
@@ -62,7 +76,7 @@ void Popup::hide() {
return;
}
- mRoot->SetClass("popup-hidden", true);
+ mRoot->RemoveAttribute("open");
mVisible = false;
}
diff --git a/src/dusk/ui/select_button.cpp b/src/dusk/ui/select_button.cpp
index 707f605e82..13cfaba37f 100644
--- a/src/dusk/ui/select_button.cpp
+++ b/src/dusk/ui/select_button.cpp
@@ -9,18 +9,15 @@ namespace {
Rml::Element* createRoot(Rml::Element* parent) {
auto* doc = parent->GetOwnerDocument();
- auto elem = doc->CreateElement("button");
- elem->SetClass("select-button", true);
+ auto elem = doc->CreateElement("select-button");
return parent->AppendChild(std::move(elem));
}
} // namespace
SelectButton::SelectButton(Rml::Element* parent, Props props) : Component(createRoot(parent)) {
- mKeyElem = append(mRoot, "div");
- mKeyElem->SetClass("key", true);
- mValueElem = append(mRoot, "div");
- mValueElem->SetClass("value", true);
+ mKeyElem = append(mRoot, "key");
+ mValueElem = append(mRoot, "value");
update_props(std::move(props));
listen(mRoot, Rml::EventId::Click, [this](Rml::Event& event) {
if (mProps.disabled) {
diff --git a/src/dusk/ui/tab_bar.cpp b/src/dusk/ui/tab_bar.cpp
index 85bfecc803..5ae696a973 100644
--- a/src/dusk/ui/tab_bar.cpp
+++ b/src/dusk/ui/tab_bar.cpp
@@ -5,8 +5,7 @@ namespace {
Rml::Element* createRoot(Rml::Element* parent) {
auto* doc = parent->GetOwnerDocument();
- auto elem = doc->CreateElement("div");
- elem->SetClass("tab-bar", true);
+ auto elem = doc->CreateElement("tab-bar");
return parent->AppendChild(std::move(elem));
}
diff --git a/src/dusk/ui/ui.cpp b/src/dusk/ui/ui.cpp
index bbd69558a2..f531a8674b 100644
--- a/src/dusk/ui/ui.cpp
+++ b/src/dusk/ui/ui.cpp
@@ -87,8 +87,8 @@ Document* top_document() noexcept {
}
void update() noexcept {
- for (size_t i = 0; i < sDocuments.size(); ++i) {
- sDocuments[i].doc->update();
+ for (const auto& doc : sDocuments) {
+ doc.doc->update();
}
sDocuments.erase(
std::remove_if(sDocuments.begin(), sDocuments.end(),
diff --git a/src/dusk/ui/window.cpp b/src/dusk/ui/window.cpp
index 3ad4cd559b..45459517b2 100644
--- a/src/dusk/ui/window.cpp
+++ b/src/dusk/ui/window.cpp
@@ -23,17 +23,27 @@ float base_body_padding(Rml::Context* context) noexcept {
return 64.0f * dpRatio;
}
+const Rml::String kDocumentSource = R"RML(
+
+
+
+
+
+
+
+
+)RML";
+
} // namespace
-Window::Window() : Document("res/rml/window.rml"), mRoot(mDocument->GetElementById("window")) {
+Window::Window() : Document(kDocumentSource), mRoot(mDocument->GetElementById("window")) {
mTabBar = std::make_unique(mRoot, TabBar::Props{
.selectedTabIndex = 0,
.autoSelect = true,
});
- auto elem = mDocument->CreateElement("div");
+ auto elem = mDocument->CreateElement("content");
elem->SetAttribute("id", "content");
- elem->SetClass("content", true);
mContentRoot = mRoot->AppendChild(std::move(elem));
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
@@ -49,6 +59,39 @@ Window::Window() : Document("res/rml/window.rml"), mRoot(mDocument->GetElementBy
}
}
});
+
+ // Hide document after transition completion
+ listen(mRoot, Rml::EventId::Transitionend, [this](Rml::Event& event) {
+ if (event.GetTargetElement() == mRoot &&
+ *mRoot->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible &&
+ !mVisible)
+ {
+ Document::hide();
+ }
+ });
+}
+
+void Window::show() {
+ if (mVisible) {
+ return;
+ }
+
+ Document::show();
+ mRoot->SetAttribute("open", "");
+ mVisible = true;
+}
+
+void Window::hide() {
+ if (mDocument == nullptr) {
+ mVisible = false;
+ return;
+ }
+ if (!mVisible) {
+ return;
+ }
+
+ mRoot->RemoveAttribute("open");
+ mVisible = false;
}
void Window::update() {
@@ -114,7 +157,7 @@ bool Window::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 (cmd != NavCommand::Next && cmd != NavCommand::Previous && target->Closest("content")) {
if (handle_content_nav(event, cmd)) {
return true;
}
diff --git a/src/dusk/ui/window.hpp b/src/dusk/ui/window.hpp
index 4576740182..ffc69f2022 100644
--- a/src/dusk/ui/window.hpp
+++ b/src/dusk/ui/window.hpp
@@ -23,6 +23,8 @@ public:
Window(const Window&) = delete;
Window& operator=(const Window&) = delete;
+ void show() override;
+ void hide() override;
void update() override;
bool focus() override;
bool set_active_tab(int index);
@@ -47,6 +49,7 @@ protected:
std::unique_ptr mTabBar;
std::vector > mContentComponents;
Insets mBodyPadding;
+ bool mVisible = false;
};
} // namespace dusk::ui