Background Story: I very recently started investing in lemur as a replacement of Nifty gui. I think it has great potential because I was looking for a library that would allow me to extend things instead of introducing hard limitations because of bad decisions during its design.
And it seems that this is what’s all about with lemur. Actually I was about to create my own library until I found out that lemur already sets the building blocks for me and I don’t need to start from scratch. Its architecture makes a lot of sense to me and the code is well written.
Issue: All I want to do is the central alignment of a button without changing its size. In other words it needs to be in the center of a panel and fits its contents. The reason for this is that I don’t want the user to feel that he stepped on a minefield and every part of the screen is clickable.
Anyway what I managed to do so far is the one or the other but not both using SpringGridLayout.
I intent to implement my own GuiLayout that is more html like but before I do that I would like to know if there’s something I missing so I can have a better understading on the existing implementations before I start doing my own thing.
So the element are not stretched but they are aligned as top-left in relationship to their parents.
Btw maybe there is a different approach to follow here for the bigger probel which is having 4 buttons in the middle of the horizontal axes spread evenly in the vertical axes but with no re sizing.
Thanks for providing the code example, I think some of it may be missing though? I don’t think LemurUtils and CircularListWrapper are core parts of the library/JME.
Yes indeed. I didn’t want to spam you with all the implementation details.
This is how I create the full screen container:
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class LemurUtils {
public static Container getFullScreenContainer(Camera camera) {
Container container = new Container();
container.setLayout(new SpringGridLayout());
final int width = camera.getWidth();
final int height = camera.getHeight();
container.setPreferredSize(new Vector3f(width, height, 0));
container.setLocalTranslation(0, height, 0);
return container;
}
}
And the circularList is just used for debugging purposes:
@RequiredArgsConstructor
public class CircularListWrapper<T> {
@Getter
private final List<T> list;
private int counter = 0;
public T getNext() {
final T nextResult = list.get(counter % list.size());
counter++;
return nextResult;
}
}
Thanks, people are dramatically more likely to help if you provide a small program they can just run and see the issue. It isn’t always possible but when it is it is a good thing to do.
Here is a minimal program that replicates your issue
import com.jme3.app.SimpleApplication;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.system.AppSettings;
import com.simsilica.lemur.Axis;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.FillMode;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.HAlignment;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.VAlignment;
import com.simsilica.lemur.component.QuadBackgroundComponent;
import com.simsilica.lemur.component.SpringGridLayout;
import java.util.Arrays;
import java.util.List;
public class LemurTest extends SimpleApplication{
@Override
public void simpleInitApp(){
GuiGlobals.initialize(this);
getGuiNode().attachChild(mainScreen());
}
private Container mainScreen() {
Container screen = LemurUtils.getFullScreenContainer(getCamera());
screen.setLayout(new SpringGridLayout(Axis.Y, Axis.X, FillMode.Even, FillMode.Even));
screen.setBackground(new QuadBackgroundComponent(ColorRGBA.Gray));
screen.addChild(createButtonPanel("Start", this::onClick));
screen.addChild(createButtonPanel("Select Level", this::onClick));
screen.addChild(createButtonPanel("Credits", this::onClick));
screen.addChild(createButtonPanel("Quit", this::onClick));
return screen;
}
private void onClick() {
System.out.println("Clicked");
}
private final CircularListWrapper<ColorRGBA> color = new CircularListWrapper<>(Arrays.asList(ColorRGBA.Green, ColorRGBA.Blue));
private Panel createButtonPanel(String label, Runnable action) {
final Container container = new Container(new SpringGridLayout(Axis.Y, Axis.X, FillMode.None, FillMode.None));
container.setBackground(new QuadBackgroundComponent(color.getNext()));
{
Button button = container.addChild(new Button(label));
button.setBackground(new QuadBackgroundComponent(ColorRGBA.Red));
button.setTextHAlignment(HAlignment.Center);
button.setTextVAlignment(VAlignment.Center);
button.addClickCommands(source -> action.run());
}
return container;
}
public static void main(String[] args){
LemurTest app = new LemurTest();
AppSettings settings = new AppSettings(true);
settings.setResolution(800, 600);
app.setSettings(settings);
app.start();
}
public static final class LemurUtils {
public static Container getFullScreenContainer(Camera camera) {
Container container = new Container();
container.setLayout(new SpringGridLayout());
final int width = camera.getWidth();
final int height = camera.getHeight();
container.setPreferredSize(new Vector3f(width, height, 0));
container.setLocalTranslation(0, height, 0);
return container;
}
}
public static class CircularListWrapper<T> {
private final List<T> list;
private int counter = 0;
public CircularListWrapper(List<T> list){
this.list = list;
}
public T getNext() {
final T nextResult = list.get(counter % list.size());
counter++;
return nextResult;
}
}
}
Hmm, it does seem somewhat difficult. I think partially it is that “outside in” layouts like this are less usual than “inside out” layouts. By which I mean most of the time a parent grows to accommodate its children, rather than being a fixed size. (Nifty was very much enforced “outside in” layout).
I can see ways in which it could be done with a new layout that took a child and parameters on where to put unwanted space (so say you put 40% of unwanted space above for example then 60% of unwanted space would go below). I’m up for trying to write something like that but before I do @pspeed is the expert on lemur (and its author) so he may have a better suggestion
…that was precisely the reason for its design: reusable building blocks to either use the “built in” stuff or roll together in different ways. So Lemur tries to be very modular.