[SOLVED] Issue with line wrapping of right to left text in BitmapText

Hi guys

I want to display a right to left text (which means you are supposed to read this text from right to left).
I am using Lemur and I have set a max-width so it will wrap the text.

The problem is it is displayed like below:

So I should read it from bottom to top!!

I have already set the boolean rightToLeft on BitmapText but it does not work.

Do you know any way I can fix it?

1 Like

I’m not clear what’s going on here. I mean, I think I understand the issue you describe but I don’t know what parts are to blame.

A test case might be interesting.

Ok, Let me explain with an example.

As you may know some languages like Arabic, Persian,… are written from right to left. I want to be able to display them in a Label.

I will demonstrate it on WordWrapDemoState in Lemur demos.

/**
 * A demo of a Label that has a maximum width set so that long strings will word
 * wrap after a certain width. The label is wrapped in a popup window to
 * illustrate that layouts and sizing work as expected.
 *
 * @author Paul Speed
 */
public class WordWrapDemoState extends BaseAppState {

    /**
     * A command we'll pass to the label pop-up to let us know when the user
     * clicks away.
     */
    private CloseCommand closeCommand = new CloseCommand();

    public WordWrapDemoState() {
    }

    @Override
    protected void initialize(Application app) {
    }

    @Override
    protected void cleanup(Application app) {
    }

    @Override
    protected void onEnable() {

        // We'll wrap the text in a window to make sure the layout is working
        Container window = new Container();
        window.addChild(new Label("Word Wrapped Text", new ElementId("window.title.label")));

        // An example Persian text. 
        // Read it from right to left.
        String txt = perisantext.p("این یک متن آزمایشی می باشد"); 
        BitmapFont font_m = getApplication().getAssetManager().loadFont("PersianFont.fnt");
        
        Label label = window.addChild(new Label(txt));
        label.setMaxWidth(200);
        label.setFont(font_m);
        label.setFontSize(30);
        label.setTextHAlignment(HAlignment.Right);

        // Add a close button to both show that the layout is working and
        // also because it's better UX... even if the popup will close if
        // you click outside of it.
        window.addChild(new ActionButton(new CallMethodAction("Close",
                window, "removeFromParent")));

        // Position the window and pop it up                                                             
        window.setLocalTranslation(400, 400, 100);
        getState(PopupState.class).showPopup(window, closeCommand);
    }

    @Override
    protected void onDisable() {
    }

    private class CloseCommand implements Command<Object> {

        public void execute(Object src) {
            getState(MainMenuState.class).closeChild(WordWrapDemoState.this);
        }
    }
}

For your ease of reading, I will represent it in English.

This is the translation of the text in English written from right to left:

String txt = ".text test a is This"; // read it from right to left

For testing purpose, I modified constructor in Label class to accept boolean rightToLeft:

public Label( String s, boolean rightToLeft  ) {
    this( s, true, new ElementId(ELEMENT_ID), null, rightToLeft );
}

protected Label( String s, boolean applyStyles, ElementId elementId, String style, boolean rightToLeft ) {
    super(false, elementId, style);

    // Set our layers
    getControl(GuiControl.class).setLayerOrder(LAYER_INSETS, 
                                               LAYER_BORDER, 
                                               LAYER_BACKGROUND,
                                               LAYER_ICON,
                                               LAYER_SHADOW_TEXT,
                                               LAYER_TEXT);

    // Retrieve the font before creation so that if the font is
    // customized by the style then we don't end up creating a
    // BitmapText object just to throw it away when a new font
    // is set right after.  It's a limitation of BitmapText that
    // can't have it's font changed post-creation.
    Styles styles = GuiGlobals.getInstance().getStyles();
    BitmapFont font = styles.getAttributes(elementId.getId(), style).get("font", BitmapFont.class);
    this.text = new TextComponent(s, font, rightToLeft);
    text.setLayer(3);

    getControl(GuiControl.class).setComponent(LAYER_TEXT, text);

    if( applyStyles ) {
        styles.applyStyles(this, elementId, style);
    }
}

note this change:
this.text = new TextComponent(s, font, rightToLeft);

but setting it either to true or false has no effect. Isn’t this boolean meant to be used for the right to left LineWrapMode?

Here is the only where I found this boolean it is used:

I am not sure If I am understanding what it does :confused:

If this rightToLeft boolean is not designed for what I am looking then I need to find an alternative way to resolve my problem.

One such way is to get the lines after they are wrapped, and reverse their order:

in this example:

In the Lemur Label if I can get those wrapped lines I can create a new string by reversing the orders:

String newText = [-------------A------------] + [----------B--------|-----A-----]

now If I set newText into Label it will look correct I guess :

[--------------A--------------]
[--------B--------|-----A-----]

but the problem is for reading the lines I need to have access to Letters.java and LetterQuad.java classes from com.jme3.font package but those classes are not public so can not be accessed from outside.

Hi. Im in holiday till end of month and have only my phone with me.
Anyhow you dont need to get the fonts. There is either in Textentrycomponent or Documentmodel (?) a method createcomposite (?). Follow it. This method is leading to the text that is displayed in lemur. And in one of the class you find lines (of your text) and can access them.
Im sure @pspeed may help you if you cant find it .

And yes you may modify one or more of the lemur classes e.g. by an own routine to reset the text.

Sorry for not being able to help more detailed at the moment.

1 Like

@Aufricer TextEntryComponent is only for TextField. I am using a Lemur Label which uses a TextComponent and it does not expose any way to get lines.
I guess TextField uses “\n” for handling lines whereas in Label line wrapping is handled internally by BitmapText and it is declared inside LetterQuad.

I haven’t had time to drill into this yet… but is the bug in BitmapText or in Lemur’s TextComponent?

Yep, an issue with BitmapText.

Edit:

Created an issue on Github:

Cool. I’m still interested, it just helps me focus in a direction.

If you feel extra adventurous… a simple BitmapText example might be nice to attach to the issue. (Super-adventurous would be to add it to the jme examples.)

1 Like

Done

The expected result should be:
(Read from right to left)

                                                  to right test a is This
                                                               .text left 

but it displays:

                                                 .text left to right test 
                                                                a is This 
1 Like

Hey guys sorry for bumping this, thought someone might still have an interest in looking further into this bug.

Will appreciate any help :slightly_smiling_face:

1 Like

After working and discussing with @Ali_RS on this, we opened an PR for it.

3 Likes

Thank you so much @Aufricer! :slightly_smiling_face:

2 Likes

This issue is now fixed on the master branch. Thanks for all the efforts made to fix the issue. :heart:

2 Likes