A Hacky approach to Ren'Py Text Accessibility

Tags: , , , , , ,

Ren'Py All-In-One GUI Template is a much less hacky approach but I couldn't get it to do what I wanted without having the code break. So this is what I did instead.

What I wanted: The ability to have very large text in Renpy, including button and UI text etc, and having the text box resize to match.

And here's how I did it, if only for my own future reference, as well as some rambling about why I made the decisions I did. I use the Caption Tool basically as is.

I based my code on the in-built Renpy accessibility screen (found in 00accessibility.rpy in the main renpy folder) and GUI Preferences example code. I also drew on Ren'Py All-In-One GUI Template, which in turn draws on Ren'Py Accessibility Add-On.

I probably could have done a lot of this with styles, but styles confuse me, so I didn't.

The principles I decided upon after some thought and rereading the Game Accessibility Guidelines:

So! I have two new additions to the Preferences screen: a font choice, and a text size choice.

Font

Overwrite/replace the following in gui.rpy:

define gui.text_font = gui.preference("font", "gui/IMFeDPrm28P.ttf") #the font used for dialogue, buttons etc.

define gui.interface_text_font = gui.preference("UIfont", "gui/IMFeENsc28P.ttf") #the font used for user interfaces

define gui.history_height = None

My default is IM Fell.

Since I wanted my preferences screen to look good with very large text, I made sure every line only had two columns. I also added "xsize 400" and "spacing 5" to each block to stop the text getting garbled.

So here's the row in screens.rpy with the font and text size choices in the Preferences menu:

hbox:
    box_wrap True
        
    null height (4 * gui.pref_spacing)
    vbox:
        {I have multiple versions of this, see below}
                            
        
    vbox:
        xsize  400
        spacing 5

        style_prefix "radio"
        label _("Typeface")

        textbutton "{font=DejaVuSans.ttf}Sans-Serif{/font}" action [
            gui.SetPreference("font","DejaVuSans.ttf"),gui.SetPreference("UIfont", "DejaVuSans.ttf")]

        textbutton "{font=gui/IMFeDPrm28P.ttf}Serif{/font}" action [
            gui.SetPreference("font","gui/IMFeDPrm28P.ttf"),gui.SetPreference("UIfont", "gui/IMFeENsc28P.ttf")]

null height (4 * gui.pref_spacing)        

I decided the actual font names would just confuse people, but I'm not sure Sans Serif vs Serif is the best dichotomy. I might change it to simple vs fancy or something.

Text Size: Version One

This has three text size options, and three matching unscaled textboxes. I couldn't be bothered implementing text box transparency options, so just made the largest text size box entirely opaque. This is the only version that adjusts the history.

Overwrite/replace the following in gui.rpy:

 
define gui.textbox_height = gui.preference("text_height", 186) #the height of the text box image

define gui.dialogue_xpos = gui.preference("text_start", 59) #how far right into the textbox the dialogue starts

define gui.dialogue_width = gui.preference("text_width", 1160) #how wide the dialogue is allowed to get

define gui.history_text_xpos = gui.preference("history_xpos", 170) #where history dialogue starts

define gui.history_text_width = gui.preference("history_width", 740) #how wide history dialogue is

Add this to the Preferences screen in screens.rpy:

vbox:
    xsize  400
    spacing 5

    style_prefix "radio"
    label _("Font Size")

    textbutton "Small" action [Preference("font size", 0.8), gui.SetPreference("text_height", 185),
        gui.SetPreference("text_start", 165), gui.SetPreference("text_width", 950),
        gui.SetPreference("history_xpos", 170),gui.SetPreference("history_width", 740)]

    textbutton "Medium" action [Preference("font size", 1.0), gui.SetPreference("text_height", 186),
        gui.SetPreference("text_start", 59),gui.SetPreference("text_width", 1160),
        gui.SetPreference("history_xpos", 171),gui.SetPreference("history_width", 739)]
 
    textbutton "Large" action [Preference("font size", 1.25), gui.SetPreference("text_height", 240),
        gui.SetPreference("text_start", 60),gui.SetPreference("text_width", 1166),
        gui.SetPreference("history_xpos", 260),gui.SetPreference("history_width", 660)]

Note that I made some of the sizes one pixel different, this was to stop Renpy thinking the choices counted as the same (I said this was hacky >.>)

And here's the new code for the dialogue window:

style window:
    xalign 0.5
    xfill True
    yalign gui.textbox_yalign
    ysize gui.textbox_height 

    background ConditionSwitch("preferences.font_size<=0.8", Image("gui/textbox_small.png"),
                "preferences.font_size<=1.25", Image("gui/textbox_medium.png"),
                 "True", Image("gui/textbox_large.png")) 
 

These numbers were found via a lot of trial and error. I initially just used a frame for the textbox until I had the size right.

Text Size: Version Two

This has a text size slider and resizes the textbox to fit. Inspired by this approach which I couldn't quite get to work. I couldn't figure out how to stop long character names overlapping the text in the history.

Add/overwrite the following variables in gui.rpy:

define gui.dialogue_ypos = 0 

define gui.textbox_height = None #resize automatically

define gui.textbox_borders = Borders(10, 10, 10, 10) #size of corners

define gui.textbox_min = 185 #minimum height

Here's some documentation on Frames and Borders.

In screens.rpy:

Add the line "has vbox" and some padding to the say screen:

window:
        id "window"
        has vbox

        if who is not None:

            window:
                id "namebox"
                style "namebox"
                text who id "who"
        else:
            text " "        

        text what id "what"
        text " "

Edit the dialogue window:

style window:
    xalign 0.5
    xfill True
    yalign gui.textbox_yalign
    ysize gui.textbox_height
    yminimum gui.textbox_min

    background Frame("gui/textbox.png", gui.textbox_borders) 

And that should work automatically! You can either just link to the accessibility screen, or add the text size bar to your preferences screen:

vbox:
    style_prefix "slider"
    box_wrap True
    xsize  400
    spacing 5
    label _("Text Size Scaling")

    null height 10

    bar value Preference("font size")

    textbutton _("Reset"):
        action Preference("font size", 1.0)

Text Size: Version 3

If you want a fancy unscaled textbox by default but a scaled one if the text size gets larger, use Version Two, but replace the window code with:

style window:
    xalign 0.5
    xfill True
    yalign gui.textbox_yalign
    ysize gui.textbox_height 
    yminimum gui.textbox_min

    background ConditionSwitch("preferences.font_size<=1", Image("gui/textbox_fancy.png"),
               "True", Frame("gui/textbox_scalable.png", gui.textbox_borders))