diff --git a/res/rml/window.rcss b/res/rml/window.rcss index 28d01db8ec..6830060116 100644 --- a/res/rml/window.rcss +++ b/res/rml/window.rcss @@ -19,6 +19,9 @@ button { } .window { + display: flex; + flex-flow: column; + height: 100%; max-width: 1088dp; max-height: 768dp; margin: auto; @@ -30,8 +33,18 @@ button { background-color: rgba(21, 22, 16, 90%); } +@media (max-height: 640dp) { + body { + padding: 16dp; + } + .window { + box-shadow: none; + } +} + .window .tab-bar { display: flex; + flex: 0 0 64dp; height: 64dp; background-color: rgba(217, 217, 217, 10%); font-family: "Fira Sans Condensed"; @@ -68,7 +81,10 @@ button { .window .content { display: flex; - height: 100%; + flex: 1 1 0; + min-width: 0; + min-height: 0; + overflow: hidden; } .window .content .pane { @@ -76,30 +92,56 @@ button { flex-flow: column; flex: 1 1 0; height: 100%; + min-width: 0; + min-height: 0; padding: 24dp; + padding-bottom: 0dp; gap: 8dp; - overflow: auto; + overflow: hidden auto; } .window .content .pane:not(:last-of-type) { border-right: 1dp #92875B; } -.window .content .pane.detail-pane { - gap: 16dp; +.window .content .pane > * { + flex: 0 0 auto; } -.window .content .detail-value { - padding: 12dp 16dp; - border-radius: 12dp; - background-color: rgba(17, 16, 10, 20%); - box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp; - font-size: 20dp; +.window .content .pane > .spacer { + display: block; + /* Completes the 24dp bottom inset after the pane's 8dp gap. */ + flex: 0 0 16dp; + height: 16dp; + pointer-events: none; } -.window .content .detail-controls { - display: flex; - gap: 12dp; +scrollbarvertical { + width: 8dp; +} + +scrollbarvertical sliderarrowdec, +scrollbarvertical sliderarrowinc { + width: 0; + height: 0; +} + +scrollbarvertical slidertrack { + width: 8dp; + background-color: rgba(224, 219, 200, 5%); + border-radius: 2dp; +} + +scrollbarvertical sliderbar { + width: 8dp; + min-height: 24dp; + background-color: rgba(224, 219, 200, 45%); + border-radius: 2dp; +} + +scrollbarvertical sliderbar:hover, +scrollbarvertical sliderbar:active { + background-color: rgba(194, 164, 45, 80%); } .section-heading { @@ -109,6 +151,10 @@ button { opacity: 0.25; } +.section-heading:not(:first-of-type) { + padding-top: 12dp; +} + .button { text-align: center; background-color: rgba(17, 16, 10, 20%); diff --git a/src/dusk/ui/component.cpp b/src/dusk/ui/component.cpp index 6f7342bc1b..6435309a57 100644 --- a/src/dusk/ui/component.cpp +++ b/src/dusk/ui/component.cpp @@ -15,6 +15,12 @@ void Component::update() { bool Component::focus() { // Can we focus self? if (mRoot->Focus(true)) { + mRoot->ScrollIntoView(Rml::ScrollIntoViewOptions{ + Rml::ScrollAlignment::Center, + Rml::ScrollAlignment::Nearest, + Rml::ScrollBehavior::Smooth, + Rml::ScrollParentage::Closest, + }); return true; } // Otherwise, try to focus a child diff --git a/src/dusk/ui/pane.cpp b/src/dusk/ui/pane.cpp index 592c8f30ee..8fe05763d6 100644 --- a/src/dusk/ui/pane.cpp +++ b/src/dusk/ui/pane.cpp @@ -38,16 +38,10 @@ Pane::Pane(Rml::Element* parent, Direction direction, const Rml::String& classNa break; } } - int i = focusedChild + direction; if (focusedChild == -1) { - // If the container itself is focused and next is pressed, focus the first element - if (direction == 1) { - i = 0; - } else { - // Otherwise, allow event to bubble - return; - } + return; } + int i = focusedChild + direction; while (i >= 0 && i < static_cast(mChildren.size())) { if (mChildren[i]->focus()) { event.StopPropagation(); @@ -58,6 +52,11 @@ Pane::Pane(Rml::Element* parent, Direction direction, const Rml::String& classNa }); } +void Pane::update() { + finalize(); + Component::update(); +} + bool Pane::focus() { for (const auto& child : mChildren) { if (child->focus()) { @@ -80,8 +79,29 @@ Rml::Element* Pane::add_text(const Rml::String& text) { return elem; } -void Pane::clear() { - clear_children(); +Rml::Element* Pane::add_rml(const Rml::String& rml) { + auto* elem = append(mRoot, "div"); + elem->SetInnerRML(rml); + return elem; } -} // namespace dusk::ui \ No newline at end of file +void Pane::finalize() { + if (finalized) { + return; + } + finalized = true; + + // Append spacer element to the bottom. RmlUi does not properly handle + // 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); +} + +void Pane::clear() { + clear_children(); + finalized = false; +} + +} // namespace dusk::ui diff --git a/src/dusk/ui/pane.hpp b/src/dusk/ui/pane.hpp index 863ad1a87d..f354d6f106 100644 --- a/src/dusk/ui/pane.hpp +++ b/src/dusk/ui/pane.hpp @@ -16,6 +16,7 @@ public: explicit Pane(Rml::Element* parent, Direction direction, const Rml::String& className = "pane"); bool focus() override; + void update() override; Rml::Element* add_section(const Rml::String& text); Button& add_button(Button::Props props) { return add_child