Bidirectional text support in Lemur?



Do you have any plan to support bidirectional languages like Arabic, Hebrew etc… in lemur text field ?

I believe that BitmapText already supports bidirectional text… and since Lemur is just using that then it should also support it.

I guess the question is whether Lemur telegraphs the proper settings through to the BitmapText but otherwise, Lemur shouldn’t care as long as you set the font right.

Yes. the problem was with this part. now solved

Encountered with problem when using right to left language (bidirectional languages) in lemur TextField

here you can see the problem.

1- we are in line one
every thing is OK

2- line one finishes and going to line two
The placement of words are wrong

3- it is supposed to be like this

I did try some ways … few ways …just one way …:relaxed: to fix it but no success :sweat: and it was by re setting text with inverse line order.

so what can be the easiest way to solve it Mr @pspeed and Mr @Tryder

Could be something wrong in TextField or the DocumentModel classes… BitmapText is not very good at providing the info that a TextField needs to position things like the cursor, etc… so there’s a lot of funny code gymnastics. Could be something is wrong in there.

Ah, i see
So i am looking for some tricks by manipulating string to fix the problem.

So I may need to ask some questions from you.

1- Can we set each line separately ? looking to DocumentModel i could not find a way.

I think this example make it more clear or maybe ambiguous

Read it from right to left

If i can somehow make the first line (Start here) go above instead of coming down, then i think it will be solved.

One thought, for TrueTypeFonts, you could write a custom DocumentModel that extends TrueTypeDocumentModel and supply it to the TextField constructor. My guess is that this custom document model would just be a copy/paste of the base TrueTypeDocumentModel class except you just cut out where you see line++. Probably a bit more to it than that, but it’s a start. In addition to that to your custom document model you would supply a custom StringContainer that extends StringContainer. Again this StringContainer would be a copy/paste of the base StringContainer class, except instead of adding lines whenever text is wrapped you insert the lines at position 0 in an overridden getLines() method.

I uploaded a new version of my modified Lemur to the link I sent you so you can supply a custom DocumentModel to the TextField constructor like so:

TextField tf = new TextField("Text",
new CustomTrueTypeDocumentModel(new CustomStringContainer(TrueTypeFont)),
true, new ElementId(TextField.ELEMENT_ID), null);

thanks a lot.
I could solve it without need to change line order or so… . It was more easy than i thought. just playing with strings.
Now there is no need to change line order. but yet i am experimenting more and will also look at your suggestion.

If you guys figure out what’s wrong with the Lemur code then let me know and I’ll fix it. I’ll be working on my own projects this weekend and so I should have the time.

I don’t think there’s anything wrong with the Lemur code in this respect. Ali contacted me via PM in regards to using my TrueTypeFont library and I sent him a link to an incomplete version of my Lemur modification so he could play around with the new TextField in conjunction with jME-TrueTypeFont. Apparently jME-TrueTypeFont & standard BitmapFonts don’t work out of the box with bidirectional languages, but Ali informed me that he was able to figure out a work around by adding a jme control to the TextField. Apparently it wasn’t working with text wrapping, but it sounds like Ali fixed that. Looking forward to seeing what you’ve come up with @Ali_RS.

Anyway you’re welcome to take a look at the Lemur modification I’m working on, LemurDynamo, on my Google Drive:

I just uploaded a newer version that includes a new default theme, Razor, to help demonstrate the new styling options. I’ll make a thread on it when I have a moment to write up bunch of stuff on how to use it. The HBoxLayout and VBoxLayout are included with improvements to make them more functional. Now you can specify on a per Element basis which elements should stretch/shrink and which Elements should maintain their request size.

HBoxLayout.addChild(Element, VAlign.Center, false, true);

Would produce an element that is centered vertically in the HBoxLayout, does not expand to fill vertical space, but will expand to fill additional horizontal space, so long as the FillMode is not set to FillMode.None, the default value, in the HBoxLayout constructor.

I wanted to provide improved HBox/VBoxLayouts because with the new layout mechanisms necessary to ensure proper text wrapping support DynamicInsetsComponent no longer works.


Aside from the checkbox this was all done using the new GradientBackgroundComponent. The font for this is Cantarell-Regular.ttf.

1 Like

A quick and dirty example of Hbox and VBox:

Container myWindow = new Container(new VBoxLayout(5));
myWindow.setLocalTranslation(144, 400, 0);
myWindow.setBackground(new GradientBackgroundComponent(2, 0, ColorRGBA.BlackNoAlpha, ColorRGBA.White));
myWindow.setPadding(new Insets3f(3, 3, 3, 3));

Label l = new Label("Title");
l.setColor(new ColorRGBA(0.1f, 0.3f, 1f, 1f));
myWindow.addChild(l, HAlign.Center);

l = new Label("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
        + "Aenean posuere, diam non interdum imperdiet, odio mi facilisis lorem, ut "
        + "porttitor est orci a ex. Duis interdum accumsan odio condimentum sagittis. "
        + "Sed ut elit fermentum, aliquet lorem vel, condimentum purus.");
l.setInsets(new Insets3f(0, 0, 15, 0));

Container cont = new Container(new HBoxLayout(5));
cont.addChild(new Button("Okay"));
cont.addChild(new Button("Cancel"));
myWindow.addChild(cont, HAlign.Right);

What I like to call fire and forget, the layout takes care of all the nitty gritty stuff for you :slight_smile:

If anyone ever wants to contribute new styles to core then I’d love to consider it. I have a “wood” one that I intend to contribute at some point but would love to have more built in styles.

You’re certainly welcome to include the Razor theme in Lemur core. In order to do so you’ll need to grab the following from LemurDynamo:
Common.MatDefs.Lemur.RoundedGradient.j3md Common.Shaders.Lemur.Gradient.vert Common.Shaders.Lemur.RoundedGradient.frag com.simsilica.lemur.component.GradientBackgroundComponent com.simsilica.lemur.geom.BrdrPlane com.simsilica.lemur.icons.Razor-check-off.png com.simsilica.lemur.icons.Razor-check-on.png

You’ll also need to change:
selector( "razor" ) { font = font("com/simsilica/lemur/style/base/fonts/Cantarell-Regular.ttf", 21) }

in razor-styles.groovy so that it points to a bitmap font instead of a true type font. Also I haven’t styled the progress bar yet.

P.S. I’m not entirely sure if the style for the slider will work in Lemur core, I made some changes to the Slider class so that it uses HBoxLayout.

Mmm… so far I’ve done my best not to require custom shaders in Lemur.

Maybe instead we can have a repository of easily included styles. (Include the jar, load the resource.) I’ll do some more thinking about it.

It’s funny because I was doing my best to work to removing the BoxLayouts. :slight_smile:

HBox and VBoxLayout aren’t really like your BoxLayouts. HBoxLayout and VBoxLayout duplicate JavaFX’s HBox and VBox functionality. Out of curiosity why wouldn’t you want to include custom shaders in Lemur?

A design goal was to build ‘core’ Lemur against stock JME shaders so that as those shaders evolved or JME evolved, it wouldn’t break Lemur’s shaders. Users are free to use their own custom shaders, of course… and can even replace the ones that Lemur uses simply by overriding GuiGlobals.

From experience with my games where I’ve forked JME shaders, it can be a pain to maintain this over time and I didn’t want to force any of those side effects on Lemur users… leaving it up to them.

For add-ons, it’s 100% fine, of course. It was Lemur’s base that I was mostly worried about when I made that design decision early on. (Also, it keeps me from doing some 2D-only shader tricks that would leave 3D UIs out in the cold.)

Also, just to throw this out there because it has been misinterpreted before. If I ever say that something wasn’t implemented in Lemur “because I didn’t need it”. It’s another way of saying “I didn’t get to it”. It’s not meant to imply that no one would need it… just that I didn’t need it yet.

Decades of experience in software development has taught me that developing something without a use-case is almost always either wasted time or even worse, poisons the brain for the proper solution when the real use-case comes along.

And it occurs to me, there is this wide grey area right now of things “I didin’t need before” but also “didn’t have time to develop it when I needed it” and so have about a half-dozen use-cases using crappy hacks. :slight_smile:

I might disagree about developing something without a use case being wasted time. In some cases yeah absolutely, but not all cases. I think it can also be great exercise for the mind and I think that’s important. Like riding a bike or lifting weights just to keep in shape. Or perhaps like the Buddhist practice of spending many months crafting incredibly intricate mandalas only to destroy them to practice detatchment from material objects.

Yes, that can be true in the general case.

In the case where you are developing an API that you hope others will depend on then not so much. I’m very cautious of including things that I might decide next month is all wrong… then now I’m stuck breaking everyone who uses it or just leaving the ‘now ugly’ in place. That’s one of the reasons I have the separate Lemur-proto to incubate things until I don’t find them ugly anymore. Though some of those classes only have a few blemishes left now.