mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-09 12:37:18 -04:00
Window animations & tags instead of classes
This commit is contained in:
Vendored
+1
-1
Submodule extern/aurora updated: 1bd972429e...285c11a13c
+10
-10
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<rml>
|
||||
<head>
|
||||
<title>Popup</title>
|
||||
<link type="text/rcss" href="popup.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="popup" class="popup popup-hidden"></div>
|
||||
</body>
|
||||
</rml>
|
||||
+42
-34
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<rml>
|
||||
<head>
|
||||
<title>Window</title>
|
||||
<link type="text/rcss" href="window.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="window" class="window"></div>
|
||||
</body>
|
||||
</rml>
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+17
-3
@@ -11,8 +11,22 @@
|
||||
#include <chrono>
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
|
||||
Popup::Popup() : Document("res/rml/popup.rml"), mRoot(mDocument->GetElementById("popup")) {
|
||||
const Rml::String kDocumentSource = R"RML(
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="res/rml/popup.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<popup id="popup"></div>
|
||||
</body>
|
||||
</rml>
|
||||
)RML";
|
||||
|
||||
}
|
||||
|
||||
Popup::Popup() : Document(kDocumentSource), mRoot(mDocument->GetElementById("popup")) {
|
||||
mTabBar = std::make_unique<TabBar>(mRoot, TabBar::Props{.autoSelect = false});
|
||||
mTabBar->add_tab("Settings", [] { push_document(std::make_unique<SettingsWindow>()); });
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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(),
|
||||
|
||||
+47
-4
@@ -23,17 +23,27 @@ float base_body_padding(Rml::Context* context) noexcept {
|
||||
return 64.0f * dpRatio;
|
||||
}
|
||||
|
||||
const Rml::String kDocumentSource = R"RML(
|
||||
<rml>
|
||||
<head>
|
||||
<link type="text/rcss" href="res/rml/window.rcss" />
|
||||
</head>
|
||||
<body>
|
||||
<window id="window"></window>
|
||||
</body>
|
||||
</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<TabBar>(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;
|
||||
}
|
||||
|
||||
@@ -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<TabBar> mTabBar;
|
||||
std::vector<std::unique_ptr<Component> > mContentComponents;
|
||||
Insets mBodyPadding;
|
||||
bool mVisible = false;
|
||||
};
|
||||
|
||||
} // namespace dusk::ui
|
||||
|
||||
Reference in New Issue
Block a user