CampBuddy/Camp.Buddy v2.2.1/Camp_Buddy-2.2.1-pc/renpy/common/00gui.rpy
2025-03-03 23:00:33 +01:00

584 lines
18 KiB
Text

# Copyright 2004-2019 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
init -1100 python in gui:
from store import config, layout, _preferences, Frame, Null, persistent, Action, DictEquality
config.translate_clean_stores.append("gui")
_null = Null()
def init(width, height):
"""
:doc: gui
Initializes the gui.
`width`
The width of the default window.
`height`
The height of the default window.
"""
if (not renpy.is_init_phase()) and config.developer:
raise Exception("gui.init may only be called during the init phase.")
config.screen_width = width
config.screen_height = height
layout.defaults()
renpy.call_in_new_context("_style_reset")
# Defer styles until after translation code runs.
config.defer_styles = True
size = (width, height)
if (_preferences.virtual_size is not None) and (_preferences.virtual_size != size):
_preferences.physical_size = None
_preferences.virtual_size = size
from store import build
build.include_old_themes = False
if persistent._gui_preference is None:
persistent._gui_preference = { }
if persistent._gui_preference_default is None:
persistent._gui_preference_default = { }
def rebuild():
"""
:doc: gui
Rebuilds the GUI.
Note: This is a very slow function.
"""
renpy.ast.redefine([ "store.gui" ])
for i in config.translate_clean_stores:
renpy.python.clean_store_backup.backup_one("store." + i)
# Do the same sort of reset we'd do when changing language, without
# actually changing the language.
renpy.change_language(_preferences.language, force=True)
not_set = object()
def preference(name, default=not_set):
"""
:doc: gui_preference
This function returns the value of the gui preference with
`name`.
`default`
If given, this value becomes the default value of the gui
preference. The default value should be given the first time
the preference is used.
"""
prefs = persistent._gui_preference
defaults = persistent._gui_preference_default
if default is not not_set:
if (name not in defaults) or (defaults[name] != default):
prefs[name] = default
defaults[name] = default
return prefs[name]
class SetPreference(Action, DictEquality):
"""
:doc: gui_preference
This Action sets the gui preference with `name` to `value`.
`rebuild`
If true, the default, :func:`gui.rebuild` is called to make
the changes take effect. This should generally be true, except
in the case of multiple gui.SetPreference actions, in which case
it should be False in all but the last one.
This is a very slow action, and probably not suitable for use
when a button is hovered.
"""
def __init__(self, name, value, rebuild=True):
self.name = name
self.value = value
self.rebuild = rebuild
def __call__(self):
prefs = persistent._gui_preference
prefs[self.name] = self.value
rebuild()
def get_selected(self):
prefs = persistent._gui_preference
return prefs.get(self.name, not_set) == self.value
class TogglePreference(Action, DictEquality):
"""
:doc: gui_preference
This Action toggles the gui preference with `name` between
value `a` and value `b`. It is selected if the value is equal
to `a`.
`rebuild`
If true, the default, :func:`gui.rebuild` is called to make
the changes take effect. This should generally be true, except
in the case of multiple gui.SetPreference actions, in which case
it should be False in all but the last one.
This is a very slow action, and probably not suitable for use
when a button is hovered.
"""
def __init__(self, name, a, b, rebuild=True):
self.name = name
self.a = a
self.b = b
self.rebuild = rebuild
def __call__(self):
prefs = persistent._gui_preference
if prefs[self.name] == self.a:
prefs[self.name] = self.b
else:
prefs[self.name] = self.a
rebuild()
def get_selected(self):
prefs = persistent._gui_preference
return prefs.get(self.name, not_set) == self.a
renpy.pure("gui.preference")
renpy.pure("gui.SetPreference")
renpy.pure("gui.TogglePreference")
# The extension used for auto-defined images.
button_image_extension = ".png"
def button_properties(kind):
"""
:doc: gui
Given a `kind` of button, returns a dictionary giving standard style
properties for that button. This sets:
:propref:`background`
As described below.
:propref:`padding`
To gui.kind_borders.padding (if it exists).
:propref:`xsize`
To gui.kind_width (if it exists).
:propref:`ysize`
To gui.kind_height (if it exists).
(Note that if `kind` is the string "nvl_button", this will look for
the gui.nvl_button_background variable.)
The background is a frame that takes its background picture from
the first existing one of:
* gui/button/kind_[prefix\_].background.png
* gui/button/[prefix\_].background.png
If a gui variables named gui.kind_borders exists, it's
used. Otherwise, :var:`gui.button_borders` is used. If gui.kind_tile
exists, it determines if the borders are tiled, else :var:`gui.button_tile`
controls tiling.
For what [prefix\_] means, check out the :ref:`style prefix search <style-prefix-search>`
documentation.
"""
g = globals()
def get(prop):
if kind + "_" + prop in g:
return g[kind + "_" + prop]
return None
borders = get("borders")
tile = get("tile")
if tile is None:
tile = button_tile
backgrounds = [ ]
if kind != "button":
backgrounds.append("gui/button/" + kind[:-7] + "_[prefix_]background" + button_image_extension)
backgrounds.append("gui/button/[prefix_]background" + button_image_extension)
if renpy.variant("small"):
backgrounds = [ i.replace("gui/button", "gui/phone/button") for i in backgrounds ] + backgrounds
rv = {
"background" : Frame(backgrounds, borders or button_borders, tile=tile),
}
if borders is not None:
rv["padding"] = borders.padding
width = get("width")
height = get("height")
if width is not None:
rv["xsize"] = width
if height is not None:
rv["ysize"] = height
return rv
def text_properties(kind=None, accent=False):
"""
:name: gui.text_properties
:doc: gui
Given a `kind` of button, returns a dictionary giving standard style
properties for that button. This sets:
:propref:`font`
To gui.kind_text_font, if it exists.
:propref:`size`
To gui.kind_text_size, if it exists.
:propref:`xalign`
To gui.kind_text_xalign, if it exists.
:propref:`text_align`
To gui.kind_text_xalign, if it exists.
:propref:`layout`
To "subtitle" if gui.kind_text_xalign is greater than zero
and less than one.
There are also a number of variables that set the text
:propref:`color` style property:
color
To gui.kind_text_color, if it exists. If the variable is not
set, and `accent` is True, sets the text color to the default
accent color.
insensitive_color
To gui.kind_text_insensitive_color, if it exists.
idle_color
To gui.kind_text_idle_color, if it exists.
hover_color
To gui.kind_text_hover_color, if it exists.
selected_color
To gui.kind_text_selected_color, if it exists.
All other :ref:`text style properties <text-style-properties>` are also available. For
example, gui.kind_text_outlines sets the outlines style property,
gui.kind_text_kerning sets kerning, and so on.
"""
g = globals()
def get(prop):
if kind is not None:
name = kind + "_" + prop
else:
name = prop
if name in g:
return g[name]
return None
rv = { }
if accent and (accent_color is not None):
rv["color"] = accent_color
if kind is not None:
xalign = get("text_xalign")
if xalign is not None:
rv["xalign"] = xalign
rv["text_align"] = xalign
if (xalign > 0) and (xalign < 1):
rv["layout"] = "subtitle"
for prefix in renpy.sl2.slparser.STYLE_PREFIXES:
for property in renpy.sl2.slproperties.text_property_names:
prop = prefix + property
text_prop = "text_" + prop
v = get(text_prop)
if v is not None:
rv[prop] = v
return rv
button_text_properties = text_properties
############################################################################
# Strings used by the confirm screen.
ARE_YOU_SURE = _("Are you sure?")
DELETE_SAVE = _("Are you sure you want to delete this save?")
OVERWRITE_SAVE = _("Are you sure you want to overwrite your save?")
LOADING = _("Loading will lose unsaved progress.\nAre you sure you want to do this?")
QUIT = _("Are you sure you want to quit?")
MAIN_MENU = _("Are you sure you want to return to the main menu?\nThis will lose unsaved progress.")
END_REPLAY = _("Are you sure you want to end the replay?")
SLOW_SKIP = _("Are you sure you want to begin skipping?")
FAST_SKIP_SEEN = _("Are you sure you want to skip to the next choice?")
FAST_SKIP_UNSEEN = _("Are you sure you want to skip unseen dialogue to the next choice?")
############################################################################
# Image generation. This lives here since it wants to read data from
# the gui variables.
# Should we skip backups?
_skip_backup = False
def _gui_images():
import store.gui as gui
from store import config, Color
import pygame_sdl2
import os
if not config.developer:
return
phone = renpy.variant("small")
class Image(object):
def __init__(self, dn, fn, width, height):
self.s = pygame_sdl2.Surface((width, height), pygame_sdl2.SRCALPHA)
if phone:
self.fn = os.path.join(config.gamedir, "gui", "phone", dn, fn + ".png")
else:
self.fn = os.path.join(config.gamedir, "gui", dn, fn + ".png")
self.width = width
self.height = height
def save(self):
s = self.s
fn = self.fn
dn = os.path.dirname(fn)
try:
os.makedirs(dn, 0o777)
except:
pass
if os.path.exists(fn):
index = 1
while True:
bfn = "{}.{}.bak".format(fn, index)
if not os.path.exists(bfn):
break
index += 1
if not gui._skip_backup:
os.rename(fn, bfn)
import cStringIO
sio = cStringIO.StringIO()
renpy.display.module.save_png(s, sio, 3)
with open(fn, "wb") as f:
f.write(sio.getvalue())
def fill(self, color=None):
if color is None:
color = gui.accent_color
color = tuple(Color(color))
self.s.fill(color)
return self
def fill_rect(self, rect, color=None):
if color is None:
color = gui.accent_color
color = tuple(Color(color))
ss = self.s.subsurface(rect)
ss.fill(color)
return self
def fill_left(self, width, color=None):
self.fill_rect((0, 0, width, self.height))
return self
def scale(fixed, scaled):
if fixed is not None:
return fixed
factor = 1.0 * config.screen_height / 720
return int(scaled * factor)
# Buttons
width = scale(gui.button_width, 300)
if phone:
height = scale(gui.button_height, 43)
else:
height = scale(gui.button_height, 33)
check_width = gui.check_button_borders.padding[0]
check_margin = scale(None, 3)
check_rect = (
check_margin,
gui.check_button_borders.padding[1],
min(check_width - check_margin, scale(None, 5)),
height - gui.check_button_borders.padding[1] - gui.check_button_borders.padding[3],
)
radio_width = gui.radio_button_borders.padding[0]
radio_margin = scale(None, 3)
radio_rect = (
radio_margin,
gui.radio_button_borders.padding[1],
min(radio_width - radio_margin, scale(None, 5)),
height - gui.radio_button_borders.padding[1] - gui.radio_button_borders.padding[3],
)
Image("button", "idle_background", width, height).save()
Image("button", "hover_background", width, height).save()
Image("button", "check_selected_foreground", check_width, height).fill_rect(check_rect).save()
Image("button", "check_foreground", check_width, height).save()
Image("button", "radio_selected_foreground", radio_width, height).fill_rect(radio_rect).save()
Image("button", "radio_foreground", radio_width, height).save()
# Bars.
long_size = scale(None, 350)
Image("bar", "left", long_size, gui.bar_size).fill(gui.hover_color).save()
Image("bar", "right", long_size, gui.bar_size).fill(gui.muted_color).save()
Image("bar", "bottom", gui.bar_size, long_size).fill(gui.hover_color).save()
Image("bar", "top", gui.bar_size, long_size).fill(gui.muted_color).save()
if phone:
thumb_size = scale(None, 15)
else:
thumb_size = scale(None, 10)
Image("slider", "horizontal_idle_bar", long_size, gui.slider_size).fill(gui.muted_color).save()
Image("slider", "horizontal_idle_thumb", thumb_size, gui.slider_size).fill(gui.accent_color).save()
Image("slider", "horizontal_hover_bar", long_size, gui.slider_size).fill(gui.hover_muted_color).save()
Image("slider", "horizontal_hover_thumb", thumb_size, gui.slider_size).fill(gui.hover_color).save()
Image("slider", "vertical_idle_bar", gui.slider_size, long_size).fill(gui.muted_color).save()
Image("slider", "vertical_idle_thumb", gui.slider_size, thumb_size).fill(gui.accent_color).save()
Image("slider", "vertical_hover_bar", gui.slider_size, long_size).fill(gui.hover_muted_color).save()
Image("slider", "vertical_hover_thumb", gui.slider_size, thumb_size).fill(gui.hover_color).save()
long_size = scale(None, 700)
Image("scrollbar", "horizontal_idle_bar", long_size, gui.scrollbar_size).fill(gui.muted_color).save()
Image("scrollbar", "horizontal_idle_thumb", long_size, gui.scrollbar_size).fill(gui.accent_color).save()
Image("scrollbar", "horizontal_hover_bar", long_size, gui.scrollbar_size).fill(gui.hover_muted_color).save()
Image("scrollbar", "horizontal_hover_thumb", long_size, gui.scrollbar_size).fill(gui.hover_color).save()
Image("scrollbar", "vertical_idle_bar", gui.scrollbar_size, long_size).fill(gui.muted_color).save()
Image("scrollbar", "vertical_idle_thumb", gui.scrollbar_size, long_size).fill(gui.accent_color).save()
Image("scrollbar", "vertical_hover_bar", gui.scrollbar_size, long_size).fill(gui.hover_muted_color).save()
Image("scrollbar", "vertical_hover_thumb", gui.scrollbar_size, long_size).fill(gui.hover_color).save()
sbp = gui.slot_button_borders.padding
tnx = (gui.slot_button_width - config.thumbnail_width) // 2
bar_width = scale(None, 5)
s = Image("button", "slot_idle_background", gui.slot_button_width, gui.slot_button_height)
s.fill_rect((tnx, sbp[1], config.thumbnail_width, config.thumbnail_height), gui.muted_color)
s.save()
s = Image("button", "slot_hover_background", gui.slot_button_width, gui.slot_button_height)
s.fill_rect((tnx, sbp[1], config.thumbnail_width, config.thumbnail_height), gui.hover_muted_color)
s.fill_rect((0, sbp[1], bar_width, config.thumbnail_height))
s.save()
return False
renpy.arguments.register_command("gui_images", _gui_images)