Libgdx making lists and scrollpanes wrap text? - java

I was wondering, if there is anyway to make a ScrollPane and Lists that wrap text horizontally in LibGDX. I would love the scroll pane to scroll vertically but for it to wrap its text instead of scrolling horizontally.
I know I can disable the X direction of scrolling by using
scrollPane.setScrollingDisabled(false, true);
but is there anyway to make the text wrap so that there is no horizontal scrolling and it would just go to a new line?

You can do in this way :
public class ScrollPaneTest extends ApplicationAdapter {
private Stage stage;
private Table container;
#Override
public void create () {
stage = new Stage();
Skin skin = new Skin(Gdx.files.internal("skin/glassy-ui.json"));
Gdx.input.setInputProcessor(stage);
container = new Table();
stage.addActor(container);
container.setFillParent(true);
Table table = new Table();
final ScrollPane scroll = new ScrollPane(table, skin);
scroll.setScrollingDisabled(true,false);
table.pad(10).defaults().expandX().space(4);
for (int i = 0; i < 100; i++) {
table.row();
Label label=new Label(i + ". Publish your games on Windows, Mac, Linux, Android, iOS, BlackBerry and HTML5, all with the same code base.", skin);
label.setAlignment(Align.center);
label.setWrap(true);
table.add(label).width(Gdx.graphics.getWidth());
}
container.add(scroll).expand().fill();
}
#Override
public void render () {
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
#Override
public void resize (int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void dispose () {
stage.dispose();
}
}
And the output is :

You can wrap the text by using Labels. Then add those Labels to your scrollpane.

Related

How to create a "Pressing Effect" for a button in LibGDX

I have created an ImageButton in my game. It has a listener and I have also added a texture, it works just fine but I couldn't find how to add a pressing effect to my buttons. Is there any premade libGDX method, or an easy way to have a pressing effect for my buttons?
You can use ImageButtonStyle to create a styling for your button, that automatically changes it's texture. This LibGDX Tutorial explains the use of buttons and button styles.
Basically you need to do something like this (from the tutorial):
ImageButton button3 = new ImageButton(mySkin);
button3.getStyle().imageUp = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("switch_off.png"))));
button3.getStyle().imageDown = new TextureRegionDrawable(new TextureRegion(new Texture(Gdx.files.internal("switch_on.png"))));
If the button is handled by a Stage, like the following, it should be handled automatically:
public class MyGdxGame extends ApplicationAdapter {
private Stage stage;
#Override
public void create () {
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
// TODO create the button
// add the button to the stage
stage.addActor(button3);
}
#Override
public void render () {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
}

Multilne text. Libgdx

How to crate a multiline text? I tried to use Label , but text have only 1 line.
Table table = new Table();
table.setPosition(0,0);
table.setSize(800,440);
label = new Label("Some long string here...", skin);
label.setFillParent(true);
label.setAlignment(center);
label.setPosition(0,0);
label.setWidth(40);
label.setHeight(label.getPrefHeight());
label.setText(tutortext);
table.addActor(label);
stage.addActor(table);
stage.setDebugAll(true);
https://i.stack.imgur.com/3whQr.png
Use setWrap(true); on label.
According to doc.
If false, the text will only wrap where it contains newlines (\n). The preferred size of the label will be the text bounds.
If true, the text will word wrap using the width of the label. The preferred width of the label will be 0, it is expected that something external will set the width of the label. Wrapping will not occur when ellipsis is enabled. Default is false.
When wrap is enabled, the label's preferred height depends on the width of the label. In some cases the parent of the label will need to layout twice: once to set the width of the label and a second time to adjust to the label's new preferred height.
I've tested with small example :
public class MultiLine extends ApplicationAdapter {
Stage stage;
Skin skin;
#Override
public void create() {
stage=new Stage();
skin=new Skin(Gdx.files.internal("skin/glassy-ui.json"));
Label label=new Label("MULTILINE IN LIBGDX GAME DEVELOPMENT",skin);
label.setWrap(true);
Table table=new Table();
table.setFillParent(true);
table.add(label).width(150);
stage.addActor(table);
}
#Override
public void render() {
Gdx.gl.glClearColor(0,0,0,0);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.draw();
stage.act();
}
#Override
public void dispose() {
stage.dispose();
skin.dispose();
}
}
Here is the output :
A way simpler solution is to just use \n for linebreaks so instead of
Label label=new Label("MULTILINE IN LIBGDX GAME DEVELOPMENT",skin);
you would just do
Label label=new Label("MULTILINE\nIN\nLIBGDX\nGAME\nDEVELOPMENT",skin);
The label will be:
MULTILINE
IN
LIBGDX
GAME
DEVELOPMENT

How to set up and transform a Camera in a SubScene?

I am trying to get an isometric view of a grid. The grid is only part of the main scene so I created a subscene and I want add a camera to it. I will want to be able to zoom the camera in and out and pan it around preserving the viewing angle throughout all these operation.
Here is what I have without the camera:
public class MyApp extends Application {
#Override
public void start(Stage stage) throws Exception {
Button actionButton = new Button("Placeholder\t\t\t\t\t\t\t\t\t\t\t\t");
HBox hbox = new HBox(actionButton);
BorderPane mainPane = new BorderPane(new MyView(), null, null, hbox, null);
Scene scene = new Scene(mainPane);
stage.setScene(scene);
stage.show();
}
private class MyView extends Group {
MyView() {
super();
GridPane grid = new GridPane();
for (int i = 0; i < 64; i++) {
Rectangle tile = new Rectangle(30, 30, Color.GREEN);
BorderPane pane = new BorderPane(tile);
pane.setBorder(new Border(new BorderStroke(null, BorderStrokeStyle.SOLID,
null, null, null)));
grid.add(pane, i / 8, i % 8);
}
Group root = new Group();
root.getChildren().add(grid);
SubScene scene = new SubScene(root, 300, 300, true, SceneAntialiasing.BALANCED);
scene.setFill(Color.DARKCYAN); // just to see the area
getChildren().add(scene);
}
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
Now I add the camera like this in the MyView constructor:
Camera camera = new PerspectiveCamera(true);
scene.setCamera(camera);
and the grid disappears.
I didn't even do any transformation yet (i would do camera.getTransforms().addAll(new Rotate(-15, Rotate.Y_AXIS));). What am i doing wrong?
also, how can I tell the subscene to take whatever space is available? I don't want to need to specify specific size because the program can run on all sorts of screens.
Your camera is positioned at the same z coordinates as the Group. However you have to make sure it's at a distance between farClip and nearClip:
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setTranslateZ(-100);
camera.setFieldOfView(120);
Furthermore for isometric views PerspectiveCamera is the wrong Camera to use. Use ParallelCamera instead:
Camera camera = new ParallelCamera();
//camera.setRotationAxis(new Point3D(1, 1, 0));
//camera.setRotate(30);
scene.setCamera(camera);
also, how can I tell the subscene to take whatever space is available?
Change the type extended by MyView to something that is resizable and bind the size of the SubScene to the size of MyView:
private class MyView extends Pane {
MyView() {
...
setPrefSize(300, 300);
scene.widthProperty().bind(widthProperty());
scene.heightProperty().bind(heightProperty());
}

JavaFX - label size not initialized

I am working on an application that enables the user to draw graphs, i.e. edges and nodes. As nodes I am currently using plain JavaFX label elements. When drawing the edges, I need to consider the bounds of the label, however, the width and the height of the labels seem to be initialized only after "drawing" it. E.g., when starting the application the label bounds have a width/height of 0, but if a label is repositioned by the user, the width/height is correct.
Is there a possibility to force JavaFX to draw the current elements? The code is rather complex, but the following gives an idea of what I want to do:
stackpane = new StackPane();
text = new Label("Test");
text.setStyle("-fx-border-color:black; -fx-padding:3px;");
stackpane.getChildren().addAll(text);
...
// is it possible to force JavaFX to draw the text here?
...
// some calculations with the bounds of the label
Node node = getLabel();
Bounds bounds = node.getBoundsInParent();
double height = bounds.getHeight();
double width = bounds.getWidth();
I also tried to wrap the text in a rectangle and then manually set the width/height of the rectangle. This works, but the nodes have labels of different length and thus manually setting it is not always suitable.
You may try to bind your logic to node.boundsInParentProperty() changes
public class SmartBorder extends Application {
#Override
public void start(Stage primaryStage) {
final Label txt = new Label("Example");
txt.relocate(100, 100);
Pane root = new Pane();
final Rectangle border = new Rectangle();
border.setFill(Color.TRANSPARENT);
border.setStroke(Color.RED);
// here we autoupdate border
txt.boundsInParentProperty().addListener(new ChangeListener<Bounds>() {
#Override
public void changed(ObservableValue<? extends Bounds> ov, Bounds old, Bounds b) {
border.setX(b.getMinX() - 1);
border.setY(b.getMinY() - 1);
border.setWidth(b.getWidth()+2);
border.setHeight(b.getHeight()+2);
}
});
root.getChildren().addAll(txt, border);
// click to see automatic border reaction
root.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
txt.relocate(Math.random()*200, Math.random()*200);
txt.setText(Math.random() + "");
}
});
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
}

Vaadin Layout - how to get a panel to expand to fill most of the screen

Please note I'm Using Vaadin for this.
I'm struggling to get the middle panel to expand to fill most of the screen with a header and footer at the top and bottom respectively. Here's my code:
public class GridpocApplication extends Application {
#Override
public void init() {
System.out.println("starting now.");
final Window mainWindow = new Window("My Application");
setMainWindow(mainWindow);
mainWindow.getContent().setSizeFull();
VerticalLayout mainColumn = new VerticalLayout();
//Header
Label top = new Label("HEADER");
mainColumn.addComponent(top);
//The middle bit
final Panel middlePanel = new Panel();
middlePanel.setSizeFull();
middlePanel.getContent().setSizeUndefined();
middlePanel.setScrollable(true);
mainColumn.addComponent(middlePanel);
mainColumn.setExpandRatio(middlePanel, 1.0f);
//footer
Label bottom = new Label("FOOTER");
mainColumn.addComponent(bottom);
mainWindow.addComponent(mainColumn);
//test
Label test= new Label("This area should fill most of the screen.");
middlePanel.addComponent(test);
}
}
Where am I going wrong? What I see is this:
Try making mainColumn.setSizeFull() and mainWindow.setContent(mainColumn)

Categories