Text display or indicator in Makie.jl

Hi

Just wondering if I am missing a very basic element here… but is there a way to have a nice and simple text display on a Makie.jl scene?

I’m trying to use Makie to build a very simple user GUI with some buttons to select a file, some plots to display the data and some sliders to play around with some settings.
So far so good, but what I want at some points is a simple display of some text, which is just a display, nothing the user would/should interact with (like, e.g., showing the selected filename after button click or any other information).

fig = Figure(); display(fig);

leftPane = fig[1:2,1] = GridLayout()
rightTopPane = fig[1,2] = GridLayout()
rightBottomPane = fig[2,2] = GridLayout()

ax1 = Axis(rightTopPane[1,1])
ax2 = Axis(rightTopPane[2,1])
ax3 = Axis(rightBottomPane[1,1])

sld = Slider(rightBottomPane[2,1],range=-10:1:10,startvalue=0)

btnOpen = Button(leftPane[1,1],label="Open a file...")
btnDo = Button(leftPane[3,1], label="Do Something!")
btnDoMore = Button(leftPane[4,1],label="Do Something Else!")

txtTest = Textbox(leftPane[2,1],stored_string="This is Text!",tellwidth=false)

I now there is Textbox(), and from a design point of view it is kind of what I want… but unfortunately it cannot be made readonly (or can it??). The user can always click on it and enter text, although this is supposed to be display only.
Then there is Label() which is really readonly… but unfortunately it has no style elements to it like background color, borders, etc…

And for both widgets I don’t see how to set a fixed width with simple word wrap for longer text.

I’m wondering, is there another option that I am missing? If not, is this not something that should be added to the Makie framework? Like a TextIndicator() widget or something…

Because it seems very natural that you want a certain area of your Layout just for displaying some info that might not be directly related to the plots (as in a legend).

Thx!

1 Like

Label is indeed very bare-bones, and Textbox is meant for interactive use. What you want doesn’t exist yet, I have so far always just put a Label on top of a Box so the Box gives the background and border. You can just put both in the same layout cell, Box first.

Automatic word wrapping is not implemented, although this one could be relatively straightforward to implement. Other rich text features like bold or italic text in between or different colors for different characters are also not implemented yet, but that’s also because it’s quite complex to implement and relatively rarely needed for most plots.

Thanks for the comment (and this workaround which will at least work for some scenarios)!

I was afraid this would be the answer to my issue that Makie in the end is not (yet) developed for easy GUI design but more like interactive scientific plotting.
I like how reactive it is with the observables though… so hopefully it will grow in this direction.

So I guess it then goes back to the few discussions on here about how Makie could be conveniently combined with other GUI packages like GTK or CImGUI or others… unfortunately that seems quite complicated at this point :confused:

So I’ve played around with this now… there is one crucial aspect I don’t quite get:

I have my Box and Label in the same GridLayout cell now which seems okay.
(I’ve used TextWrap.jl btw to have the text wrapped to a fixed width)

Now - of course - the background boxes size is not linked to the size of the text. So what I would like to do is adjust to Box to the content. I know I will have to program the logic myself… that’s fine!

But my problem is… how do I determine the actual size of a Label?
The attributes for width and height only give the current setting as Auto(true,1.0f0) but no actual values.
In the end I would for example like to override the height of the Box with a Fixed() value (instead of Auto()) according to the current absolute height of the text Label. Is there any way to access this???

I found some mentioning of bounding boxes somewhere and there exists GLMakie.BBox in the package (though it might be a deprecated concept already?).

So … any ideas how to get the current bounding box (or similar) of a Label (or Box or Button or any other layoutable element, for that matter) at it’s current displayed size ?

I know one way would be to create the whole GridLayout with Fixed() sizes from the beginning, but then you loose all the nice rescaling features. I don’t see why it shouldn’t be possible to obtain the current absolute size of an element even though it’s size is in auto-scaling mode. Are these values really just calculated on-demand and then thrown away?

Hm usually the Label should already compute its own size, and be able to shrink rows / columns of the parent GridLayout accordingly. Can you post the full code for both Label and Box so I can check if you’re doing something that you shouldn’t be?

You’re absolutely right, I’m sorry.

I had set tellheight=false for the Label earlier and forgot to remove it. So that makes the layout cell’s (and background Boxes’) height adapt automatically when the text changes. Quite the behaviour I was looking for, I think.

Still leaves - for the sake of curiosity - the question if there is in principle a way to access absolute element/row/column sizes or if this is just not part of the GridLayout concept and therefore not possible.
Coming from a MATLAB or matplotlib background I am used to the fact that autosizing objects still have absolute pixel sizes stored somewhere in their attributes, which get updated on resizing.

Anyway: this is the code at the moment. Always happy for good advice :slight_smile:

fig = Figure(resolution=(1280,720)); display(fig);
leftPane = fig[1:2,1] = GridLayout()
rightTopPane = fig[1,2] = GridLayout()
rightBottomPane = fig[2,2] = GridLayout()

# setup axes
ax1 = Axis(rightTopPane[1,1])
ax2 = Axis(rightTopPane[2,1])
ax3 = Axis(rightBottomPane[1,1])

# setup interactive elements/widgets
ghs = Dict() # Dictionary containing gui widgets
ghs["slider1"] = Slider(rightBottomPane[2,1],range=-10:1:10,startvalue=0)
ghs["btnOpenTSFolder"] = Button(leftPane[1,1],label="Open a file...")
ghs["btnCalTS"] = Button(leftPane[3,1], label="Do Something!")
ghs["btnTest"] = Button(leftPane[4,1],label="Do Something Else!")
ghs["txtBkg"] = GLMakie.Box(leftPane[2,1])

mystr="This is a longer text which is supposed to be wrapped in the text box. It may, however, contain linebreaks in the original text.\n
These linebreaks\n
should be preserved.\n
\n    
Also it contains one veryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy long word!!"

ghs["txtTest2"] = GLMakie.Label(leftPane[2,1],wrap(mystr,width=20,replace_whitespace=false))

Using the dictionary here only to be able to pass all GUI handles as a whole later.

Yeah the size is in the label.layoutobservables struct, it’s just not public API

And by the way, Label has a padding field with which you can pad it against the borders of the Box

Yeah the size is in the label.layoutobservables struct, it’s just not public API

Good morning

Yes!! That’s exactly what I was looking for. Thank you! :slight_smile:

I see you should avoid accessing these “hidden” attributes whenever auto-behaviour is possible. But there are scenarios for specific GUI behaviour where you just want to know how big something is in absolute boundingbox screen pixel size.

THX :slight_smile: