Ren'Py [SOLVED]ToggleDict in a loop

GoldenD

Member
Sep 30, 2018
102
70
Code first, explain following

Python:
default _var        = None
default _counter    = 0
default list_select = dict()

label start:
    python:
        for _var in listOfSpells:
            store.list_select[_var.id] = False
    call screen setupHero(listOfSpells, maxItems=5)

screen setupHero(listOf, maxItems=1):
    modal True
    zorder 200
    add "gui/overlay/confirm.png"
    add "gui/setup.png" pos (800, 100)  size (950,600)

    use displayItems(listOf)

    textbutton _("Ok")      action [Return(True), With( dissolve)]      xpos 950 ypos 610
    textbutton _("Cancel")  action [Rollback(),With( dissolve)]         xpos 1500 ypos 610

    ## Right-click and escape answer "no".
    key "game_menu" action [Rollback(),With( dissolve)]

screen displayItems(listOf):
    $ _var  = 0
    $ _xpos = 860
    $ _ypos = 220
    for _var in range(len(listOf)):
        textbutton listOf[_var].name xpos _xpos ypos _ypos:
            action [ToggleDict( list_select, _var, True, False ), updateCounter()]
            style "checkbox_button"
            hovered ShowTransient("ttSelectItems", msg=listOf[_var].description)
            unhovered Hide("ttSelectItems")
        $ _ypos += 35

    # For debug
    text "{color=#ffffff}_counter = [_counter] {/color}"
   
python:
    def updateCounter():
        store._counter = 0
        for _var in store.list_select:
            if store.list_select[_var] == True:
                store._counter += 1
Goal is to have list of textbutton which represents list of spells (for sample). you can choose 5 out of 10 by clicking the textbutton.
Clicking textbutton should changed font of button and particularly increase _counter
What happened here :
at beginning, all datas in list_select are false, normal. But when you click one button, all datas are assigned to True when only the one that is clicked takes the good style "checkbox_button".

So, action seems to be executed for each elt in the loop, while rest of textbutton is correctly assign at the only one I click.
Why, why, why ? An idea ?
 
Last edited:

Rich

Old Fart
Modder
Donor
Respected User
Game Developer
Jun 25, 2017
2,566
7,384
So, action seems to be executed for each elt in the loop, while rest of textbutton is correctly assign at the only one I click.
Why, why, why ? An idea ?
I think at least part of your problem is the use of updateCounter. In your textbutton action, I think you want "updateCounter" not "updateCounter()". You're calling the function when the textbutton is being set up - you want the call to only happen when the button is pushed.

The reason you see Ren'py actions with parentheses is that the actions are actually classes, so the declaration is creating and returning a Python object that is later "called" when the action is performed. Essentially, an action has to be a Python "callable." A function is a callable, so what you want to do is to give the textbutton just the name of your function, and let it be called later. Instead, your current code is calling it as part of setting up the list of actions, and not returning anything that can then be treated as an action.

So, yes, your updateCounter function is being executed each time through the loop, because that's what you told Ren'py to do...
 

GoldenD

Member
Sep 30, 2018
102
70
I think at least part of your problem is the use of updateCounter. In your textbutton action, I think you want "updateCounter" not "updateCounter()". You're calling the function when the textbutton is being set up - you want the call to only happen when the button is pushed.

The reason you see Ren'py actions with parentheses is that the actions are actually classes, so the declaration is creating and returning a Python object that is later "called" when the action is performed. Essentially, an action has to be a Python "callable." A function is a callable, so what you want to do is to give the textbutton just the name of your function, and let it be called later. Instead, your current code is calling it as part of setting up the list of actions, and not returning anything that can then be treated as an action.

So, yes, your updateCounter function is being executed each time through the loop, because that's what you told Ren'py to do...
Ok, I began to test, there is a change. I'll clear my code and use less confused variables and will do others tests with your notice. I'll come back with results.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,979
16,236
As additional answer to what Rich said, here's more in depth explanation of the difference between something() and something.

Just don't care of the TL;DR part, in your particular case, it's the opposite ;)
 
  • Haha
Reactions: GoldenD

GoldenD

Member
Sep 30, 2018
102
70
Ok guys,
cleaning code and reading your notice, all is fine for this part. Bottom, the code "cleaning" and working.
Python:
# default _var            = None

init python:
    class Item:
        def __init__(self, id, name=""):
            self.id             = id
            self.name           = name

    def updateCounter():
        store.counterSelected = 0
        for eltSelect in store.listSelected:
            if store.listSelected[eltSelect] == True:
                store.counterSelected += 1

define listItems       = [(Item(0, name="Item01")), (Item(1, name="Item02")), (Item(2, name="Item03")), (Item(3, name="Item04")), (Item(4, name="Item05"))]
default listSelected    = dict()
default counterSelected = 0
define MAX_SELECT       = 3

label test():

    python:
        for _var in listItems:
            store.listSelected[_var.id] = False

    call screen selectItems(listItems)


screen selectItems(listOf):
    modal True
    zorder 200
    add "gui/overlay/confirm.png"
    add "gui/setup.png" pos (800, 100)  size (950,600)

    use displayItems(listOf)

    textbutton ("Ok")      action [Return(True), With( dissolve)]   xpos 950 ypos 610
    textbutton ("Cancel")  action [Rollback(), With( dissolve)]    xpos 1500 ypos 610

    key "game_menu" action [Rollback(),With( dissolve)]

screen displayItems(listOf):
    $ _xpos = 860
    $ _ypos = 220
    for eltItems in range(len(listOf)):
        textbutton listOf[eltItems].name xpos _xpos ypos _ypos:
            action [ToggleDict( listSelected, eltItems, True, False ), Function(updateCounter)]
            # if store.counterSelected != MAX_SELECT:
            style "displayItems_button"

        $ _ypos += 35

    # For debug
    text "{color=#ffffff}counterSelected = [counterSelected] {/color}"

style displayItems_button is button
style displayItems_button_text is button_text:
    idle_color              "#000000"       # BLACK NORMAL
    hover_color             "#ffffff"       # WHITE HOVER
    selected_idle_color     "#550001"       # RED   SELECTED
    selected_hover_color    "#550001"       # RED   SELECTED
Note for newbies like me:
if you try this code without change, the Cancel button will be insensitive because not possible Rollback. If you add "Hello" before calling screen, Cancel will be active. (no doubt obvious to the majority, I just spent time reviewing all my styles to understand).

And like always, a Great THANKS everybody.