linebender / druid

A data-first Rust-native UI design toolkit.
https://linebender.org/druid/
Apache License 2.0
9.51k stars 567 forks source link

control widgets and container alignment #582

Open cmyr opened 4 years ago

cmyr commented 4 years ago

We have a bunch of nice control widgets, but they don't play nicely together. The major issue is vertical alignment; widgets all have their own heights, and this makes them look really weird when used together.

As an illustration, here is a row of our common control widgets, laid out naively:

Screen Shot 2020-02-28 at 3 10 15 PM

There are various things going on here:

This stuff is a bit tricky. The easy one is the interior h-padding; I think we can just say that widgets shouldn't do that.

The alignment stuff is tricky, given our layout model. The basic problem is that in the current implementation of Flex, we do a single pass, measuring each widget, and then laying it out immediately. This means that we do not know our own final size when laying out widgets, so we can't do things like center widgets vertically in the container.

One option we would have is to have a canonical 'control height', which would be the declared height of all control widgets, and they could handle centering themselves.

Another option would be to have a ControlGroup widget that would know the default control height, would size itself to that height, and then center or otherwise align all children in that space; this feels hacky.

A third option is to allow the user to specify an alignment for a row/column. This would make layout more expensive; we would need to do two passes at layout, one to get sizes and then one to resolve position.

This maybe needs more research. SwiftUI has alignment guides which seem interesting, but I don't know anything about the implementation.

Baseline alignment is going to be an additional challenge, because we will need to find some way of getting that information from widgets.

futurepaul commented 4 years ago
sized_box

Fwiw, the widgets were designed to center vertically, but can only center vertically if given a height to center themselves within:

    Flex::row()
        .with_child(textbox, 0.0)
        .with_child(checkbox, 0.0)
        .with_child(slider, 0.0)
        .with_child(progress_bar, 0.0)
        .with_child(stepper, 0.0)
        .with_child(switch, 0.0)
        .with_child(button, 0.0)
        .with_child(label, 0.0)
        .fix_height(25.0)
        .center()

Maybe I'm misunderstanding?

cmyr commented 4 years ago

my desire (and this is implemented in #583) is that we be able to specify the alignment of widgets when they are smaller than the container; that is, a row takes on the height of the tallest of its children; but when another child is smaller than this, how do we align those widgets within the container? currently we just align them with the top, but we should be able to specify that.

edit: your example looks good, but it has the problem that you need to know the height up-front, which might not always be possible?

PoignardAzur commented 3 years ago

I think this might deserve a bump, so to speak. Alignment problems and the UI elements looking bespoke is a non-trivial paint point when I'm writing druid UIs.

It just... looks unprofessional, you know? Super unsatisfying when you're iterating on them.

cmyr commented 3 years ago

So there is now baseline alignment of widgets; the baseline for built-in controls that don't contain text should be some position such that they look harmonious. This is really just trial and error, and anyone is welcome to play around!

black7375 commented 2 years ago

I think it can refer to the CSS vertical-align. https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align