Ren'Py Where do I go wrong with persistence in this gallery implementation?

EviteGames

Newbie
Sep 29, 2020
58
1,133
Hey!

Last night, another dev asked me to take a look at his gallery implementation, as he is not as experienced in coding and was only following a tutorial. The basic implementation was pretty lacking, and relied only on Ren'Py's 'has seen image' function, so the gallery items unlocked automatically, if an image was seen during gameplay.

His specification was that the gallery elements should be manually unlockable by him, in his code.

I modified his original solution and cleaned up the code a bit. I'm a software engineer by discipline but I'm not super well versed with the Ren'Py SDK and Python stuff. I mainly work with Kotlin, Java and C#.

The solution turned out to be the following:

First, a GalleryElement class which is the basic model of every single element in the gallery. It also holds the "unlock" function and the is_locked variable to define its locked state.

Python:
# The GalleryElement class is the basic model of a single element in the gallery
init python:
    class GalleryElement:
        def __init__(self, item_name, image_list, available_thumbnail, locked_thumbnail="default_locked_thumbnail"):
            self.item_name=item_name
            self.image_list=image_list
            self.available_thumbnail=available_thumbnail
            self.locked_thumbnail=locked_thumbnail
            self.is_locked = True

        def unlock(self):
            self.is_locked = False
After that, we have a few utility methods for resizing the images (so that there is no need for separate image sizes for thumbnails and the high res image). Additionally, it holds the "unlock_gallery_element" method which should be called from... wherever... to unlock a GalleryElement:

Python:
# This file is responsible for holding utility methods connected to the gallery features.
init python:
    def max_scale(image, min_width=config.screen_width, min_height=config.screen_height):
        current_width, current_height = renpy.image_size(image)
        x_scale = float(min_width) / current_width
        y_scale = float(min_height) / current_height

        if x_scale > y_scale:
            max_scale = x_scale
        else:
            max_scale = y_scale

        return im.FactorScale(image, max_scale, max_scale)

    def min_scale(image, max_width=config.screen_width, max_height=config.screen_height):
        current_width, current_height = renpy.image_size(image)
        x_scale = float(max_width) / current_width
        y_scale = float(max_height) / current_height

        if x_scale < y_scale:
            min_scale = x_scale

        else:
            min_scale = y_scale
            
        return im.FactorScale(image, min_scale, min_scale)

    def unlock_gallery_element(item_name):
        next((i for i in gallery_elements if i.item_name == item_name), None).unlock()
After that, we have the screen definitions for the Gallery and "gallery closeup" screens:

Python:
init python:
    GALLERY_WIDTH = 2
    GALLERY_HEIGHT = 2
    GALLERY_ELEMENT_WIDTH = config.screen_width / (GALLERY_WIDTH + 1)
    GALLERY_ELEMENT_HEIGHT = config.screen_height / (GALLERY_HEIGHT + 1)
    MAX_ELEMENTS_PER_PAGE = GALLERY_WIDTH * GALLERY_HEIGHT
    current_gallery_page = 0
    current_closeup_page = 0

screen Gallery():
    tag menu
    add "black_background"

    $start = current_gallery_page * MAX_ELEMENTS_PER_PAGE
    $end = min(start + MAX_ELEMENTS_PER_PAGE - 1, len(gallery_elements) - 1)

    # Create a grid for the images
    grid GALLERY_WIDTH GALLERY_HEIGHT:
        xfill True
        yfill True

        for i in range(start, end +1):
            if gallery_elements[i].is_locked:
                add gallery_elements[i].locked_thumbnail:
                    xalign 0.5
                    yalign 0.5
            else:
                imagebutton idle gallery_elements[i].available_thumbnail:
                    action Show("gallery_closeup", dissolve, gallery_elements[i].image_list)
                    xalign 0.5
                    yalign 0.5

        for i in range(end +1, start + MAX_ELEMENTS_PER_PAGE):
            null

    # Create a grid for the image titles
    grid GALLERY_WIDTH GALLERY_HEIGHT:
        xfill True
        yfill True

        for i in range(start, end + 1):
            hbox:
                spacing GALLERY_ELEMENT_WIDTH - 70
                xalign 0.5
                yalign 0.1
                $item_name = gallery_elements[i].item_name
                text "[item_name]"

        for i in range(end - start + 1, MAX_ELEMENTS_PER_PAGE):
            null

    # Add the 'Previous' and 'Next' buttons
    if current_gallery_page > 0:
        textbutton "Previous":
            action SetVariable("current_gallery_page", current_gallery_page - 1)
            xalign 0.1
            yalign 0.98
    if (current_gallery_page + 1) * MAX_ELEMENTS_PER_PAGE < len(gallery_elements):
        textbutton "Next":
            action SetVariable("current_gallery_page", current_gallery_page + 1)
            xalign 0.9
            yalign 0.98
    #Return Button
    textbutton "Return":
        action Return()
        xalign 0.5
        yalign 0.98

screen gallery_closeup(images):
    modal True
    add images[current_closeup_page] at truecenter

    if current_closeup_page > 0:
        textbutton "Previous":
            action SetVariable("current_closeup_page", current_closeup_page - 1)
            xalign 0.1
            yalign 0.98
            background "black_background"
    if current_closeup_page < len(images) - 1:
        textbutton "Next":
            action SetVariable("current_closeup_page", current_closeup_page + 1)
            xalign 0.9
            yalign 0.98
            background "black_background"

    textbutton "Return":
        action [SetVariable("current_closeup_page", 0), Hide("gallery_closeup", dissolve)]
        xalign 0.5
        yalign 0.98
        background "black_background"
The last file is supposed to hold everything related to the GalleryElements. I used constant variables for the name definitions since I wanted to implement compile safety.

Python:
# Define the names of the gallery items. These names will be used to unlock them and to display the name of the item as well.
define GALLERY_ITEM_NAME_1 = "Space & K/DA"
define GALLERY_ITEM_NAME_2 = "Maid Service"
define GALLERY_ITEM_NAME_3 = "Portrait of a girl"

# Declare the high resolution gallery images that are shown close-up when clicked on the image
image gallery_img_1 = max_scale("gallery/gallery_img_1.jpg")
image gallery_img_1b = max_scale("gallery/gallery_img_1b.jpg")
image gallery_img_2 = max_scale("gallery/gallery_img_2.jpg")
image gallery_img_3 = max_scale("gallery/gallery_img_3.jpg")

# Declare the lower resolution thumbnails images that are shown in the gallery
image gallery_thumbnail_1 = min_scale("gallery/gallery_img_1.jpg", GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)
image gallery_thumbnail_2 = min_scale("gallery/gallery_img_2.jpg", GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)
image gallery_thumbnail_3 = min_scale("gallery/gallery_img_3.jpg", GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)

# Miscellanious declarations such as the default locked thumbnail, gallery background, etc.
image black_background = "#000"
image default_locked_thumbnail = min_scale("images/scene2/lockedaf1.jpg", GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)

# This block is responsible for declaring the elements which should be available in the gallery
init python:
    gallery_elements = []
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_1,["gallery_img_1", "gallery_img_1b"],"gallery_thumbnail_1"))
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_2,["gallery_img_2"],"gallery_thumbnail_2"))
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_3,["gallery_img_3"],"gallery_thumbnail_3"))
And that's about it. It works like a charm! Well, that is UNTIL you close the game. If you open it up again. you just lost all the unlockables' states.

And I can't figure out why. Since I define the gallery_elements = [], shouldn't that be a persistent solution? Shouldn't it hold and save the state of all the elements inside that list?

I'm a bit confused and I'd appreciate some help figuring this out. For a while I thought the issue is that the GalleryElement's constructor defines the is_locked variable automatically. But it can't run again if I open up the game. That doesn't seem right.

What I'd like to avoid is having to create a seperate variable for each GalleryElement to track its locked/unlocked state.

Thank you for reading and thank you for the help!
 
Jul 22, 2019
247
369
Don't have much experience with Ren'py but looking at the documentation, it seems you need to use something like

Code:
default persistent.gallery_elements = []
Add this line before the start label. And then afterwards Ren'py will save any changes to this variable persistently. Basically Ren'py treats all variables associated with this "persistent" object as persistent data.

Again I might be wrong haven't tested this out.

 
Last edited:

DelinquentProductions

Degenerate
Game Developer
Oct 24, 2020
135
892
I think your compilation safety measures are actually working against you here. There may also be some weirdness if you haven't started the game but are unlocking things. Pulling from the RenPy docs on save states:

Python variables that are not changed before the game begins will not be saved.
What bipedal posted also tracks with some important caveats:

All data reachable through fields on persistent is saved when Ren'Py terminates, or when renpy.save_persistent() is called. Persistent data is loaded when Ren'Py starts, and when Ren'Py detects that the persistent data has been updated on disk.

As persistent data is loaded before init python blocks are run, persistent data should only contain types that are native to Python or Ren'Py. Alternatively, classes that are defined in python early blocks can be used, provided those classes can be pickled and implement equality.
Good work on that gallery implementation though.
 

EviteGames

Newbie
Sep 29, 2020
58
1,133
Thank you both for your answers. I tried a bunch of different solutions, but I don't see myself closer to a final solution.

I've tried what Bipedal mentioned. Interestingly, once I removed the "gallery_elements = []" from the init python block, and put it outside as "define persistent.gallery_elements = []", I could only access the gallery_elements list if I referred to it as persistent.gallery_elements.

No problem, change occurrences accordingly. A new issue occurs.

Exception: To be persisted, [<store.GalleryElement object at 0x0517E2F0>, <store.GalleryElement object at 0x0517E070>, <store.GalleryElement object at 0x0517E350>] must support equality comparison.
To save custom classes into persistent data, you have to write an equality comparison method for the class. A quick google search and this is done.

Python:
# The GalleryElement class is the basic model of a single element in the gallery
init python:
    class GalleryElement:
        def __init__(self,item_id, item_name, image_list, available_thumbnail, locked_thumbnail="default_locked_thumbnail"):
            self.item_id = item_id
            self.item_name=item_name
            self.image_list=image_list
            self.available_thumbnail=available_thumbnail
            self.locked_thumbnail=locked_thumbnail
            self.is_locked = True

        def __eq__(self, other):
            return self.item_id == other.item_id

        def unlock(self):
            self.is_locked = False
Cool, issue resolved. The data should be persisted right now. But it is not. The error is gone, but we are back to where we were in the very beginning. Once I restart the game, the unlocked elements are lost.

I've removed the compile safety measures as DelinquentProductions mentioned, but I fail to see how it would affect the functionality. Something I haven't wrapped my head around in Ren'Py is persistance, apparently.
 
Jul 22, 2019
247
369
I could only access the gallery_elements list if I referred to it as persistent.gallery_elements.
That is expected, the gallery_elements member exists only within the persistent object, so that's only how it can be accessed.

Its hard to tell what could be going wrong, but try to do the appending after the start label instead of in an init block. (Use a $ sign before the python statements when inside a label, like
Code:
label start:
    $ persistent.gallery_elements.append(blah blah)
 
  • Like
Reactions: EviteGames

EviteGames

Newbie
Sep 29, 2020
58
1,133
Thanks for the explanation.

I tried that right now, and the results were... interesting.

After starting the game and reaching the point where I've unlocked the GalleryElement manually, it was available.

But after I've restarted the game, the whole gallery was... empty! Which screams to me that I have an issue somewhere else, since the persisted list should have retained its content.
 
Jul 22, 2019
247
369
Welp, idk. You can try printing to the console at different stages to debug the issue. Shift + O to open the console. Also maybe check the persistent save file to see if its really saving the array or not.
 
  • Like
Reactions: EviteGames

EviteGames

Newbie
Sep 29, 2020
58
1,133
I will do these, thanks. I'm not really used to the Ren'Py debugging tools yet, but I guess I gotta learn them now.
 

DelinquentProductions

Degenerate
Game Developer
Oct 24, 2020
135
892
RenPy's debugging options and docs aren't the best just due to the nature of RenPy. One thing that might be worth checking is this order of events:
  1. Reach unlockable portion
  2. Save
  3. Close game
  4. Open and load the specific save
  5. Check gallery.
In theory if the data is being saved but not loaded on game start you could end up in a real weird state, but I'm not very familiar with RenPy's save/load/rollback mechanics.
 
  • Like
Reactions: Madmanator99

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,269
After that, we have a few utility methods for resizing the images (so that there is no need for separate image sizes for thumbnails and the high res image).
You don't need that. Frame automatically resize the image for you.
Therefore, don't need this :
Code:
image gallery_img_1 = max_scale("gallery/gallery_img_1.jpg")
[...]
image gallery_thumbnail_1 = min_scale("gallery/gallery_img_1.jpg", GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)
Also, Ren'py automatically create an image object with the name of all the images in "game/images" and its sub-directories ; unless the name is duplicated, then only the first one will be created. Therefore, you just need that :
Python:
gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_1,["gallery_img_1", "gallery_img_1b"]))
Then depending if you want to display the thumbnail or the full image, you use Frame( gallery_elements[i].image_list[0], size=( GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT) ) or directly gallery_elements[i].image_list[0].


As for your problem, it come from there :
Python:
# This block is responsible for declaring the elements which should be available in the gallery
init python:
    gallery_elements = []
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_1,["gallery_img_1", "gallery_img_1b"],"gallery_thumbnail_1"))
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_2,["gallery_img_2"],"gallery_thumbnail_2"))
    gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_3,["gallery_img_3"],"gallery_thumbnail_3"))
The objects are created at init time, therefore they'll not be saved.

This should solve the problem :
Python:
label start:
    call initGallery
    [...]

label initGallery:
    python:
        gallery_elements = []
        gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_1,["gallery_img_1", "gallery_img_1b"],"gallery_thumbnail_1"))
        gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_2,["gallery_img_2"],"gallery_thumbnail_2"))
        gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_3,["gallery_img_3"],"gallery_thumbnail_3"))
    return
 

EviteGames

Newbie
Sep 29, 2020
58
1,133
Thank you for your reply anne O'nymous! I haven't gotten around to testing your solution to the problem but I'll give it a whirl very soon.

However, there are a few things about your solution I don't quite understand.

- I've tried putting the list into a "default" declaration as follows:
Python:
# Define the persistent list (the constructor has changes so bear with me)
default persistent.gallery_elements = [GalleryElement(1, "Space & K/DA",["gallery_img_1", "gallery_img_1b"],"gallery_thumbnail_1"), GalleryElement(2, "Maid Service",["gallery_img_2"],"gallery_thumbnail_2"), GalleryElement(3, "Portrait of a girl",["gallery_img_3"],"gallery_thumbnail_3")]
Shouldn't this produce the same result? I had zero success with this approach.

- Is your solution foolproof in a way that if I start the game again, the list won't get overridden or duplicated? I can see this happening, since you are just appending the list again. (but the __eq__ function might stop that.)

Edit:

I've tried your solution. The issue with that it is tied to the save. In my use-case, the Gallery is a menu available from the main screen as well. In the context of the main menu, the gallery_elements list isn't defined yet. It is only available once the game has started and only through there. Additionally, since it is tied to the save file, a new walkthrough will have a completely new (and locked) gallery as well.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,269
- I've tried putting the list into a "default" declaration as follows:
[...]
Shouldn't this produce the same result? I had zero success with this approach.
Hmm.
Alright, wrote like this, it totally change the meaning of your initial message. The code you provided in it absolutely not use persistent data. So I, wrongly, assumed that your "If you open it up again. you just lost all the unlockables' states" had an implied and loaded a save file.
So, yes, this will not works more than your initial code or the one in my answer.

It's late, so I can forget something, but as far as my brain is working, persistent data are saved whatever the moment they are defined and whatever if they are object or scalar-like. So, it shouldn't matter that you are creating the persistent list in an init block.
The problem, in addition to the fact that you initially didn't used the persistent prefix, come from the fact that you don't verify it the list exist before creating it. Therefore, every time Ren'py is launched, it reset the said list ; things are persistent, as long as you don't write over them.

Python:
init python:
    if persistent.gallery_elements is None:
        persistent.gallery_elements = []
        persistent.gallery_elements.append(GalleryElement(GALLERY_ITEM_NAME_1,[...] )
    [...]
 
  • Like
Reactions: EviteGames
Jul 22, 2019
247
369
Ok, just as general rule, I would suggest:

1) Before actually initialiazing the list in a label, check if it already exists or not (hasattr()). You might be overwriting it without knowing it.

2) After making your changes, call renpy.save_persistent() just to ensure it gets saved.

I have no idea if persistent variables are available in the context of the main menu screen or not. If they aren't then maybe make the gallery in-game somehow?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,269
1) Before actually initialiazing the list in a label, check if it already exists or not (hasattr()). You might be overwriting it without knowing it.
This don't works with persistent values. Due to its destination, the object handling them is designed to never throw an AttributeError exception, therefore hasattr() will always return True.
As I said above, to test if a persistent variable exist, you need to test if it's value is None or not.
 

EviteGames

Newbie
Sep 29, 2020
58
1,133
Thank you for your help. I managed to fix the issue, but additional changes needed to be made. Most importantly, I had to put the GalleryElement in an init python early block.

Furthermore, while your tips with the Frame methods are super useful anne O'nymous, it somehow messed up the gallery grid spacing and I couldn't fix it totally. But personally, I've sank enough time into this, and the solution adheres to the original specification anyways. It's just not super beautiful.

Here is the reduced, cleaned-up, final state of the code for anyone who needs it:

galleryelement.rpy
Python:
# The GalleryElement class is the basic model of a single element in the gallery
#
# item_id (required) is the numerical ID of the GalleryElement. Ideally, this should be a constant to add more safety.
# item_name (required) is the human-readable name of the GalleryElement. This is used to display its name in the Gallery.
# image_list (required) is a list of images that are contained in the GalleryElement
# available_thumbnail (optional) is the optional thumbnail that is shown if the gallery element is unlocked. If it is not provided, the first image in the image_list will be used.
# locked_thumbnail (optional) is the optional locked thumbnail that is shown if the gallery element is locked. If not provided, the default_locked_thumbnail will be shown.
init python early:
    class GalleryElement:
        def __init__(self,item_id, item_name, image_list, available_thumbnail = None, locked_thumbnail="lockedaf1"):
            self.item_id = item_id
            self.item_name=item_name
            self.image_list=image_list
            self.available_thumbnail= available_thumbnail if available_thumbnail is not None else image_list[0]
            self.locked_thumbnail=locked_thumbnail
            self.is_locked = True

        def __eq__(self, other):
            return self.item_id == other.item_id

        def unlock(self):
            self.is_locked = False
gallerylist.rpy
Python:
# Declare the constants holding the gallery elements' IDs, for compile safety.
define GALLERY_ELEMENT_SUNSETS = 1
define GALLERY_ELEMENT_LOW_TIDE = 2
define GALLERY_ELEMENT_FULL_MOON = 3
define GALLERY_ELEMENT_KOI = 4
define GALLERY_ELEMENT_BREAKING_THROUGH = 5

image black_background = "#000"

init python:
    def unlock_gallery_element(item_id):
        next((i for i in persistent.gallery_elements if i.item_id == item_id), None).unlock()

    if persistent.gallery_elements is None:
        persistent.gallery_elements = []
        persistent.gallery_elements.append(GalleryElement(GALLERY_ELEMENT_SUNSETS, "Sunsets",["gallery_img_1", "gallery_img_1b"]))
        persistent.gallery_elements.append(GalleryElement(GALLERY_ELEMENT_LOW_TIDE, "Low tide",["gallery_img_2"]))
        persistent.gallery_elements.append(GalleryElement(GALLERY_ELEMENT_FULL_MOON, "Full moon",["gallery_img_3"]))
        persistent.gallery_elements.append(GalleryElement(GALLERY_ELEMENT_KOI, "Koi",["gallery_img_4"]))
        persistent.gallery_elements.append(GalleryElement(GALLERY_ELEMENT_BREAKING_THROUGH, "Breaking through",["gallery_img_5"]))
galleryscreen.rpy
Python:
init python:
    GALLERY_WIDTH = 2
    GALLERY_HEIGHT = 2
    GALLERY_ELEMENT_WIDTH = config.screen_width / (GALLERY_WIDTH + 1)
    GALLERY_ELEMENT_HEIGHT = config.screen_height / (GALLERY_HEIGHT + 1)
    MAX_ELEMENTS_PER_PAGE = GALLERY_WIDTH * GALLERY_HEIGHT
    current_gallery_page = 0
    current_closeup_page = 0

screen Gallery():
    tag menu
    add "black_background"

    $start = current_gallery_page * MAX_ELEMENTS_PER_PAGE
    $end = min(start + MAX_ELEMENTS_PER_PAGE - 1, len(persistent.gallery_elements) - 1)

    # Create a grid for the images
    grid GALLERY_WIDTH GALLERY_HEIGHT:
        xfill True
        yfill True
        for i in range(start, end +1):
            if persistent.gallery_elements[i].is_locked:
                add Frame(persistent.gallery_elements[i].locked_thumbnail, size = (GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)):
                    xalign 0.5
                    yalign 0.5
            else:
                imagebutton idle Frame(persistent.gallery_elements[i].available_thumbnail, size = (GALLERY_ELEMENT_WIDTH, GALLERY_ELEMENT_HEIGHT)):
                    action Show("GalleryCloseUp", dissolve, persistent.gallery_elements[i].image_list)
                    xalign 0.5
                    yalign 0.5

        for i in range(end +1, start + MAX_ELEMENTS_PER_PAGE):
            null

    # Create a grid for the image titles
    grid GALLERY_WIDTH GALLERY_HEIGHT:
        xfill True
        yfill True

        for i in range(start, end + 1):
            hbox:
                spacing GALLERY_ELEMENT_WIDTH - 70
                xalign 0.5
                yalign 0.1
                $item_name = persistent.gallery_elements[i].item_name
                text "[item_name]"

        for i in range(end - start + 1, MAX_ELEMENTS_PER_PAGE):
            null

    # Add the 'Previous' and 'Next' buttons
    if current_gallery_page > 0:
        textbutton "Previous":
            action SetVariable("current_gallery_page", current_gallery_page - 1)
            xalign 0.1
            yalign 0.98
    if (current_gallery_page + 1) * MAX_ELEMENTS_PER_PAGE < len(persistent.gallery_elements):
        textbutton "Next":
            action SetVariable("current_gallery_page", current_gallery_page + 1)
            xalign 0.9
            yalign 0.98

    textbutton "Return":
        action Return()
        xalign 0.5
        yalign 0.98

screen GalleryCloseUp(images):
    modal True
    add Frame(images[current_closeup_page], size = (config.screen_width, config.screen_height)) at truecenter

    if current_closeup_page > 0:
        textbutton "Previous":
            action SetVariable("current_closeup_page", current_closeup_page - 1)
            xalign 0.1
            yalign 0.98
    if current_closeup_page < len(images) - 1:
        textbutton "Next":
            action SetVariable("current_closeup_page", current_closeup_page + 1)
            xalign 0.9
            yalign 0.98

    textbutton "Return":
        action [SetVariable("current_closeup_page", 0), Hide("GalleryCloseUp", dissolve)]
        xalign 0.5
        yalign 0.98

This is how the end result looks like, with 2 items unlocked:
1603648434120.png

If anybody got any ideas for improvement and how to fix the spacing issues, please share so I can update the code.
 

Paz

Active Member
Aug 9, 2016
912
1,449
If anybody got any ideas for improvement and how to fix the spacing issues, please share so I can update the code.
Not sure if you've changed it, but the default Frame style has a 6px padding (defined as Border in gui.rpy if I recall correctly) that can mess it up if you're trying pixel-perfect UI.
You can check if that's the case for you with Style Inspector (Shift + I) while hovering over a displayable.
 

EviteGames

Newbie
Sep 29, 2020
58
1,133
It wasn't really an issue with the default padding on Frame.

The issue was that when creating the grid elements for the images, I couldn't set it so that they only take up a portion of the space available. (Of their respective grid elements)

If I didn't set the xfill True yfill True, the image would be using its original size, despite whatever arguments I provided.

The same issue didn't happen with the min_scale and max_scale methods in the initial versions. Somehow, those could work.

But this whole problem might be a bit moot, to be honest. I'm overdoing optimization here. Most devs would just include a smaller resolution image for the available_thumbnail so that it'd fit pixel perfectly.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,269
Not sure if you've changed it, but the default Frame style has a 6px padding (defined as Border in gui.rpy
You're mixing two different things here. There's , that was my advice, which is a displayable, and there's which is a screen statement and the one that have the padding.
 

Paz

Active Member
Aug 9, 2016
912
1,449
You're mixing two different things here. There's , that was my advice, which is a displayable, and there's which is a screen statement and the one that have the padding.
Ah, right. That will teach me trying to read code snippets semi-awake.