Custom user interface

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.
Message
Author
User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#16 Post by PyTom »

Yeah, I slipped the new demo back to 5.6.2, since I want people to have a stable version of 5.6 to work with.

Of course, the sooner I can see the backgrounds, the better. :-)
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#17 Post by monele »

Ok, I'm having troubles with the "hovered" and "unhovered" parameters of buttons. What I'm trying to do :

Have a bunch of buttons generated from a list and placed on screen (OK).
Have these buttons clickable and return a unique result for each of them (their ID)... (OK).
Have the interface react to hovering each of them and display a unique text for each of them (NOT OK ^^;...).

The concrete example of what I'm trying to do is : a map, locations on the map (imagebutton) that you can either click (=goto) or just hover (displays name of location or detailed infos).
The main problem is that you define "hovered=somefunction". Except that function has no way to know which button called it. I wish something like "hovered=somefunction(ID)" would be possible but it's not. I could also have "somefunction()" get its caller afterwards... something like "self.ID", but self isn't not accessible and I'm pretty sure I can't set ID anyway :/...

I know you mentioned DynamicDisplayable but it only changes styles, not text.

Any idea ? :/

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#18 Post by PyTom »

Well, DynamicDisplayables can change Displayables as well as styles. So I'm not sure what you mean by that.

Ren'Py does not need to support passing default data to functions... this is Python, not C++. There are a couple of ways you can get default data to functions that need it.

The first is to use bound methods. In Python, when one takes a reference to a method on an object, a callable is created that remembers both the object and the method. So one can do (in straight python):

Code: Select all

class Foo(object):
    def __init__(self, a):
         self.a = a

    def bar(self):
         print self.a       

o = Foo(42)
bound_method = o.bar

# ....

bound_method()
And it will print out 42.

Another way is to create a new function, with default values for some of its parameters. This is the way I'd recommend solving your problem:

Code: Select all

label splashscreen:
    python hide:

        store.hovered_text = ""

        def mybutton(text, hovered_text, clicked):

            def hovered(hovered_text=hovered_text):

                if store.hovered_text == hovered_text:
                    return

                store.hovered_text = hovered_text
                renpy.restart_interaction()
                return None

            
            ui.textbutton(text, hovered=hovered, clicked=clicked)

        ui.vbox()
        ui.hbox()
        mybutton("Foo", "You're hovering the foo button.", ui.returns(1))
        mybutton("Bar", "You're hovering the bar button.", ui.returns(2))
        mybutton("Baz", "You're hovering the baz button.", ui.returns(3))
        ui.close()

        ui.add(DynamicDisplayable("Text(store.hovered_text)"))
        ui.close()

        ui.interact()
I suggest doing this inside a python hide, to prevent the newly-created functions (the different variants of hovered) from leaking into the main namespace, and preventing loading and saving. It's not necessary in this case, but it can't hurt.

You can also do this using closures, which accomplish roughly the same thing without as much typing. (But with a larger dose of magic.)
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#19 Post by monele »

I see ^.^. I haven't looked that much into Python (except for basic list and dictionaries stuff) so I wasn't aware of these possibilities.
I didn't think about making object-specific functions this way, in particular ^.^. I'll try this soon :). Thanks a lot.

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#20 Post by PyTom »

Yeah, python is big on it's first-class functions and bound methods. So you use things like closures, bound methods, and default arguments quite a bit, where in a language like C you need a way of supplying data (traditionally, a void *) to the callback function.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#21 Post by monele »

Still quite confusing ^.^...

Ok, I tried and am facing a problem already (*sigh*)... See, I defined a "displayMap" function in some "map.rpy" file. This is the one looping through available locations and displaying them.
According to your tip, it now tries to call this "mybutton"-type function to generate the hoverable buttons.
Last thing : I'd call displayMap from quite anywhere in the game.

Problem : mybutton should be in a python hide block... displayMap should too, then... and could still access the location list with "store.locations"... but now, I can't call displayMap since it's defined and then destroyed (at least I suppose that's the concept of python hide ?) without having been used once.
So uh... can anything declared in python hide block be called from "outside"? ô_o...

I can see a possible workaround : define a label in my game (displaymap) that would contain all this python hide block (definitions and use of functions)... then call it from anywhere in the game.
It means the whole thing will be generated on the fly, executed, and sent back to the abysses, right ?


EDIT : The workaround works but this means that I'll have to copy paste my hover functions a *lot* :/... I'm still eager for a cleaner solution ^^;

And an additional question : can imagebutton accept Displayable instead of just filenames ? *thinking of animated, hoverable imagebuttons >.>...*

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#22 Post by PyTom »

There's no need to use python hide inside an init block. It's only during game execution (when things defined or changed will be saved) that it matters.

The answer is no on ui.imagebutton, but there's no good reason for that. It's just that it currently restricts its inputs to images. I'll fix that in 5.6.2.

In the meantime, you can fake it.

Code: Select all

ui.button(background=anim1, hover_background=anim2, clicked=click_func)
ui.null(100, 200)
The idea is to make a generic button with two displayables as backgrounds, and then put a null inside it so it becomes the appropriate size.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#23 Post by monele »

Only at execution ? Coooool~ X3... Well all these functions will clearly be created on init... except... *thinks*... this means mybutton() doesn't need to be in a hide, but... mybutton creates functions when called... so... if mybutton is called at runtime... are the created functions added to store ? :/

I also read something about local/global variables. Putting "i=1" in a function, for example, means i becomes a new local variable, even if "i" already exists in the global scope. Can it be used in our case to select what should be local and what shouldn't ?

ui.imagebutton : Okay, good ^.^. It was strange that they were the only ones not allowing animation :). And ohh, ui.null accepts size ? XD... So many hidden features ^^;. I'll really have to fill the wiki once I get the hang of all these :).
Thanks again for your help. I know you didn't mean Ren'Py to be used for RPGs (that's not what I'm doing though) but there really is lots of possibilities for such things. And it's not even that hard to make it seems. There's just one thing I see as impossible : realtime action. But anything with a windowed interface seems ok.

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#24 Post by monele »

Just a side note before the main dish : "ui.null(100,200)" doesn't work. ui.null doesn't accept any argument.

Now to the main problem :

Code: Select all

label mmenu:

    scene mainmenu with Dissolve(0.2)
    
    show ttMainmenu at MoveEase((0.5,0.0), (0.5,0.1), 0.5, mode="out", xanchor="center", yanchor="center")
    
    $ renpy.transition(dissolve)   # randomly crashes ren'py when clicking on either imagebutton
    
    
    $ ui.hbox(spacing=20, xpos=0.5, ypos=0.5, xanchor="center", yanchor="center")
    
    $ ui.imagebutton("bAssign.png", "bAssign_sel.png", clicked=ui.jumps("assign"))
    $ ui.imagebutton("bBrew.png", "bBrew_sel.png", clicked=ui.jumps("brew"))
    $ ui.imagebutton("bStatus.png", "bStatus_sel.png", clicked=ui.jumps("status"))
    
    $ ui.close()
    
    $ ui.frame(xpos=0.5, xanchor="center", ypos=0.75, style="banner", xmaximum=400)
    
    $ ui.text("Please choose an activity...", style="banner")
    
    $ ui.frame(xpos=0.7, ypos=0.90)
    
    $ ui.textbutton("Sortir...", clicked=ui.jumps("intro"))
    
    
    $ ui.interact()
    
#
See the renpy.transition ? It makes Renpy crash with this :

Image

when I click on one of the three image buttons. Sometimes it's immediate... sometimes not... Very weird.

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#25 Post by PyTom »

Hm... does the crash happen when you get rid of the MoveEase? There's a slightly different (and slower) codepath that is used when Dissolve has to deal with a changing screen. But it shouldn't crash.

Any debugging information created would be appreciated... check the Event Log for details.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#26 Post by monele »

It happens with the MoveEase commented too.

Event log ?... uh.... where ? ^^;

User avatar
PyTom
Ren'Py Creator
Posts: 16088
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

#27 Post by PyTom »

Um... the event log is a windows thing. I'm not sure where it is... could someone help out.

Also, if you could send me a test case, I could try to debug it.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#28 Post by monele »

Here is the game folder...
Attachments
game.rar
(668.81 KiB) Downloaded 87 times

Jake
Support Hero
Posts: 3826
Joined: Sat Jun 17, 2006 7:28 pm
Contact:

#29 Post by Jake »

PyTom wrote:Um... the event log is a windows thing. I'm not sure where it is... could someone help out.
Control Panel -> Administrative Tools -> Event Viewer

Of course, you have to be logged in as an administrative user to do this.
Server error: user 'Jake' not found

monele
Lemma-Class Veteran
Posts: 4101
Joined: Sat Oct 08, 2005 7:57 am
Location: France
Contact:

#30 Post by monele »

Hmmm.... doesn't seem to generate anything ô_o;...
(thanks Jake ^^)

Post Reply

Who is online

Users browsing this forum: haitai