Lemur: Size cannot be negative?

I have an application where the label grows as more text it has, yes it looks bad, so we can just remove text from it. But the automatically evened size becomes negative and it crashes.

I wonder if there could have some way to prevent it, like set a minimum for all elements to never become negative?

On the test case, just click any button, the textfield text will be copied to the label and it will crash. If you hit backspace before clicking (one less letter), it will not crash.

java.lang.IllegalArgumentException: Size cannot be negative:(-0.25321198, 0.0, 0.0)
	at com.simsilica.lemur.core.GuiControl.setSize(GuiControl.java:242)
	at com.simsilica.lemur.component.SpringGridLayout$Entry.setSize(SpringGridLayout.java:537)
	at com.simsilica.lemur.component.SpringGridLayout.reshape(SpringGridLayout.java:310)
	at com.simsilica.lemur.core.GuiControl.setSize(GuiControl.java:259)
	at com.simsilica.lemur.core.GuiControl.revalidate(GuiControl.java:351)
	at com.simsilica.lemur.core.GuiControl.controlUpdate(GuiControl.java:318)
	at com.jme3.scene.control.AbstractControl.update(AbstractControl.java:112)
	at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:661)
	at com.jme3.scene.Spatial.updateLogicalState(Spatial.java:808)
	at com.jme3.scene.Node.updateLogicalState(Node.java:222)
	at com.jme3.scene.Node.updateLogicalState(Node.java:233)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:250)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:192)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:745)

Test case:

Unfortunately, Lemur doesn’t really like it when you give it impossible layouts and so will throw this exception. I was kind of waiting to “see it in the wild” (and not just in my own use) before deciding what to really do about it.

Actually it’s weird in this case because I thought TextField would already limit itself.

Have you tried TextField.setPreferredLineCount() and setPreferredWidth() instead of forcing the size with preferred size?

1 Like

My opinion :slight_smile:

I believe, a good option would be to prevent buttons and labels text wrapping. If the text overflow the bounds, the text could simply be truncated.

Also, the minimum width should be the width of the visible letter (or the first letter), the same for the height.

Basically, on stressing shrinking situations, this would keep the GUI usable (clickable), readable (we can see at least one letter) and without crashing.

Back to the crash:

I changed textfield to prefer width 100, and lines 1, but the crash still happens.

The problem seems to happen not at the textfield but on the top container itself “myWindow”.

I think it is that because I put names on all these spatials, in debug, at this stack element below, while watching for this.getName(), I got “myWindow”.

at com.jme3.scene.Spatial.runControlUpdate(Spatial.java:661)

The problem happens after this calculation:

protected float weighted(int index, float pref, float totalSize, float totalPref, int count, FillMode fill, Axis axis) {
    switch( fill ) {
        case Even:
            return pref + (totalSize - totalPref)/count;

where values are

pref	68.774704	
totalSize	618.0	
totalPref	1032.1675	
count	6	

returns -0.25321198, (are stored at colSizes) may be it could be protected to return a minimum of 0.1. As a test, I changed all negative values from that local variable at:

SpringGridLayout.reshape(Vector3f, Vector3f) -> colSizes

to 0.1f and it did not throw exception :slight_smile:

PS.: I updated the gist

I will look into the rest in more detail later

Something is wrong I think in how you are determining where the error is happening… because myWindow’s size will be set first to the preferred size that you’ve forced upon it. It cannot have this error. It has to be further down in the layouts where they are being asked to do the impossible.

but I wanted to drill in on this…

If your text field is only supposed to be one line then you can set it to be single line.

I was doing some more tests. The Label and the TextField accept PreferredSize constraints, but the Buttons doesnt! Is that a bug?

I would like to request also if it could be implemented a setMinimumSize(), so elements could grow as much we want, but would never shrink less than expected.

And if there could have a global limit of 1x1 size (one dot), so nothing would be allowed to have less than 1 dot in size.

For now, I fixed my application by fixating the size of the label, so it will not smash the buttons anymore.

This concept implies that layouts run some kind of iterative algorithm to drill in on a solution. This waaaay complicates things… and in fact you then have to add all kinds of cases to handle the impossible. (What if even with all of your minimum sizes it’s still too big for the outer constraints?)

Lemur uses a simpler approach where one pass calculates preferred size and another sets the size.

I agree that maybe there should be a better fallback than an exception… though that is the most obvious way to indicate that your layout constraints are broken.

As for buttons, buttons are just labels. They do no other processing related to preferred size.

I’m underwater at my day job at the moment or I’d have looked into your example more deeply. Sorry about that.

1 Like

I thought it could be unnecessarily complicated to address, I was just not sure, now I know :).

Well, the exception makes the developer have to fix the layout as soon he can. With a fallback (like min of 1 dot size), lets the end user (lets say) expand the window again so the elements will fit again, and… the developer may never know what happened, but… the end user/client will be more happy!

To test, I inverted the elements order, now buttons are to the left, I thought they would get priority for the preferred size, but they continued shrinking, now I am puzzled, I need more tests to understand how it works may be?

Its cool, np!
As you suggested, I am using (layout/design) workarounds (just fixed/fixated it) and the application is stable again concerning this!