I would like to display a JFX screen inside a Lemur rollup panel. I am using Lemur and jmejfx2.0.0 at the same time in my game. I was wondering if anyone had created a JFX custom component as a panel in Lemur? If not, I will have to create one from scratch. If I do, is anyone interested in it?
EDIT:
I got tired of waiting so I created a Lemur Element that acts like a Lemur Panel but displays the contents of a .FXML file. If you have a window resize listener in your application just call updateShape() so that the translation and size get refreshed based on the new window size. Enjoy!
IMPORTANT!!! MAKE SURE THE Z ORDER OF YOUR JMEJFX NODE IS IN FRONT OF THE LEMUR COMPONENTS IN THE GUI NODE. I SET MINE TO 100!
import java.io.IOException;
import java.net.URL;
import org.lwjgl.opengl.Display;
import com.jfoenix.concurrency.JFXUtilities;
import com.jme3.app.Application;
import com.jme3.math.Vector3f;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.lemur.Panel;
import com.simsilica.lemur.component.AbstractGuiComponent;
import com.simsilica.lemur.core.GuiControl;
import com.simsilica.lemur.core.GuiUpdateListener;
import com.simsilica.lemur.core.VersionedReference;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.layout.AnchorPane;
public class JFXAnchorPane<ControllerClass> extends Panel
{
private class JFXAnchorPaneComponent<T extends Object> extends AbstractGuiComponent
{
public T getController()
{
return controller;
}
private AnchorPane anchorPane;
private T controller;
private Group jfxGroup;
@SuppressWarnings("unchecked")
public JFXAnchorPaneComponent(URL fxmlLocation, Group jfxGroup)
{
FXMLLoader loader = new FXMLLoader(fxmlLocation);
try
{
anchorPane = loader.load();
controller = (T) loader.getController();
} catch (IOException e)
{
e.printStackTrace();
}
this.jfxGroup = jfxGroup;
}
@Override
public void calculatePreferredSize(Vector3f size)
{
size.setX((float) anchorPane.getPrefWidth());
size.setY((float) anchorPane.getPrefHeight());
}
public void privateReshape()
{
JFXUtilities.runInFXAndWait(new Runnable()
{
@Override
public void run()
{
Vector3f screenPos = getNode().getWorldTranslation();
Vector3f size = getSize();
anchorPane.setLayoutX(screenPos.getX());
anchorPane.setLayoutY(Display.getHeight() - screenPos.getY());
anchorPane.setPrefWidth(size.getX());
anchorPane.setPrefHeight(size.getY());
}
});
}
@Override
public void detach(GuiControl parent)
{
super.detach(parent);
JFXUtilities.runInFX(() -> {
jfxGroup.getChildren().remove(anchorPane);
});
}
@Override
public void attach(GuiControl parent)
{
// TODO Auto-generated method stub
super.attach(parent);
JFXUtilities.runInFX(() -> {
jfxGroup.getChildren().add(anchorPane);
});
}
@Override
public void reshape(Vector3f pos, Vector3f size)
{
}
}
public ControllerClass getController()
{
return component.getController();
}
private JFXAnchorPaneComponent<ControllerClass> component;
public JFXAnchorPane(URL fxmlLocation, Group jfxGroup)
{
super();
component = new JFXAnchorPaneComponent<ControllerClass>(fxmlLocation, jfxGroup);
setBackground(component);
}
/**
* This will update the translation and size of the JFX component based on
* the current layout and window size of the {@link Application}.
*/
public void updateShape()
{
component.privateReshape();
}
private Vector3f oldTranslation = new Vector3f();
private Vector3f oldSize = new Vector3f();
@Override
public void updateLogicalState(float tpf)
{
super.updateLogicalState(tpf);
if(getWorldTranslation().equals(oldTranslation) == false || getSize().equals(oldSize) == false)
{
updateShape();
oldTranslation.set(getWorldTranslation());
oldSize.set(getSize());
}
}
}