Lemur Text on Image

Hey Guys,
So far I had success in using a Label in Combination with setIcon() to display images.
Now I wanted to add a number on top of that image (it shows how often that (de-)buff has stacked).

When I, however, set the Text for that Label, the Image is to the left and the text to the right.
After reading the wiki I tried to set it as Background and even as Border however I got the same result.

Can anyone give me a hint on what to do?

Have you tried:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/Label.html#setTextHAlignment(com.simsilica.lemur.HAlignment)

And:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/Label.html#setTextVAlignment(com.simsilica.lemur.VAlignment)

Edit: Also check:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/component/IconComponent.html#setOverlay(boolean)

Edit 2: and note that IconComponent also has V and H alignment properties.

Step 1: Make a container the size of your image.
Step 2: Add the image as the container background iconcomponent
Step 3: Attach label to container.

I think no other way (except going back to jme nodes) will let you place an element on top of something else in the lemur layout.

GuiComponents are always stacked within a GUI element, ie: they overlay. IconComponent is a special component that does’t do that… because it’s meant to be the icon for a label, usually to one side or the other.

Otherwise, simply using a regular QuadBackgroundComponent with an image texture would perfectly “underlay” the text… but then you are left to size the GUI element properly yourself.

This is why IconComponent supports the overlay option. It lets it behave more like a regular background but still have its automatic ‘size of image’ functionality.

Initially I tried the setV/HAlignment, but it did not change anything (I set them to CENTER).
setOverlay does the trick, however then I have the problem, that the outer container with a SpringGridLayout is also overlaying the individual sub-containers which each consists of a progressBar and that Icon-Label.

Did I somehow misuse the SpringGridLayout? (The FillModes were a bit confusing, I used FIllMode.None, since I wanted them to “stack” (fill up a row, like a FlowLayout)).

It’s hard for me to comment as the information provided is leaving too much for me to construct in my head as to what your code might actually look like.

FillMode.None is fine… but recognize that if you don’t give your container enough size then I guess the items may just stack on top of each other. It means what you want it to mean, though.

I would first test a button on its own with the icon and text like you want. Separate it from any layout issues that may or may not be related.

I’ve now tested it with only one Label. The problem is that the “bounding box” of the Label is just as big as the text it contains. The Icon however is bigger, but that doesn’t affect layout.

The relevant code would be:

@Override
    protected Container addObject(Entity e) {
        final BuffComponent bc = e.get(BuffComponent.class);
        final Container cont = buildInnerContainer(e, bc);
        final Container outerContainer;
        Node n = parentContainer.getObject(bc.getTarget()); 
        
        if (n.getChild("OuterContainer") != null) {
            outerContainer = (Container)n.getChild("OuterContainer"); // OuterContainer already there
        } else {
            outerContainer = new Container(new SpringGridLayout(Axis.X, Axis.Y, FillMode.None, FillMode.None), "glass");
            outerContainer.setName("OuterContainer");
            outerContainer.setLocalScale(0.008f);
            outerContainer.setLocalTranslation(-0.50f, -0.1f + 0.4f, 0);
        }
        
        if (outerContainer != null) { // add buff to bufflist
            Main.self.enqueue(() -> outerContainer.addChild(cont));
        }
        return cont;
    }

     protected Container buildInnerContainer(Entity e, BuffComponent bc) {
        final Label img = new Label("1"); // Label seems to be the best way for images?!
        final IconComponent icon = new IconComponent("Interface/Icons/bleeding-wound.png");
        final Container cont = new Container(new BorderLayout(), "glass");
        
        icon.setIconScale(0.05f);
        icon.setOverlay(true);
        img.setIcon(icon);
        //img.setBorder(icon);
        img.setTextHAlignment(HAlignment.Center);
        img.setTextVAlignment(VAlignment.Center);
        img.setName("ImageLabel"); // Does both: The StackCount and the Background Image
        cont.addChild(img);
        
        if (bc.getBuffDuration() >= 0f) {
            final ProgressBar progressBar = new ProgressBar("glass");
            final Decay d = e.get(Decay.class);
            
            progressBar.setName("BuffDuration");           
            setColor(progressBar, (bc.isDebuff() ? ColorRGBA.Red : ColorRGBA.Green));
            progressBar.setModel(new DefaultRangedValueModel(0, bc.getBuffDuration(), d.getTimeToLive()));
            //progressBar.setLocalScale(0.01f);
            progressBar.setPreferredSize(new Vector3f(img.getSize().x, 5f, 1f));        
            progressBar.setLocalTranslation(-0.5f, 0f, 0f);
            cont.addChild(progressBar, BorderLayout.Position.South);
        }
        
        cont.setLocalTranslation(0f, 0.1f + 2f * cont.getSize().y, 0f);
        return cont;
    }

That may be a bug.

To be honest, the overlay=true option is not tested much because 9 times out of 10 in those cases I would just use a regular non-icon background component.

I guess when overlay = true then the icon should still contribute to the preferred size of the GUI element… but just in a max() sort of way. So the bug is here, I guess:

Edit: note that you could hack around this by setting the preferred size of your label/button whatever. That will override the calculation.

Is this in any way difficult to achieve? I was just going for an IconComponent because a hub post told me “Use a Label along with an IconComponent to display images” and that I know that the TbtQuadComponent is a bit more difficult.

So I could just use a regular QuadComponent for the Background of my Label and then the only “problem” I have is that the component is stretching the image without caring about the actual image resolution?

Yep. That’s right.

The only real thing IconComponent adds is that (by default) it wants to put the image beside the underlying layers and that it auto-sizes based on the actual image size. The non-default way seems to be broken at the moment though it’s not particularly hard to fix, either.

Now how can I set a size to (e.g. a Label)?
I tried using #setSize() however that seems to be overridden by the size the text of the label takes?
I have this Problem no matter if I scale the Label directly or the Container containing it.

Ideally I’d set the Label Size and then have the container adjust to it.
The only thing I saw was that the size could affect how the background was stretched actually

As in…

http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/Panel.html#setPreferredSize(com.jme3.math.Vector3f)

It turns out sometimes proper reading IS a skill :smiley:
I’ve mistaken that for “setting the desired size”, but I’m happy it works now :slight_smile:
Thanks for your time guys!

May I ask, @pspeed - is your pattern replicated from anything specific? I see a lot of AWT type behaviour but I’m not very well versed in java GUI’s.

It’s kind of “swing with the nastiness removed” in a sense… but it resembles a lot of GUI libraries on some level. Swing is where I took my inspiration, though… I just made the API more “fluent”. (FluentInterface)

1 Like