How to make a centered label with Icon?

It sounds like you’ve made your own Button… not sure why.

Edit: note that it is quite likely that a Button will already do what you want to do. It will certainly do everything in your list.

Indeed it is, except for that it wants to do some stuff I don’t need (like layout), and documentation on tweaking its look, etc. is a bit… unwelcoming.

So I grabbed a Label+icon which is the simplest component that gives me what I need, and rolled out myself the rest.

??? re: layout, it’s just a Label with clickability.

Except it doesn’t.

What is it that you needed to tweak?

Tried to swap Label with Button.

-same wrong layout as before
-now the text highlights in wrong colors, and only when I’m inside the red box (as opposed from when I’m inside the background quads)

…so problem unsolved, and another problem added. :frowning:

I’ll need to see the code.

If the background quads are part of the button then they should get the mouse enter/exit and set the highlighting, etc. for anything over the background. That’s how they’re supposed to work.

If they aren’t part of the button then we haven’t actually fixed anything because the buttons still aren’t in a container as suggested. So it won’t be a surprise that they are still only as big as the red box (since that’s the only thing sizing the button) and that the mouse only works over the red box (since that’s the only thing sizing the button).

Enjoy(?)

https://pastebin.com/1qVJ5K8q

Yeah, so when you’ve attached the label, it isn’t really attached… so the setSize() will get overridden later.

What is it that your button is doing that the regular Button won’t do? Because then you could just pop them all into one container:
Container menu = new Container();
menu.addChild(button1);
menu.addChild(button2);
menu.addChild(button3);

etc. and be done with it. Set the container how big you want it and everything will size and layout appropriately.

How can I hook in my code for customizing the look?

You mean for highlighting? You can do whatever you want for a variety of events:

http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/Button.html#addCommands(com.simsilica.lemur.Button.ButtonAction,%20com.simsilica.lemur.Command...)

Click
Down
FocusGained
FocusLost
HighlightOff
HighlightOn
Hover
Up

Also if you need more layers for something that’s pretty easy, too.

Lemur built in GUI element are basically thin wrappers over the GuiControl anyway. They setup standard layers and the order for those layers but it’s easy to add more layers, etc.

A step backward please. How do I customize the look when “doing nothing”? And being enabled/disabled?

Then I’ll get to input event…

If you copy the glass-styles.groovy file into an identically name folder setup in your src, you can edit that file and when you

BaseStyles.loadGlassStyle();

Your stuff will be loaded instead.

It might help me to know how you want to customize the look. Like, change colors, switch backgrounds, animate something, or?

Edit: and note re: mitm’s comment… it’s easy to create your own non-glass style and use that instead also. But if for some reason you can’t/don’t want to use the styles files, note: that anything you can do there can also be done to setup a style in code… and anything a style is doing can be done directly to the GUI elements also. One feature is built on the other and so on.

Just being clear for reference here in case someone runs across this thread…

I think if someone is not just modifying the glass style then it would be better to create your own new style. Like, myCustomStyle.groovy and put that on the classpath somewhere. Then instead of BaseStyles.loadGlassStyle() call:
BaseStyles.loadStyleResources(“myCustomStyle.groovy”);

…and if you want that to be the default style then set that instead of glass as the default style.

Note also: just making tweaks to the existing glass style can be done by creating a new com/simsilica/lemur/style/base/glass-styles.groovy in your project and adding to it. All of the style files of a particular name that are found on the classpath are loaded. So the local version will “enhance” what is already in Lemur’s jars. (That’s also how Lemur-proto extends the glass style for its own GUI elements.)

I doubt this will be meaningful but I took an interest so piddled around and maybe it can help.

package mygame;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.component.DynamicInsetsComponent;
import com.simsilica.lemur.component.IconComponent;
import com.simsilica.lemur.component.TbtQuadBackgroundComponent;

/**
 *
 * @author mitm
 */
public class CenteLabelState extends BaseAppState {
    
    @Override
    protected void initialize(Application app) {
        //It is technically safe to do all initialization and cleanup in the 
        //onEnable()/onDisable() methods. Choosing to use initialize() and 
        //cleanup() for this is a matter of performance specifics for the 
        //implementor.
        //TODO: initialize your AppState, e.g. attach spatials to rootNode
    }

    @Override
    protected void cleanup(Application app) {
        
    }

    //onEnable()/onDisable() can be used for managing things that should 
    //only exist while the state is enabled. Prime examples would be scene 
    //graph attachment or input listener attachment.
    @Override
    protected void onEnable() {
        
        Container c = new Container();
        c.setPreferredSize(new Vector3f(200, 364, 0));
        
        //Centered label using DynamicInsetsComponent. Text left (default), 
        //icon right. Set border to background, set background to 
        //DynamicInsetsComponent.
        Label labelCampMode = c.addChild(new Label("Campain Mode"));
        labelCampMode.setBorder(labelCampMode.getBackground());
        labelCampMode.setBackground(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        labelCampMode.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) labelCampMode.getIcon()).setHAlignment(HAlignment.Right);
        
        Label labelInstAct = c.addChild(new Label("Instant Action"));
        labelInstAct.setBorder(labelInstAct.getBackground());
        labelInstAct.setBackground(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        labelInstAct.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) labelInstAct.getIcon()).setHAlignment(HAlignment.Right);
        
        //Using text left (default), icon right, set the border to the background, 
        //background to DynamicInsetsComponent to center. Uses setPreferredSize 
        //of container to stretch the button. Text and component always center evenly.
        Button butCampMode_1 = c.addChild(new Button("Campain Mode"));
        butCampMode_1.setBorder(butCampMode_1.getBackground());
        butCampMode_1.setBackground(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butCampMode_1.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butCampMode_1.getIcon()).setHAlignment(HAlignment.Right);
        
        Button butInstAct_1 = c.addChild(new Button("Instant Action"));
        butInstAct_1.setBorder(butInstAct_1.getBackground());
        butInstAct_1.setBackground(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butInstAct_1.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butInstAct_1.getIcon()).setHAlignment(HAlignment.Right);
        
        Button butBoss_1 = c.addChild(new Button("Boss Mode"));
        butBoss_1.setBorder(butBoss_1.getBackground());
        butBoss_1.setBackground(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butBoss_1.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butBoss_1.getIcon()).setHAlignment(HAlignment.Right);
        
        //Text left (default), icon right. Set insetsComponet to 
        //DynamicInsetsComponent. Button sized based off componet contents.
        Button butCampMode_2 = c.addChild(new Button("Campain Mode"));
        butCampMode_2.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        butCampMode_2.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        ((IconComponent) butCampMode_2.getIcon()).setHAlignment(HAlignment.Right);
        
        Button butInstAct_2 = c.addChild(new Button("Instant Action"));
        butInstAct_2.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        butInstAct_2.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        ((IconComponent) butInstAct_2.getIcon()).setHAlignment(HAlignment.Right);
        
        Button butBoss_2 = c.addChild(new Button("Boss Mode"));
        butBoss_2.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        butBoss_2.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        ((IconComponent) butBoss_2.getIcon()).setHAlignment(HAlignment.Right);
        
        //Using centered text, icon right, adjusting the margin of text and 
        //offsetting the icon to the left. Text is already offset at creation by 
        //icon width. Not perfect but close. Using the containers preferred size 
        //to stretch buttons.    
        Button butCampMode_3 = c.addChild(new Button("Campain Mode"));
        butCampMode_3.setTextHAlignment(HAlignment.Center);
        //Push the edges of button out.
        ((TbtQuadBackgroundComponent) butCampMode_3.getBackground()).setMargin(5, 0);
        butCampMode_3.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butCampMode_3.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butCampMode_3.getIcon()).setOffset(new Vector3f(-40, 0, 0));
        
        Button butInstAct_3 = c.addChild(new Button("Instant Action"));
        butInstAct_3.setTextHAlignment(HAlignment.Center);
        ((TbtQuadBackgroundComponent) butInstAct_3.getBackground()).setMargin(5, 0);
        butInstAct_3.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butInstAct_3.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butInstAct_3.getIcon()).setOffset(new Vector3f(-40, 0, 0));
        
        Button butBoss_3 = c.addChild(new Button("Boss Mode"));
        butBoss_3.setTextHAlignment(HAlignment.Center);
        ((TbtQuadBackgroundComponent) butBoss_3.getBackground()).setMargin(5, 0);
        butBoss_3.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butBoss_3.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butBoss_3.getIcon()).setOffset(new Vector3f(-40, 0, 0));

   
        //Using text left (default), icon right, and DynamicInsetsComponent to center.
        //use setPreferredSize to size the buttons. Text will align to left neatly.
        Button butCampMode_4 = c.addChild(new Button("Campain Mode"));
        butCampMode_4.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butCampMode_4.setPreferredSize(new Vector3f(150, 20, 0));
        ((TbtQuadBackgroundComponent) butCampMode_4.getBackground()).setMargin(20, 0);
        butCampMode_4.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butCampMode_4.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butCampMode_4.getIcon()).setOffset(new Vector3f(-4, 0, 0));
        
        Button butInstAct_4 = c.addChild(new Button("Instant Action"));
        butInstAct_4.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butInstAct_4.setPreferredSize(new Vector3f(150, 20, 0));
        ((TbtQuadBackgroundComponent) butInstAct_4.getBackground()).setMargin(20, 0);
        butInstAct_4.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butInstAct_4.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butInstAct_4.getIcon()).setOffset(new Vector3f(-4, 0, 0));
        
        Button butBoss_4 = c.addChild(new Button("Boss Mode"));
        butBoss_4.setInsetsComponent(new DynamicInsetsComponent(.5f, .5f, .5f, .5f));
        butBoss_4.setPreferredSize(new Vector3f(150, 20, 0));
        ((TbtQuadBackgroundComponent) butBoss_4.getBackground()).setMargin(20, 0);
        butBoss_4.setIcon(new IconComponent("Interface/icons/SmartMonkey16.png"));
        ((IconComponent) butBoss_4.getIcon()).setHAlignment(HAlignment.Right);
        ((IconComponent) butBoss_4.getIcon()).setOffset(new Vector3f(-4, 0, 0));
        
        centerComp(c);
        ((SimpleApplication) getApplication()).getGuiNode().attachChild(c);

    }
    
    /**
     * Centers any lemur component to the middle of the screen.
     * 
     * @param panel the lemur component to center.
     */
    public void centerComp(Panel panel) {
        // Position the panel                                                            
        panel.setLocalTranslation((getApplication().getCamera().getWidth() - panel.getPreferredSize().x)/2, 
                (getApplication().getCamera().getHeight() + panel.getPreferredSize().y)/2, 0);
    }

    @Override
    protected void onDisable() {
        //Called when the state was previously enabled but is now disabled 
        //either because setEnabled(false) was called or the state is being 
        //cleaned up.
    }
    
    @Override
    public void update(float tpf) {
        //TODO: implement behavior during runtime
    }
    
}

What I was describing earlier, you can swap the background to the border component and use the dynamic insets as the background. In properly sized container, it should give you the same effect as what you have in your second-to-last block where the buttons will stretch automatically but so will the background image.

button.setBorder(button.getBackground());
button.setBackground(new DynamicInsetsComponent(0.5f, 0.5f, 0.5f, 0.5f));
…or whatever.

That’s real sweet. I redid the code and moved your examples to the top.

It looks like I need to replace the QuadBackgroundComponent with “my” background, which is:

-a quad on the left, fixed size
-a quad on the right, fixed size
-a stretched quad on center, which elongates to match the intended size.

Should not possible to stretch vertically, but I guess that’s on the shoulder of the game developer.

Where do I start? How can I make the above without making it conflict with Lemur?
I also suppose that I should have no border.

Could you use the existing TbtQuadBackgroundComponent for this or must the images actually be separate?

Just make your own component implementation and your stuff will work seamlessly. But hopefully the TbtQuadBackgroundComponent works for you and you don’t have to worry about it. It’s basically a “9 patch” implementation of a component:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/component/TbtQuadBackgroundComponent.html

Didn’t know this thing existed, looks nice, will try it

Note: more expanded documentation on the TbtQuadBackgroundComponent here:

Thanks, but some parameter are left to personal interpretation

TbtQuad(float width, float height, int x1, int y1, int x2, int y2, int imageWidth, int imageHeight, float imageScale) 
// whattiz thad? ^^         ^^^^                                         ^^^^^^          ^^^^^

    label.setBackground(new TbtQuadBackgroundComponent(new TbtQuad(150, 68, 50, 0, 100, 68, 150, 68, 1),GameGlobals.assetManager.loadTexture("Interface/ui-menu-button.png")));

Almost there though