Automatic resize area to fit a changing text is possible?

Chantajista

Newbie
May 28, 2019
91
341
150
Hello

I want an area of a frame to automatically resize to fit a given text.

I'd like to be able to set the X, Y, and width values. And have the height automatically change to accommodate the text as it changes.

Is this possible?

Thank you.

(it is for a code like this)

frame:
area (x,y,width, height)
background Frame("bg.png" , 30, 30, tile=False)
padding (10, 10)
text dialog
 

Chantajista

Newbie
May 28, 2019
91
341
150
Related to this, I am trying to get the height of a text after limiting the width size of the text, but it is not working.
Can someone help me with this?

Thanks.

I do something like this. But the text always returns the size of a single line. Doesn't break the text in several lines to fit the maximum width size.

label test:

$ t = Text("Hello World! Hello World! Hello World!" , xmaxium=200)
$ z = t.size()
"[z]"
pause
return
 

osanaiko

Engaged Member
Modder
Jul 4, 2017
3,437
6,604
707
If you don't specify a size property (or only constrain one axis), in general the screen elements will auto size to contain their largest child.
The element can be made to expand to the maximum size of it's container with xfill or yfill properties.
To allow the an element to expand to have more contents than it's height with a scrollbar then you need to use a viewport.

If you are trying to do complex stuff, Screen element layout is not really easy to understand if you are not used to such UI construction techniques. You need to experiment and slowly change properties/layout while observing the results to understand it. I recommend using 'frame' elements of fixed size to represent your UI components (with colored backgrounds to differentiate them) as the innermost elements, then work in a change-test cycle to setup the parents structure to arrange the layout to your needs. Only after the layout is clear should you try adding images etc or program driven changable size/position/content.
 
  • Like
Reactions: anne O'nymous

Chantajista

Newbie
May 28, 2019
91
341
150
Hello.

Thanks for the help. That is actually what I am trying to do. Do weird things with screens and their elements to see how they work

I am actually doing a test like this.
I am trying to find how to access to the properties of the text element in a frame in a screen.
Can you point me what I should look to learn more about this?
I know what I was trying doesn't works.

Thanks for your time.

screen test(x, y, width, height, f_size, bg, dialog):

$ x = int(x)
$ y = int(y)
$ width = int(width)
$ height = int(height)

frame:
area (x,y,width, height)
background Frame(bg, 30, 30, tile=False)
padding (20, 10)
text dialog size f_size id "txt"

#I know this doesn't work
$txt.text="Change text"
$s=txtsize()



If you don't specify a size property (or only constrain one axis), in general the screen elements will auto size to contain their largest child.
 

osanaiko

Engaged Member
Modder
Jul 4, 2017
3,437
6,604
707
I might have a chance to take a look at this later, gotta rush out now.

One small thing: please put all your code snippets into "[ code ]" formatting blocks, it's necessary to preserve indentation which is important context in Renpy/Python. And it's just easier to read too.

For reference, here are the details of the formatting codes: https://f95zone.to/help/bb-codes/
 
  • Like
Reactions: Chantajista

osanaiko

Engaged Member
Modder
Jul 4, 2017
3,437
6,604
707
Chantajista You might be thinking about how screens and UI elements work in a way that is not consistent with how renpy is designed. You can't "get a reference" to an element, and then manipulate it's properties directly or via method calls.

Renpy's system grew out of it's roots - a way to show custom UI screens in visual novels. It was not designed to be a general purpose UI builder (although skilled users can achieve amazing things), and it does not have programmatically assigned callbacks or the ability to attach event handlers that listen to events.

The UI Elements are assembled in a screen to define the structure of the page.
Each element has "style properties". These properties can be set "inline" in the screen, or can be applied by "style" definitions. You can think of it being a bit like HTML and CSS, but without the concepts of a DOM, Events, or Javascript to automate stuff.

Here is a quick example showing how you can use a screen local variable, an action, and an element "size" style which takes the value of the local variable, and this setup shows how you can change an element's properties dynamically upon user interaction.

Code:
screen text_size_demo():

    default textsize=20

    vbox:
        align(0.5, 0.5)
        pos(0.5, 0.5)
        spacing 50

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            padding(0.1, 0.1)
            text "This is a text in a frame which takes it's size from it's children" size textsize

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            padding(0.1, 0.1)
            xysize(0.3, 0.2)
            text "This is a text in a frame that has a fixed size" size textsize

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            background Color("#AA5")

            textbutton "Make text bigger (click me)":
                text_color "#131"
                action [SetScreenVariable("textsize", textsize + 1)]
You might notice that i'm repeating some "align", "pos" etc. statements over and over - this is a perfect example of where it would be good to use a defined style and apply it to multiple elements, with style_prefix ( )
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
12,934
21,509
1,026
Code:
screen test(x, y, width, height, f_size, bg, dialog):

    $ x = int(x)
    $ y = int(y)
    $ width = int(width)
    $ height = int(height)
Unlike you'll specifically pass string to the screen, there's absolutely no need for those int(...) lines.


#I know this doesn't work
$txt.text="Change text"
$s=txtsize()
There's two reason for this to not works. Firstly because a text screen statement do not have a "text" property. Secondly because id are only valid inside the screen where they are defined.

If you follow what osanaiko already said in his first answer, what you want to do is relatively simple; you just need to not give size to the frame, like he shown in his second post.

Now, if you want to goes further and also change the text displayed, but without actually centering the frame, just adjusting its size, you just need to rely on .
Python:
default textSize = 20
default dialog = ""

screen test( x, y ):
    frame:
        xpos x
        ypos y

        text "[dialog]" size textSize
Just change the value of dialog whenever needed:
Python:
label whatever:
    $ dialog = "First line"
    show test( 100, 100 )
    pause  # mandatory since there's no interaction
    $ dialog = "Second line"
    pause  # mandatory since there's no interaction
    "END"

Then if you want the text centered, but in a portion of the screen (by example, if you vertically split the screen on third, and want the text in the right portion, but centered inside it), you need to put the frame inside a .
Python:
default textSize = 20
default dialog = ""

screen test( x, y, width, height ):

    fixed:
        area( x, y, width, height )

        frame:
            xalign 0.5
            yalign 0.5

            text "[dialog]" size textSize

All this being said, this, as well as osanaika's posts, answer the question as you asked it: "I want an area of a frame to automatically resize to fit a given text."
But there's another valid answer that can possibly fit better the question as you intended it.

background is a valid textbutton property, and said textbutton are none sensitive if they have neither an action nor an alternate property.

Therefore, this also answer your question:
Python:
default textSize = 20
default dialog = ""

screen testScreen(x, y):

    textbutton "[dialog]":
        style "text"  # Use the 'text' style in place of the 'textbutton' one.
        xpos x
        ypos y
        background Frame("bg.png", 30, 30, tile=False)
        padding (10, 10)
        size textSize
What can be simplified a bit through a style definition:
Python:
default textSize = 20
default dialog = ""

style myText is textbutton_text:
        background Frame("bg.png", 30, 30, tile=False)
        padding (10, 10)

screen testScreen(x, y):

    textbutton "[dialog]":
        style "myText"
        xpos x
        ypos y
        text_size textSize
 

Chantajista

Newbie
May 28, 2019
91
341
150
Chantajista You might be thinking about how screens and UI elements work in a way that is not consistent with how renpy is designed. You can't "get a reference" to an element, and then manipulate it's properties directly or via method calls.

Renpy's system grew out of it's roots - a way to show custom UI screens in visual novels. It was not designed to be a general purpose UI builder (although skilled users can achieve amazing things), and it does not have programmatically assigned callbacks or the ability to attach event handlers that listen to events.

The UI Elements are assembled in a screen to define the structure of the page.
Each element has "style properties". These properties can be set "inline" in the screen, or can be applied by "style" definitions. You can think of it being a bit like HTML and CSS, but without the concepts of a DOM, Events, or Javascript to automate stuff.

Here is a quick example showing how you can use a screen local variable, an action, and an element "size" style which takes the value of the local variable, and this setup shows how you can change an element's properties dynamically upon user interaction.

Code:
screen text_size_demo():

    default textsize=20

    vbox:
        align(0.5, 0.5)
        pos(0.5, 0.5)
        spacing 50

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            padding(0.1, 0.1)
            text "This is a text in a frame which takes it's size from it's children" size textsize

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            padding(0.1, 0.1)
            xysize(0.3, 0.2)
            text "This is a text in a frame that has a fixed size" size textsize

        frame:
            align(0.5, 0.5)
            pos(0.5, 0.5)
            background Color("#AA5")

            textbutton "Make text bigger (click me)":
                text_color "#131"
                action [SetScreenVariable("textsize", textsize + 1)]
You might notice that i'm repeating some "align", "pos" etc. statements over and over - this is a perfect example of where it would be good to use a defined style and apply it to multiple elements, with style_prefix ( )
Thanks, That was useful. It gave me something to look at.
 
  • Heart
Reactions: osanaiko

Chantajista

Newbie
May 28, 2019
91
341
150
Thanks, That was useful. It gave me something to look at.
Thanks also. There is something interesting here.

What I am actually trying to figure is how to have a screen "function" with several parameters (x, y position, text, font, size... ) and with a parameter that is a number of lines. And the frame automatically resize to fit the text with the given number of lines.

I have the function work with x,y width and height and it works. But it will save me time if I can just set the number of lines and let renpy calculate width and height.

Trully thanks for both
 

osanaiko

Engaged Member
Modder
Jul 4, 2017
3,437
6,604
707
I don't really understand what you are trying to do.

It's possible to construct "displayables" using Renpy's exposed python functions. There's some examples in the docs, and more if you search deep into the lemmasoft forum posts.

But I'll say it again: I think you are fighting against Renpy, not using it like it is designed to be used.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
12,934
21,509
1,026
But I'll say it again: I think you are fighting against Renpy, not using it like it is designed to be used.
I agree.

The fact that the string argument is named "dialog" make me think about an alternative for "say", but as I implied this will lead to issues due to the lack of interaction.
It would be better to just edit the "say" screen, even if it need to use a say argument to select between the regular dialog box and a custom one. Looking at can also be an option.