[SOLVED] BitmapText wont clip at the bottom

I’m using the BitmapText to display a box of user entered information (unlimited length). When they enter too much information I’d like it to just not show all of it but instead it escapes its bounding box (which is a square in the below example):

https://imgur.com/a/KnYTY

Here’s the code to generate that:

public class Main extends SimpleApplication {

  private AudioNode audio_gun;
  private AudioNode audio_nature;
  private Geometry marker;

  public static void main(String[] args) {
    Main app = new Main();
    app.start();
  }

  @Override
  public void simpleInitApp() {
    flyCam.setMoveSpeed(40);

    BitmapText textualDisplay = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"), false);   
    
    Rectangle textRectangle=new Rectangle(0,0,1,1);
     
    textualDisplay.setBox(textRectangle);
    textualDisplay.setVerticalAlignment(BitmapFont.VAlign.Center);
    textualDisplay.setAlignment(BitmapFont.Align.Center);
    textualDisplay.setLineWrapMode(LineWrapMode.Word);
    textualDisplay.setText("This text should be clipped within a square, its wraps at the edges but just ignores the edges,This text should be clipped within a square, its wraps at the edges but just ignores the edges, This text should be clipped within a square, its wraps at the edges but just ignores the edges,This text should be clipped within a square, its wraps at the edges but just ignores the edges ");
    textualDisplay.setSize(0.1f);
    
    rootNode.attachChild(textualDisplay);
        
  }

}

Anyway I can get it to clip the text at the bottom while still wrapping over multiple lines (without having to guess how much space the text will take and shortening it manually)?

I have found a couple of methods that may indirectly help me:

textualDisplay.getLineCount();
textualDisplay.getLineHeight();

With these I should be able to be able to calculate how much to shorten the text by without having to guess how much space a string will take.

I’m still interested in an easier way to do it but if not that should give me what I need

Heres a minimum example of using this if anyone else goes down this route

public class Main extends SimpleApplication {

  private AudioNode audio_gun;
  private AudioNode audio_nature;
  private Geometry marker;

  public static void main(String[] args) {
    Main app = new Main();
    app.start();
  }

  BitmapText textualDisplay;
  private float boxHeight = 1;
  
  @Override
  public void simpleInitApp() {
    flyCam.setMoveSpeed(40);

    textualDisplay = new BitmapText(assetManager.loadFont("Interface/Fonts/Default.fnt"), false);   
    
    Rectangle textRectangle=new Rectangle(0,0,1,boxHeight);
     
    textualDisplay.setBox(textRectangle);
    textualDisplay.setVerticalAlignment(BitmapFont.VAlign.Center);
    textualDisplay.setAlignment(BitmapFont.Align.Center);
    textualDisplay.setLineWrapMode(LineWrapMode.Word);
    rootNode.attachChild(textualDisplay);
    
    setText("This text should be clipped within a square, its wraps at the edges but just ignores the edges,This text should be clipped within a square, its wraps at the edges but just ignores the edges, This text should be clipped within a square, its wraps at the edges but just ignores the edges,This text should be clipped within a square, its wraps at the edges but just ignores the edges ");
      
  }
  
  public void setText(String text){
    textualDisplay.setText(text);
    textualDisplay.setSize(0.1f);

    int maxLines = (int)(boxHeight/ textualDisplay.getLineHeight());
    int actualLineCount = textualDisplay.getLineCount();

    if (actualLineCount>maxLines){
        //cut the text down by that amount
        double fractionToKeep = maxLines / (double)actualLineCount;
        int charactersToKeep = (int)(fractionToKeep * text.length());

        setText(text.substring(0, charactersToKeep)); //recursive becaues calculation may not be quite right if for example word boundaries are unhelpful
    }
  }
  

}

This may slightly over trim the string, if you wanted to get it exactly right you could use a bisection approach

1 Like

I once had a similar problem to solve, but did it with scaling down the font instead.

Code was something like:

while(text.getLineCount()>2){
    text.setFontSize(text.getFontSize()-1);
    text.updateGeometricState(); //not sure if something like this was needed or not
}

You could just replace the setFontSize with something like setText(getText().substring(0,getText().length-1)).

Trimming it char by chat should get it to the most accurate size, but it’s a bit more performance demanding.