[Solved] Rotate button background

I want to rotate an lemur button on its center (to make a picture rotate).
The button is inside a Container.

If I do like that:

Button.rotate 

It is rotating around its left up corner.
I would like the rotation around the center of the button.

My aim is that on runtime I have a button with a rotating (circle) image e.g. if server connection is down.

Any idea how to move the center of the rotation into the center of the button?

Add it to a node, center it in the node and rotate the node.

I thought about that solution too…
And thats the tricky part. It is already in a gui. And if I understand lemur, the button and the graphic are child elements or a composite of elements. So I am not sure if I can put them to a new node without consequences. If I move e.g. the background it will be above the other parts of the button.

If there is a solution to reset the center of the rotation that would help.
Otherwise I will need to somehow work around that by adding a new node and attaching the whole button to it.

I think you’ll have to make a custom button that does the same as the normal button except centers the icon in a parent.

Or translate it and rotate it at the same time… though I suspect errors may creep in.

I wanted to create a set of tweens that would do things like shrink-expand or rotate around the center. The problem is that they can’t be combined because of how they have to manipulate things.

A custom layout that just centers its child is probably the easiest way, I guess.

(To be fair, this sort of thing is really hard in a lot of GUI libraries… in Swing it takes a ton of weird code (or similar nesting) and in AWT it’s essentially impossible.)

I once wanted to rotate a picture so I made a silly node class called center container, and when i whant to rotate another panel, i just added to the center container

import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.core.GuiLayout;
import com.simsilica.lemur.style.ElementId;
import com.simsilica.lemur.style.StyleAttribute;

/**
 *
 * @author Pankey
 */
public class CenterContainer extends Node{
    public Container container;


    public static final String ELEMENT_ID = "container";

    public CenterContainer() {
        this(null, true, new ElementId(ELEMENT_ID), null);
    }

    public CenterContainer( GuiLayout layout ) {
        this(layout, true, new ElementId(ELEMENT_ID), null);
    }

    public CenterContainer( String style ) {
        this(null, true, new ElementId(ELEMENT_ID), style);
    }

    public CenterContainer( ElementId elementId ) {
        this(null, true, elementId, null);
    }

    public CenterContainer( ElementId elementId, String style ) {
        this(null, true, elementId, style);
    }

    public CenterContainer( GuiLayout layout, ElementId elementId ) {
        this(layout, true, elementId, null);
    }

    public CenterContainer( GuiLayout layout, String style ) {
        this(layout, true, new ElementId(ELEMENT_ID), style);
    }

    public CenterContainer(GuiLayout layout, boolean applyStyles,
                                ElementId elementId, String style){
        this.container = new Container(layout,elementId,style);
        Vector3f size = this.container.getPreferredSize();
        this.container.setLocalTranslation(-size.x/2, size.y/2, 0);
        this.attachChild(this.container);
    }

    public <T extends Node> T addChild( T child, Object... constraints ) {
        return this.container.addChild(child, constraints);
    }

    public void removeChild( Node child ) {
        this.container.removeChild(child);
    }

    public void clearChildren() {
        this.container.clearChildren();   
    }

    @Override
    public Spatial detachChildAt( int index ) {
        return this.container.detachChildAt(index);
    }

    @StyleAttribute(value="layout", lookupDefault=false)
    public void setLayout( GuiLayout layout ) {
        this.container.setLayout(layout);
    }

    public GuiLayout getLayout() {
        return this.container.getLayout();
    }

    @Override
    public String toString() {
        return getClass().getName() + "[layout=" + getLayout() + ", elementId=" + this.container.getElementId() + "]";
    }
}
2 Likes

Thanks all for the ideas and hints. In the end I used a center Container and not a node to center the Button and keep it at his original position.

To simulate a “Button” with background color and a rotating “picture” I made the following steps

Container C1 = new Container()
C1.setBackground(new QuadBackgroundComponent(myColor))
Container center = new Container () --> has no Background
Button myButton = new Button("", new ElementID("db").child("button")) --> defined in style setBackground(new QuadBackgroundComponent(myTexture)) 

float buttonsize = xy


center .addChild(myButton)
C1.addChild(center)
guiNode.attachChild(C1)

C1.setLocaltranslation (anyx,anyy,anyz)
center.setLocaltranslation(+buttonsize/2,-buttonsize/2,0)
myButton.setLocalTranslation(-buttonsize/2,+buttonsize/2,e.g.2)
 ...
later in updateloop 

center.rotate(0,0,tpf*anyvalue)

It may be possible to just use a center container but in my case I wanted to have a color background, that is not moving or rotating with the Button.

Edit!!:
You need to do the setLocaltranslations after the elements had been initialized…
= you need to put that operation (once) in the updateloop