Lemur component help

Imgur

I’m making a custom component, but the “<” and “>” symbols should be centered (click on the image to view them). What am I missing?

import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import static com.pesegato.p8s.appstates.MainMenuAppState2.SMALL_AMETHYST;
import com.simsilica.lemur.ActionButton;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.CallMethodAction;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.component.DynamicInsetsComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import com.simsilica.lemur.style.ElementId;

public class ASlider extends Node {

    ActionButton decrease;
    ActionButton increase;
    Label center;

    PurpleWrapper pe;
    String label;

    public ASlider(String label, PurpleWrapper pe) {
        this.pe = pe;
        this.label = label;
        Container row = new Container(new SpringGridLayout(Axis.X, Axis.Y));
        row.setPreferredSize(new Vector3f(500, SMALL_AMETHYST, 0));

        decrease = new ActionButton(new CallMethodAction("<", this, "decrease"), new ElementId("circle.button"));
        decrease.setPreferredSize(new Vector3f(SMALL_AMETHYST, SMALL_AMETHYST, 0));
        decrease.setLocalTranslation(0, 0, 0);
        row.addChild(decrease);
        center = new Label(label + pe.getValue(), new ElementId("mini.label"));
        center.setPreferredSize(new Vector3f(350, SMALL_AMETHYST, 0));
        center.setInsetsComponent(new DynamicInsetsComponent(0.5f, 0, 0.5f, 0));
        center.setLocalTranslation(100, 0, 0);
        row.addChild(center);
        increase = new ActionButton(new CallMethodAction(">", this, "increase"), new ElementId("circle.button"));
        increase.setPreferredSize(new Vector3f(SMALL_AMETHYST, SMALL_AMETHYST, 0));
        increase.setLocalTranslation(500, 0, 0);
        row.addChild(increase);
        attachChild(row);
    }

    public ActionButton getDecreaseButton() {
        return decrease;
    }

    public ActionButton getIncreaseButton() {
        return increase;
    }

    public void decrease() {
        pe.decrease();
        center.setText(label + pe.getValue());
    }

    public void increase() {
        pe.increase();
        center.setText(label + pe.getValue());
    }
}

The style is on pastebin

https://pastebin.com/56pcdqi3

It’s weird because it’s acting like it’s losing its vertical alignment setting somehow.

The first thing I would try is printing out the VAlignment after creation to see if it’s still center.

(Also note that the things like decrease.setLocalTranslation() should have no effect because the layout will override them… not related to your problem, though.)

    System.out.println("VAlignment "+decrease.getTextVAlignment());

VAlignment Center
Both after creation and after pressing the decrease button

Super weird.

I don’t have time today but I will try to create a test case in the next couple of days and add it to the lemur examples… just to see if I can duplicate/fix the issue.

2 Likes

I created a demo in the Lemur examples/demo that tries all of the different text alignments.

I wasn’t able to reproduce the issue but perhaps this gives us the tools to start closing the gap between why mine works and yours doesn’t.

Edit: and the interesting thing is that the default behavior is “top”… so the fact that yours is on the bottom indicates something. Not sure what… but it indicates “something”. :slight_smile: For example, maybe the button is really twice as tall as it looks for some reason.

1 Like
    System.out.println("VAlignment "+decrease.getTextVAlignment());
    System.out.println("Size "+decrease.getSize().x+" "+decrease.getSize().y);
    System.out.println("Preferred size "+decrease.getPreferredSize().x+" "+decrease.getPreferredSize().x);
    System.out.println("Bounding Volume "+decrease.getWorldBound().getVolume());

Yelds:

VAlignment Center
Size 0.0 0.0
Preferred size 49.0 49.0
Bounding Volume 0.0

Note: don’t leave the z component out because it’s important, too. Lemur components have a Z-size and it relates to how their internal layers are drawn. May not be an issue here but it’s still important information.

The sizes we’re interested in are after it’s been laid out, though. I think you are printing the sizes right after creation. Have to wait to ask until they are added to the scene.

        System.out.println("VAlignment "+decrease.getTextVAlignment());
        System.out.println("Size "+decrease.getSize().x+" "+decrease.getSize().y+" "+decrease.getSize().z);
        System.out.println("Preferred size "+decrease.getPreferredSize().x+" "+decrease.getPreferredSize().y+" "+decrease.getPreferredSize().z);
        System.out.println("Bounding Volume "+decrease.getWorldBound().getVolume());

On creation

VAlignment Center
Size 0.0 0.0 0.0
Preferred size 49.0 49.0 0.0
Bounding Volume 0.0

When I click the button:

VAlignment Center
Size 66.333336 49.0 0.0
Preferred size 49.0 49.0 0.0
Bounding Volume 328.63492

Just in case, can you also add:
System.out.println(“text[” + decrease.getText() + “]”);

…to make sure there aren’t any extra line feeds or something in the text.

        System.out.println("Pressed button \"decrease\"");
        System.out.println("text[" + decrease.getText() + "]");
        System.out.println("VAlignment "+decrease.getTextVAlignment());
        System.out.println("Size "+decrease.getSize().x+" "+decrease.getSize().y+" "+decrease.getSize().z);
        System.out.println("Preferred size "+decrease.getPreferredSize().x+" "+decrease.getPreferredSize().y+" "+decrease.getPreferredSize().z);
        System.out.println("Bounding Volume "+decrease.getWorldBound().getVolume());
text[<]
VAlignment Center
Size 0.0 0.0 0.0
Preferred size 49.0 49.0 0.0
Bounding Volume 0.0
Pressed button "decrease"
text[<]
VAlignment Center
Size 66.333336 49.0 0.0
Preferred size 49.0 49.0 0.0
Bounding Volume 328.63492

Boo.

Since I’ve been unable to duplicate this locally, do you suppose it’s possible for you to put together a small test case that illustrates the issue?

The self contained application: https://pastebin.com/rUnbAbma

The groovy style: https://pastebin.com/iGcj33EW

Let me know if you need other stuff. Thanks! :slight_smile:

Probably I will need the images and stuff, too, I guess. Didn’t see them if they are there.

Here you go

So I finally got time to copy this into a project, setup a build, fix the missing class errors, etc…

It turns out the issue is that the text wants to be height=0 because the background has no size left for the text itself. This is most easily demonstrated by switching the background to something else.

And from the style:

def defCircleSmallPink = TbtQuadBackgroundComponent.create(
    texture( name:"Interface/ui-circle-pink.png",
        generateMips:false ),
    1f, 24, 24, 24, 24,
    1f, false);

Given that the border is 24 all around, there is no space left for the text. The default margin for a TbtQuadBackgroundComponent is the x1, y1 values… so 24x24 in this case.

Setting the margin’s y value to something more reasonable fixes the issue… as does letting the components calculate their own preferred size.

But for example:

def defCircleSmallPink = TbtQuadBackgroundComponent.create(
    texture( name:"Interface/ui-circle-pink.png",
        generateMips:false ),
    1f, 24, 24, 24, 24,
    1f, false);
defCircleSmallPink.setMargin(12, 2);

…is probably a more reasonable margin for something with rounded corners.

I will give some advice:
Where possible, don’t force the size calculation. In the long run, it’s better to setup the container hierarchy and layout such that you only have to force size on the root. a) your layout will be more adaptable, b) these sorts of margin issues will be easier to spot because things will be sized weird. (For example, removing all of the setPreferredSize() calls from your MySlider class causes the up/down buttons to get really tall… but otherwise the screen layout is not so bad.)

I’m also bugged by all of the cloning in the action handlers… but neither can I offer a good (and easy) alternative yet.

1 Like

I love it when I track something down like this and discover a big giant “FIXME” in the code. lol. Thanks, past-me. (Should probably put tracking “TODO” and “FIXME” comments down on my to-do list.)

Thanks for the help but sorry, a lot of things that are obvious to you aren’t obvious to me. Here’s what I did after reading your answer.

So I did (first attempt)

def defCircleSmallPink = TbtQuadBackgroundComponent.create(
    texture( name:"Interface/ui-circle-pink.png",
        generateMips:false ),
    1f, 24, 0, 24, 24,
    1f, false);

Didn’t fix the issue.

So I did comment (second attempt)

    //decrease.setPreferredSize(new Vector3f(SMALL_AMETHYST, SMALL_AMETHYST, 0));

Didn’t fix the issue

So I did

def defCircleSmallPink = TbtQuadBackgroundComponent.create(
    texture( name:"Interface/ui-circle-pink.png",
        generateMips:false ),
    1f, 24, 24, 24, 24,
    1f, false);
defCircleSmallPink.setMargin(12, 2);

Didn’t work either.
Made further attempt by mixing and matching the above. Still no luck. :frowning:

Your first attempt will mess up your stretching.

You have to clear out ALL of the preferred size setting in MySlider… else something will still force them all to be too small.

But the real solution is to set margin properly.

You need to do the setMargin() thing with all of the circle backgrounds… but especially the black one as that’s the default one for your button. If you only set the pink one then it won’t fix the issue.

In case it’s helpful, some background. The javadoc for the TBT stuff talks about what the x1, y1, x2, y2 values are (24, 24, 24, 24 in your original create calls)
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/component/TbtQuadBackgroundComponent.html

But it also uses x1, y1 as the default margin for the component. The margin is what determines how much extra space should be given to the background around whatever is on top of it.

From: https://github.com/jMonkeyEngine-Contributions/lemur/wiki/GUI-Components#component-layout

So if the height is forced to y=49 and the margin is y=24 * 2… there would only be 1 pixel left to render text. In fact, something else adds at least one pixel (probably the text shadows) and so you end up with y=0 pixels left for the text. This passes a text rectangle of size y=0 to BitmapText and BitmapText doesn’t deal with it very well.

Edit: P.S.: I meant to say before that your button graphics look really nice.

Many thanks for the in-depth explanation, solution, and compliments! Will forward them to the real author :wink:

EDIT: However, I noticed a strange behavior with click. The buttons are supposed to look:

  • black with pink text (standard)
  • white with black text (mouse over)
  • pink with black text (mouse pressed)

But if I click the decrease button, and then the mouse exit, the background turn black but the text remain black.

I think that since focusColor = black, then after the button loses the focus, the color should revert to the default… wrong?

Probably highlight off gets called?

An issue with using separate action handlers for every individual state is that order becomes important… versus having one action handler that sets the background based on the current state of the button.

Edit: wait… I guess you are using the Lemur built-in text coloring so my comment is meaningless.

Edit2: you are using black as the focus color. “Focus” in this case is about keyboard/joystick navigation and means that if the user presses the space bar it will click the button. So even though your mouse moved away. the button still has focus and so its text is black.