[GUI] StructuredTextBlock: multiple colors/styles in one block of text

Hi there,

Being able to have multiple styles in one TextBlock would be really great, especially for a game character’s (or narrator’s) dialog to emphasize with italic, or to highlight some keyword in bold red, and so on…

Is there any plan for supporting this?

If so I would suggest an agnostic approach for the text input, something like text = [ { text: "some italic text" , attributes: { italic: true } } , { text: "some normal text" , attributes: { italic: false } } ] so userland would parse any markup (HTML, BBCode, whatever) on his own, producing an array of text-part and attributes.

It seems that @msDestiny14 is the one to ping for GUI questions :wink:

1 Like

AH! At first I thought this was a request for being able to have like bold + italic + highlight in the same textbook. (This is already possible). I see what you mean now.

I think some kind of markdown would be cool to add. Just like: “Here is ** B ** text” becoming Here is B text;.

Let me add it to our backlog to discuss. If you want to want to make a PR on it anyways. Be my guest. :slight_smile: and I would be happy to review.

In the meantime. If you want a workaround. You can have separate textBlocks with the resize to fit option. Then knowing the sizes you can just have horizontal alignment left and lay them one after the other. This also works by default with a stack panel as well. Here is an example in the GUI editor: https://gui.babylonjs.com/#NVAEEZ#1

2 Likes

To me it seems better to start with an agnostic format, so “Here is B text” would be somthing like [ { text: "Here is " } , { text: "B" , bold: true } , { text: " text" } ]. Then either let userland convert markdown to that format, or add built-in support later. What do you think about it?

I would gladly make a PR, but I’ve never coded a single line of TypeScript yet…
I will probably hack my way in JS first, then see what can I do in TS later.

Also I can live without that feature for instance, but I will badly need that in 1 or 2 months.

Side question: is Babylon-native going to support GUI?

Adding @Cedric for the babylon native part.

@cronvel yes, there is already a partial GUI support. Text in dynamic textures works for example. Some other features likes rectangles, colors, partial drawimage.
Feel free to test it and report bugs or needed features.

@Cedric I’m a bit curious: did you re-implemeted browser’s 2D canvas for that?

yes but not all functionnalities. only those needed by babylon js gui… well at least, some of them :slight_smile:

Hey hey! I opened this issue for record keeping: Create markdown for GUI textBlock control · Issue #11309 · BabylonJS/Babylon.js · GitHub

As for the format. It’s up to you! :smiley: Only thing to be accounting for however is that the GUI Editor will need to support this. I’m having a slightly hard time picturing how something like this would look in the editor but maybe there is some design exploration needed for this. :slight_smile:

@msDestiny14 Thanks for the reply!
And what about some typical game effects like slow-typing? Is it ok to add this to TextBlock?

Let’s write a separate issue for it.

Personally this feels like a animation/state machine like feature. Not sure if it makes sense to have it in the GUI system itself. But I can see reasons to have it in as well.

Let me get back to you on that!

@PatrickRyan if you have some time today would love to know your thoughts design wise.

Made a simple slow-typing example
https://playground.babylonjs.com/#XCPP9Y#9251

2 Likes

@aWeirdo Yes of course… But the effect is not nice when dealing with word-wrapping, alignment, and so on… At least, it’s not the effect that games are using for their dialog boxes.
All the alignment stuffs and line-break should be precomputed beforehand, that’s why it’s best to implement this internally in TextBlock.

Hi @cronvel
You can use \n directly in the text string for precise newlines at specific words (First 2 lines),
or textBlock.textWrapping = WordWrap; for automatic word-wrapping (Last 2 lines)
combined with textBlock.textHorizontalAlignment & textBlock.textVerticalAlignment to properly align the text to edges.

https://playground.babylonjs.com/#XCPP9Y#9264

Ofc, if you also want the container/rectangle to scale, which can be common in these scenarios, it’s a bit more work. :slight_smile:

A little update to say that I’ve made some progress hacking TextBlock.
For instance it supports multiple colors.
Now I will try to make bold and italic work.

By the way there is a lot a things that have/may have to change internally.
At the moment I just duplicated TextBlock methods to support both plain text and the structured format. It just detects if the user provide a string or an array as .text and branch accordingly.
In the future, it would be probably best to have only one codepath, so TextBlock would use only the structured format internally, and simply convert plain string into [{text:"my string"}] inside the setter.

Bold and underline are now working, also I improved underline, adding support for the outline feature (basically replaced the canvas .lineTo() by a canvas .strokeRect() before the .strokeText() and .fillRect() before the .fillText()).

1 Like

This is a single TextBlock with word-wrapping mixing colors underline, strike-through, bold and italic:

@msDestiny14 Is it better to continue discussion on Github or here? Also, before investing more time, I need some approval on this:

By the way there is a lot a things that have/may have to change internally.
At the moment I just duplicated TextBlock methods to support both plain text and the structured format. It just detects if the user provide a string or an array as .text and branch accordingly.
In the future, it would be probably best to have only one codepath, so TextBlock would use only the structured format internally, and simply convert plain string into [{text:"my string"}] inside the setter.

For instance my PoC was made in JS, I need to know if this is going to be accepted by the team before investing more of my free time for a PR.

3 Likes

Also I noted that the TextBlock is often fully recomputed for no reason.
E.g. simply opening dev-tools (which resize the screen but not the size of the TextBlock) have to compute word-wrapping again (which make a lot of context.measureText() calls).
Maybe it would be better to have more level of dirtiness, e.g. have a ._innerContentIsDirty property, and only recompute lines when the text have changed (or the TextBlock bounding box size).

1 Like