I’m trying to have a container located at the top-right corner of another panel. For it, I add a GuiControlListener to that panel and listen at it reshape method. It would work if it wasn’t because of the panel has got insets and the reshape method’s size parameter is the panel size before applying the insets. This is something obvious and seems intended if we take a look at the source:
public void setSize( Vector3f size ) {
if( size.x < 0 || size.y < 0 || size.z < 0 ) {
throw new IllegalArgumentException("Size cannot be negative:" + size);
}
lastSize.set(size);
// The components will take their parts out of size.
// The caller may not be expecting their size to change... especially
// since it might have been the getPreferredSize() of some other GUI element
Vector3f stackSize = size.clone();
Vector3f offset = new Vector3f();
for( GuiComponent c : componentStack.getArray() ) {
c.reshape(offset, stackSize);
stackSize.x = Math.max(0, stackSize.x);
stackSize.y = Math.max(0, stackSize.y);
stackSize.z = Math.max(0, stackSize.z);
}
if( layout != null ) {
layout.reshape(offset, stackSize);
}
if( listeners != null ) {
// Call the listeners with the original size befoe
// the components took a whack at it.
for( GuiControlListener l : listeners.getArray() ) {
l.reshape(this, offset, size);
}
}
}
However, there is something strange, the size is passed to listeners with the value previous to applying the insets but the offset isn’t. So we end with listeners that give a position applying insets and a size that doesn’t.
Shouldn’t that method use the “stackSize” instead of “size”? (the latter can be taken with source.getSize())
The listener reshape is on the GUI element… not on the component stack. There could be 100 items in that component stack doing strange things to the offset and size. The listeners should not see that. (Else you will see really strange offsets and sizes and certainly containing more than just the insets.)
In your case, just see if the element you are listening to has insets and offset accordingly. There really isn’t any other way as the component stack itself has no concept of insets… that’s just another component in the stack (and an InsetsComponent could technically be in multiple places in the stack).
Since you want to position your other GUI element relative to the upper inset corner then you will need to care about insets… by calling getInsets() (or getInsetsComponent()). A lot of other GuiControlListeners wouldn’t care about that.
Anyway, passing “offset” is technically a bug but it’s also safe to ignore in your listener. Because if the “right” value were passed in then it would just be new Vector3f() anyway.
I’m not totally sure about that. It is a common case (at least I want to do it in a lot of places) to try to visually locate a panel in a position related to another one, considering that panel the visual part of it, what the background shows and, if I’m correct, the background is applying that 100 items transformations to it (so, the second panel position must be aware of that 100 items transformations too).
100 items could be an icon or text or various other things that slowly squeeze the size more and more… (to the point that if you decided to locate your other element there it would be a tiny dot in the middle.)
Any of which are easy to get just by asking the component stack.
the GuiControlListener is meant to listen to…ahem… GuiControl. The size of the GuiControl is the one provided.
Well, thanks for the info. I did a fast workaround trying to make it work with any insets type (I’m not sure it is right but it works with normal insets):
public void reshape(GuiControl source, Vector3f pos, Vector3f size) {
Vector3f aux = optionsPanel.getLocalTranslation();
InsetsComponent insetsComponent = source.getComponent(LAYER_INSETS);
if(insetsComponent != null) {
Vector3f position = new Vector3f();
insetsComponent.reshape(aux.set(size.x, 0, 0), position);
aux.addLocal(position.x, 0, 0);
}
optionsPanel.setLocalTranslation(aux.addLocal(0, 0, pos.z));
}
It is supposed to be just like in the image. The blue panel has insets and what the user sees is just it background. The orange panel top-center must be aligned with the blue panel top-right corner.
Well… now you mention it, nothing that couldn’t be done using panels instead of insets.
The blue and orange box are inside another container (the green one) with a SpringGridLayout. The green panel is the second element in that layout (the red is the first). Finally, the blue panel must be slightly separated from the surrounding borders.