threerings / tripleplay

Utilities for use in PlayN-based games.
Other
92 stars 32 forks source link

Fixed-size element background rendering only up to child bounds #53

Closed doctor-g closed 9 years ago

doctor-g commented 9 years ago

Given an element with the fixed-size constraint, when placed into an absolute layout, it will only render its background up to the positions of child elements. If there are no children, the element is not rendered at all. For example, this screen remains black:


public class TestScreen extends ScreenStack.UIScreen {
    @Override
    protected Root createRoot() {
        Root root = iface.createRoot(new AbsoluteLayout(), SimpleStyles.newSheet(game().plat.graphics()));
        Group group = new Group(new AbsoluteLayout())
                .setConstraint(Constraints.fixedSize(300, 200))
                .setStyles(Style.BACKGROUND.is(Background.solid(Colors.WHITE)));
        root.add(AbsoluteLayout.at(group, 10, 10));
        return root;
    }

    @Override
    public Game game() {
        return SimGame.game;
    }
}

Putting a label into the group makes it so that the white background is only rendered up to the label's bounds:

public class TestScreen extends ScreenStack.UIScreen {
    @Override
    protected Root createRoot() {
        Root root = iface.createRoot(new AbsoluteLayout(), SimpleStyles.newSheet(game().plat.graphics()));
        Group group = new Group(new AbsoluteLayout())
                .setConstraint(Constraints.fixedSize(300, 200))
                .setStyles(Style.BACKGROUND.is(Background.solid(Colors.WHITE)))
                .add(AbsoluteLayout.at(new Label("Hello, world"), 50, 50));
        root.add(AbsoluteLayout.at(group, 10, 10));
        return root;
    }

    @Override
    public Game game() {
        return SimGame.game;
    }
}

This is what it shows, verified in LWJGL and HTML backends: image

jamie-sparked commented 9 years ago

If I recall correctly, Constraints factory methods only apply to the builtin text elements, and are not applied to other elements like Group universally. The best things to use in this situation is a SizableGroup:

        Group group = new Group(new AbsoluteLayout(), new Dimension(300, 200));

It would be cool if Constraints.at and such were somehow applied globally, but that would be quite a lot of work. Should at least be a comment saying what they do apply to.

doctor-g commented 9 years ago

Ah, it was definitely not clear that Constraints could not be used in this way. It would be helpful to either have a comment in place, or to either log a warning or prevent the call using the type system---although a comment is clearly easiest! In reading the API, I had not seen SizableGroup, but you're right: it worked like a charm (replacing the Group constructor in your example with SizableGroup, natch).

Thanks for your help. Issue resolved.

samskivert commented 9 years ago

The Constraint mechanism does in fact apply to all elements and is used by all Layout implementations. The problem here is that constraints cannot be composed. AbsoluteLayout uses a Constraint to capture the at information, which overwrites any previous Constraints.fixedSize constraint that was configured on the element.

While Jamie's SizableGroup suggestion certainly works, the intent with AbsoluteLayout is for you to use its built-in mechanism for specifying position and size:

        Group group = new Group(new AbsoluteLayout())
                .setStyles(Style.BACKGROUND.is(Background.solid(Colors.WHITE)))
                .add(AbsoluteLayout.at(new Label("Hello, world"), 50, 50));
        root.add(AbsoluteLayout.at(group, 10, 10, 300, 200));
samskivert commented 9 years ago

We should probably emit a warning when a constraint is overwritten by another constraint. Or perhaps throw an exception (though that would be a nasty surprise for anyone with code that benignly ran afoul of this restriction).