Altering UI elements at Runtime [SOLVED]

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Altering UI elements at Runtime [SOLVED]

#1 Post by trooper6 »

Hello!

So I'm working on my first ren'py game. I have no Python experience, but I do have Java experience. I want to change parts of the UI at runtime...and I'm having some trouble with something (well many things).

So here is the set up.

I have made a screen that has some frame and vboxes and a textbutton in them. I want to be able to add dialogue menus to the frames and enable and disable the button during runtime.

I mock up of my renpy code looks like this (a bit simplified):

File: controlscreen.rpy

Code: Select all

screen control:    
    frame:
        id "cframe"
        xalign 1.0
        xpos 1.0 
        yalign 0.0
        ypos 0.0
        
        has vbox:
            id "cfvbox"
            style_group "inner"
            frame:
                id "div1frame"
                add "top small"
            frame:
                id "uppercframe"
                ymaximum 160
                add "clock2" xanchor 0.5 yanchor 0.5
                add "clock" xanchor 0.5 yanchor 0.5
                add "clock1"  xanchor 0.5 yanchor 0.5   
            frame:
                id "div2frame"
                add "top small"
            frame:
                id "midcframe"
                yminimum 0.5
                label _("Control Panel")             
            frame:  
                id "lowercframe"
                has vbox
                textbutton "Interrupt" action [SetVariable ("interrupts", interrupts +1), Return("smth")]
                text "No of interrupts: [interrupts]"
                add "bottom small"
in the script.rpy I want to be able to do things like:

Code: Select all

a "I'm going to give a long speech and you can't interrupt me now"
[color=#4000FF]disable interrupt button[/color]
a "blah blah blah blah"
b "I'm going to give a long speech and you can totally interrupt me anytime"
[color=#4000FF]enable interrupt button[/color]
b "blah blah blah blah"
a "so, you've hear both our proposals, which one person do side with?"
menu: [color=#4000FF]-- showing up in the midcframe[/color]
    "I choose you Alphie!":
        $ alphie_love += 1
    "I choose you Bebe!":
        $ bebe_love += 1
If this were Java, it wouldn't be a problem because I would have declared the Interrupt button as an instance of the button class with a name and then I could do things to it at runtime. Same thing with the frames.
Something like (the grammar will be off, but you'll hopefully understand what I mean.):

*during initialization
controlS = new Screen();
dialogueF = new Frame ();
interruptB = new TextButton("Interrupt");

then during the code part I'd just do this:

Code: Select all

a "I'm going to give a long speech and you can't interrupt me now"
[color=#4000FF]interruptB.setEnabled(false);[/color]
a "blah blah blah blah"
b "I'm going to give a long speech and you can totally interrupt me anytime"
[color=#4000FF]interruptB.setEnabled(false);[/color]
b "blah blah blah blah"
a "so, you've hear both our proposals, which one person do side with?"
dialogueF.addMenu(
    "I choose you Alphie!":
        $ alphie_love += 1
    "I choose you Bebe!":
        $ bebe_love += 1);
I can't figure out how to replicate that sort of thing in Renpy. The text button I created, doesn't seem to have an initialized name, so I don't see how I can access it later. Also, I have no idea if ren'py buttons have an enabled flag...I mean, they should, right? but the documentation doesn't mention it at all. Same with screens/frames/boxes. Where can I find out what properties these elements have? With java all those things are are online in the object definitions...here I can't find it.

Also, where exactly is the menu object defined? I assume that somewhere in there it says to show up on the overlay layer of the game screen(?)...but I want to tell it to show up in the dialogueF instead...how do I talk to it when it doesn't seem to have a name?

So...I know what I want to do...I know how I'd do it in Java, but I don't know how it works in Ren'py/Python. Help?
(For those who say: just write the thing in Java...creating an entire VN engine in java with all the wonderful functionality of Ren'py seems like it would be a real pain, and why reinvent the wheel when something completely awesome is already here!)

Looking in the ren'py folder, it looks like the version of Python we are using is 2.7...so if I want to look up Python tutorials and documentation I should be looking at 2.7 stuff, yes? Also, what is the relationship between Pygame an Ren'py?

Note: while this question is about this specific conundrum that I alluded to in my last post, this one is really about instances of objects in general...how does object oriented programming work in ren'py? How do I know what methods and fields text or imagebuttons or labels etc have?

Thank for any replies! I'm tying to work this out!
Last edited by trooper6 on Tue Jun 18, 2013 11:33 am, edited 1 time in total.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#2 Post by Alex »

Can tell you nothing about objects and all that cool stuff, but you can use an If() action to operate your button

Code: Select all

textbutton "Interrupt" action If(flag_var, [SetVariable ("interrupts", interrupts +1), Return("smth")], None)

label start:
    $ flag_var = True    # you need to set value before your screen that contains the button will be shown

    a "I'm going to give a long speech and you can't interrupt me now"
    $ flag_var = False
    a "blah blah blah blah"
    b "I'm going to give a long speech and you can totally interrupt me anytime"
    $ flag_var = True
    b "blah blah blah blah"
In screens.rpy you can find "screen choice" that is in charge of menus and modify it the way you need.

http://www.renpy.org/doc/html/index.html
http://www.renpy.org/doc/html/screen_ac ... er-actions
http://www.renpy.org/doc/html/screen_sp ... tml#choice

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#3 Post by trooper6 »

You are a superstar Alex...for real! I'm going to try out the Interrupt code, but I have a few questions about it:
1) why is the "If" there capitalized while if in other parts of Ren'py code is not capitalized?
2) I assume the None in the If(flag, do something, None) is what to do if the flag_var is false? Can I change styles for the button in the none? So that the button is greyed out if the flag_var is false? What would be the command to change the color/style of the button?

oh...why are you declaring your instances in the start block and not before when you declare your images?
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#4 Post by trooper6 »

Okay back to my buttons...I'm having a problem getting my variables to change.

in my script file I have:

Code: Select all

image bg barbershop1 = "00 images/00BackgroundBarbershop2.jpg"
image ctc = "00 images/WArrow75.png"
image ctcH = "00 images/WArrow75blue.png"

init python:
    def arrow(event, **kwargs):
        if event == "show" or event == "begin":
            can_interrupt = True
            can_cont = False
            renpy.music.play("00 sounds/click.wav", channel="sound") #this is for testing purposes
        if event == "slow_done" or event == "end":
            can_interrupt= False
            can_cont = True
            renpy.music.play("00 sounds/punch.wav", channel="sound") #this is for testing purposes
        
init:
    $ n = Character(None, what_italic=True, callback=arrow)
    $ b = Character('Barber', color="#99FFFF", what_slow_cps=20, what_slow_abortable=False, callback=arrow)
    $ c = Character('Customer', color="#FF9966", callback=arrow)
                    
init -2:
    $ config.keymap["dismiss"] = None

# The game starts here.
label start:    
            
    #variables
    $ interrupts = 0
    $ can_interrupt = True
    $ can_cont = True
 
    scene bg barbershop1:
    show screen control
      
    n "The scene is a barber shop. At the center is the chair, facing a mirror and washstand at the right. 
     The tiled walls are sprinkled with the usual advertisements. At the rear, a door leads up to the street 
     by a flight of two or three steps. A clock on the left wall indicates three."
    
    n "At the rise of curtain, THE BARBER, a man of fifty, is discovered sharpening a razor, and whistling 
     softly to himself. He finishes with the razor; seats himself in the chair, takes up a paper, and reads."
    
    n "The door opens, and THE CUSTOMER, a flashily-dressed individual of forty-five, enters the shop."

    $ can_interrupt = False
    $ can_cont = False    
    menu:
        "Give me a shave and make it quick, I don't have much time!":
            $ interrupts += 1
        "My good man, do you have time to do a very quick shave?.":
            $ interrupts -= 1
    $ can_interrupt = True
    $ can_cont = True  
In my control screen file I have my two buttons defined:

Code: Select all

init:
    image top small = im.Scale("00 images/00TopBar412x17.png", 150, 6)
    image bottom small = im.Scale("00 images/00BottomBar427x16.png", 150, 6)

    image clock = im.Scale("00 images/clock.png", 150, 150)
    image clock1 = im.Scale("00 images/clock_1.png", 150, 150)
    image clock2 = im.Scale("00 images/clock_2.png", 150, 150)

screen control:   
    frame:
        style_group "game"
        id "cframe"
        xalign 1.0
        xpos 1.0 #1024
        yalign 0.0
        ypos 0.0
        
        has vbox:
            id "cfvbox"
            style_group "inner"
            frame:
                id "div1frame"
                #yminimum 0.2
                add "top small"
            frame:
                id "uppercframe"
                ymaximum 160
                add "clock2" xanchor 0.5 yanchor 0.5
                add "clock" xanchor 0.5 yanchor 0.5
                add "clock1"  xanchor 0.5 yanchor 0.5   
            frame:
                id "div2frame"
                add "top small"
            frame:
                id "midcframe"
                #yminimum 0.5
                yminimum 300
                label _("Control Panel")             
            frame:  
                id "lowercframe"
                has vbox
                textbutton "Interrupt" action If(can_interrupt, [SetVariable ("interrupts", interrupts +1), Return("smth")], None)
                text "No of interrupts: [interrupts]"
                text "Can Interrupt: [can_interrupt]"
                add "bottom small"
                imagebutton:
                    idle "ctc"
                    hover "ctcH"
                    action If(can_cont, Return("smth"), None)

init -2 python:
    style.game_frame.background = Frame("00 images/00Intertitle2_64x71.png", 64, 71)
    style.game_frame.xmargin = 10 
    style.game_frame.ymargin = 20
    style.game_frame.ypadding = 35
    style.game_frame.xminimum = 250
    style.game_frame.yminimum = 768
    style.game_frame.xmaximum = 250
    style.game_frame.ymaximum = 768
    
    style.inner_frame.background = None
Okay so when I run the game, what happens?

The audio parts of the callback work. When the text starts I get the click audio, when it ends I get the punch audio. So I know that that part of the callback works. Further, changing the flags from within the start block with direct statements works. It changes my flags, which changes my labels, disables and then enables my buttons.

But, the lines in the callback changing the flags don't do anything. The flags stay unchanged. The game doesn't crash...the flags, and therefore the buttons, just don't change at all.

So what am I doing wrong with my callback? Why does playing audio work but flag changing doesn't? Does it have to do with the order things are done? In which blocks things are placed?

As for the choice menu thing...I can see how I can go into the options file and change the aesthetic of the menu, but I don't see how I can make it a child of the frame that is part of another screen. Perhaps that isn't possible? Would I have to make a choice menu class that then could be added to a specific frame?

Anyway, thanks for all the help so far everybody.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

Anima
Veteran
Posts: 448
Joined: Wed Nov 18, 2009 11:17 am
Completed: Loren
Projects: PS2
Location: Germany
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#5 Post by Anima »

Scope. The variables inside the function are not the same as the variables in the label. Either pass as parameter or use globals.
Avatar created with this deviation by Crysa
Currently working on:
  • Winterwolves "Planet Stronghold 2" - RPG Framework: Phase III

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#6 Post by trooper6 »

So I changed my function by adding global variables (I think), like so (let me know if that isn't how you do global variables):

Code: Select all

init python:
    def arrow(event, **kwargs):
        global can_interrupt
        global can_cont
        if event == "show" or event == "begin":
            can_interrupt = True
            can_cont = False
            renpy.music.play("00 sounds/click.wav", channel="sound")
        if event == "slow_done" or event == "end":
            can_interrupt = False
            can_cont = True
            renpy.music.play("00 sounds/punch.wav", channel="sound")
But it still isn't working right. I still get both audio sounds playing, letting me know that both if blocks are activating through call backs, but the variables stay at can_interrupt = True, and can_cont = False.

So maybe I should try the pass as parameter version? How would I do that?
But I feel like the the global variable thing should work. Am I doing something wrong in my callback?

I feel like I should set some sort of debugging thing...print to console so I can see exactly which of the events are firing...but I can't quite see how to print to console.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#7 Post by trooper6 »

Some more data for those who might be in the know. I tried this variation on the above, I added the "or event == "show_down": to my second if block, like so:

Code: Select all

init python:
    def arrow(event, **kwargs):
        global can_interrupt
        global can_cont
        if event == "show" or event == "begin":
            can_interrupt = True
            can_cont = False
            renpy.music.play("00 sounds/click.wav", channel="sound")
        if event == "slow_done" or event == "end" or event == "show_done":
            can_interrupt = False
            can_cont = True
            renpy.music.play("00 sounds/punch.wav", channel="sound")
In this code, the punch sound plays at the beginning and end and I only get: can_interrupt= False and can_cont = True.

How the heck do I get this to work right!
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#8 Post by apricotorange »

I'm pretty sure you want to check "if event == 'show' or event == 'begin' or event == 'show_done':" or something like that.

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime (Declaring Instances?)

#9 Post by trooper6 »

Hm...that didn't work either.

So this is what I did. I took the callback off of the Customer and the Narrater and left if on the Barber. I had the default can_Interrupt = False, and the default can_cont = True.

In this instance, everything is good until we get to the barber. He starts his slow text and the Interrupt button goes on and the continue button goes off and the click sound plays. So far so good. Then we get to the end of the slow_text and the punch sound goes off, but, as far as I can tell, nothing else happens. But then I thought...maybe something *is* happening. So I checked the variable viewer in the developer's screen. And sure enough, even though the screen hadn't changed, the variables had changed. So I figured I just needed to figure out a way to reload the screen. A bit of googling here in the forums produced:

renpy.restart_interaction()

So I did this:

Code: Select all

init python:
    def arrow(event, **kwargs):
        global can_interrupt
        global can_cont
        if event == "show" or event == "begin":
            can_interrupt = True
            can_cont = False
            renpy.music.play("00 sounds/click.wav", channel="sound")
        if event == "slow_done" or event == "end":
            can_interrupt = False
            can_cont = True
            renpy.music.play("00 sounds/punch.wav", channel="sound")
            renpy.restart_interaction()
And it works like a dream! So that part of the coding is finished!
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

apricotorange
Veteran
Posts: 479
Joined: Tue Jun 05, 2012 2:01 am
Contact:

Re: Altering UI elements at Runtime [SOLVED]

#10 Post by apricotorange »

Ah, yes, that's the right solution.

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Altering UI elements at Runtime [SOLVED]

#11 Post by Alex »

Well, I'm soo slooow, but if you still interested...
1) if - is a python statement and If() - is an action in screen language (http://www.renpy.org/doc/html/quickstar ... statements / http://www.renpy.org/doc/html/screen_ac ... er-actions)
2) if you set the action for button as None then it will be insensitive and will change its appearence according to preset style (there is a tutorial that explains the usage of styles - http://lemmasoft.renai.us/forums/viewto ... f=8&t=9812)
3) Declaring vars in start label guarantees that they will be properly saved (see also - http://www.renpy.org/doc/html/save_load_rollback.html)

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Altering UI elements at Runtime [SOLVED]

#12 Post by trooper6 »

Alex, thanks for the info. About answer #3. That is really interesting...so I want to ask, should a person initialize all variables inside the start block? When would you want to save variables outside of the start block?
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
Alex
Lemma-Class Veteran
Posts: 3093
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Altering UI elements at Runtime [SOLVED]

#13 Post by Alex »

Ahem, actually, that was an advise from PyTom to set vars in label start. You could try and see if some of your vars will be overwritten or something if you set them in init block, save game and restore it.

Post Reply

Who is online

Users browsing this forum: Andredron