Restore merges.
This commit is contained in:
@@ -104,3 +104,4 @@ module/glrtt_fbo.c
|
||||
module/glrtt_fbo.html
|
||||
tutorial/game/cache
|
||||
renpy.exe.log
|
||||
renpy/vc_version.py
|
||||
|
||||
+5
-2
@@ -48,9 +48,12 @@ init -1210 python:
|
||||
config.imagereference_respects_position = True
|
||||
config.predict_screens = False
|
||||
config.choice_screen_chosen = False
|
||||
|
||||
if version <= (6, 12, 0):
|
||||
config.keep_running_transform = False
|
||||
config.image_attributes = False
|
||||
config.new_character_image_argument = False
|
||||
|
||||
|
||||
|
||||
init 1210 python hide::
|
||||
|
||||
# This returns true if the script_version is <= the
|
||||
|
||||
+19
-1
@@ -1315,7 +1315,25 @@ init -1140 python:
|
||||
def __call__(self):
|
||||
renpy.take_screenshot()
|
||||
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Side Images
|
||||
|
||||
def SideImage(tag="side"):
|
||||
"""
|
||||
:doc: side_image_function
|
||||
|
||||
Returns the side image associated with the currently speaking character,
|
||||
or a Null displayable if no such side image exists.
|
||||
"""
|
||||
|
||||
name = renpy.get_side_image(tag)
|
||||
if name is None:
|
||||
return Null()
|
||||
else:
|
||||
return ImageReference(name)
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Preferences Constructor
|
||||
|
||||
|
||||
+31
-9
@@ -115,23 +115,45 @@ def tree(root):
|
||||
|
||||
def main():
|
||||
|
||||
# Revision updating is done early, so we can do it even if the rest
|
||||
# of the program fails.
|
||||
|
||||
# Determine the version. We grab the current revision, and if any
|
||||
# file has changed, bump it by 1.
|
||||
p = subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE)
|
||||
revno = p.stdout.read().strip()
|
||||
revno = int(revno)
|
||||
p.wait()
|
||||
|
||||
p = subprocess.Popen(["bzr", "status", "-V"], stdout=subprocess.PIPE)
|
||||
status = p.stdout.read().strip()
|
||||
p.wait()
|
||||
|
||||
if status:
|
||||
revno += 1
|
||||
|
||||
# Write the revno to the necessary files.
|
||||
f = file("lib/update-version.txt", "w")
|
||||
f.write("{revno}-{now} base\n".format(revno=revno, now=time.time()))
|
||||
f.close()
|
||||
|
||||
f = file("renpy/vc_version.py", "w")
|
||||
f.write("""\
|
||||
# The version of Ren'Py reported by the version control software.
|
||||
vc_version = {revno}
|
||||
""".format(revno=revno))
|
||||
f.close()
|
||||
|
||||
# Check to be sure we have the right arguments.
|
||||
if len(sys.argv) != 2:
|
||||
print "Usage: %s <prefix>" % sys.argv[0]
|
||||
return
|
||||
|
||||
prefix = sys.argv[1]
|
||||
|
||||
# Copy over the screens, to keep them up to date.
|
||||
shutil.copy("tutorial/game/screens.rpy", "template/game/screens.rpy")
|
||||
|
||||
# Update the update-version.txt file.
|
||||
p = subprocess.Popen(["bzr", "revno"], stdout=subprocess.PIPE)
|
||||
revno = p.stdout.read().strip() + "-" + str(time.time())
|
||||
p.wait()
|
||||
|
||||
f = file("lib/update-version.txt", "w")
|
||||
f.write(revno + " base\n")
|
||||
f.close()
|
||||
|
||||
# Compile all the python files.
|
||||
compileall.compile_dir("renpy/", ddir=prefix + "/renpy/", force=1)
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
init -999:
|
||||
$ config.script_version = (6, 12, 0)
|
||||
$ config.script_version = (6, 12, 1)
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
A="$RENPY_ANDROID"
|
||||
|
||||
CFLAGS="$CFLAGS -DANDROID"
|
||||
CFLAGS="$CFLAGS -I$A/android-sdl/sdl/sdl-1.2/include"
|
||||
CFLAGS="$CFLAGS -I$A/android-sdl/jni/png"
|
||||
CFLAGS="$CFLAGS -I$A/android-sdl/jni/freetype/include"
|
||||
CFLAGS="$CFLAGS -I$A/sdl/sdl-1.2/include"
|
||||
CFLAGS="$CFLAGS -I$A/jni/png"
|
||||
CFLAGS="$CFLAGS -I$A/jni/freetype/include"
|
||||
|
||||
LDFLAGS="$LDFLAGS -L$A/android-sdl/libs/armeabi -L$A/android-sdl/obj/local/armeabi"
|
||||
LDFLAGS="$LDFLAGS -L$A/libs/armeabi -L$A/obj/local/armeabi"
|
||||
|
||||
export CFLAGS
|
||||
export LDFLAGS
|
||||
|
||||
+2
-1
@@ -4,7 +4,6 @@ import os
|
||||
import os.path
|
||||
import platform
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
# These control the level of optimization versus debugging.
|
||||
extra_compile_args = [ "-O3", "-Wno-unused-function" ]
|
||||
@@ -128,6 +127,7 @@ def cython(fn):
|
||||
print pyx, "is not newer than", c
|
||||
return
|
||||
|
||||
import subprocess
|
||||
subprocess.call(["cython", pyx])
|
||||
|
||||
|
||||
@@ -283,6 +283,7 @@ display("glrtt_copy", glew_libs)
|
||||
display("glrtt_fbo", glew_libs)
|
||||
|
||||
sys.path.append('..')
|
||||
|
||||
import renpy
|
||||
|
||||
distutils.core.setup(
|
||||
|
||||
+80
-70
@@ -29,8 +29,18 @@ import os
|
||||
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
|
||||
# Be sure to change script_version in launcher/script_version.rpy, too!
|
||||
# Be sure to change _renpy.pyx and module.py, if necessary.
|
||||
version = "Ren'Py 6.12.0f"
|
||||
|
||||
try:
|
||||
from renpy.vc_version import vc_version; vc_version
|
||||
except ImportError:
|
||||
vc_version = 0
|
||||
|
||||
# The tuple giving the version. This needs to be updated when
|
||||
# we bump the version.
|
||||
version_tuple = (6, 12, 1, vc_version)
|
||||
|
||||
# A verbose string computed from that version.
|
||||
version = "Ren'Py " + ".".join(str(i) for i in version_tuple)
|
||||
|
||||
# Other versions.
|
||||
script_version = 5003000
|
||||
@@ -53,105 +63,106 @@ def import_cython():
|
||||
grab the various cython modules.
|
||||
"""
|
||||
|
||||
import renpy.display.accelerator
|
||||
import renpy.display.gldraw
|
||||
import renpy.display.glenviron
|
||||
import renpy.display.glenviron_fixed
|
||||
import renpy.display.glenviron_limited
|
||||
import renpy.display.glenviron_shader
|
||||
import renpy.display.glrtt_copy
|
||||
import renpy.display.glrtt_fbo
|
||||
import renpy.display.glshader
|
||||
import renpy.display.gltexture
|
||||
import renpy.display.render
|
||||
import renpy.display.accelerator #@UnresolvedImport
|
||||
import renpy.display.gldraw #@UnresolvedImport
|
||||
import renpy.display.glenviron #@UnresolvedImport
|
||||
import renpy.display.glenviron_fixed #@UnresolvedImport
|
||||
import renpy.display.glenviron_limited #@UnresolvedImport
|
||||
import renpy.display.glenviron_shader #@UnresolvedImport
|
||||
import renpy.display.glrtt_copy #@UnresolvedImport
|
||||
import renpy.display.glrtt_fbo #@UnresolvedImport
|
||||
import renpy.display.glshader #@UnresolvedImport
|
||||
import renpy.display.gltexture #@UnresolvedImport
|
||||
import renpy.display.render #@UnresolvedImport
|
||||
|
||||
# Prevent a pyflakes warning.
|
||||
renpy
|
||||
|
||||
|
||||
def import_all():
|
||||
import renpy.display #@UnresolvedImport
|
||||
|
||||
# Should probably be early, as we will add it as a base to serialized things.
|
||||
import renpy.object
|
||||
import renpy.object #@UnresolvedImport
|
||||
|
||||
import renpy.game
|
||||
import renpy.game #@UnresolvedImport
|
||||
|
||||
# Adds in the Ren'Py loader.
|
||||
import renpy.loader
|
||||
import renpy.loader #@UnresolvedImport
|
||||
|
||||
import renpy.ast
|
||||
import renpy.atl
|
||||
import renpy.curry
|
||||
import renpy.easy
|
||||
import renpy.execution
|
||||
import renpy.loadsave
|
||||
import renpy.parser
|
||||
import renpy.python # object
|
||||
import renpy.remote
|
||||
import renpy.script
|
||||
import renpy.statements
|
||||
import renpy.style
|
||||
import renpy.ast #@UnresolvedImport
|
||||
import renpy.atl #@UnresolvedImport
|
||||
import renpy.curry #@UnresolvedImport
|
||||
import renpy.easy #@UnresolvedImport
|
||||
import renpy.execution #@UnresolvedImport
|
||||
import renpy.loadsave #@UnresolvedImport
|
||||
import renpy.parser #@UnresolvedImport
|
||||
import renpy.python #@UnresolvedImport
|
||||
import renpy.remote #@UnresolvedImport
|
||||
import renpy.script #@UnresolvedImport
|
||||
import renpy.statements #@UnresolvedImport
|
||||
import renpy.style #@UnresolvedImport
|
||||
|
||||
import renpy.display
|
||||
import renpy.display.presplash
|
||||
import renpy.display.iliad # Must be before scale and pgrender.
|
||||
import renpy.display.pgrender
|
||||
import renpy.display.scale # Must be before module.
|
||||
import renpy.display.module
|
||||
import renpy.display.presplash #@UnresolvedImport
|
||||
import renpy.display.iliad # Must be before scale and pgrender. @UnresolvedImport
|
||||
import renpy.display.pgrender #@UnresolvedImport
|
||||
import renpy.display.scale # Must be before module. @UnresolvedImport
|
||||
import renpy.display.module #@UnresolvedImport
|
||||
|
||||
# Now that render is pre-compiled, we want to use the
|
||||
# location of renpy.display.module to find it.
|
||||
import _renpy
|
||||
libexec = os.path.dirname(_renpy.__file__)
|
||||
renpy.display.__path__.insert(0, os.path.join(libexec, "renpy", "display"))
|
||||
renpy.display.__path__.insert(0, os.path.join(libexec, "renpy", "display")) #@UndefinedVariable
|
||||
|
||||
# Also find encodings, to deal with the way py2exe lays things out.
|
||||
import encodings
|
||||
libexec = os.path.dirname(encodings.__path__[0])
|
||||
renpy.display.__path__.insert(1, os.path.join(libexec, "renpy", "display"))
|
||||
renpy.display.__path__.insert(1, os.path.join(libexec, "renpy", "display")) #@UndefinedVariable
|
||||
|
||||
import renpy.display.render # Most display stuff depends on this.
|
||||
import renpy.display.render # Most display stuff depends on this. @UnresolvedImport
|
||||
|
||||
import renpy.display.core # object
|
||||
import renpy.display.font
|
||||
import renpy.display.text # core, font
|
||||
import renpy.display.layout # core
|
||||
import renpy.display.motion # layout
|
||||
import renpy.display.behavior # layout
|
||||
import renpy.display.transition # core, layout
|
||||
import renpy.display.im
|
||||
import renpy.display.image # core, behavior, im
|
||||
import renpy.display.video
|
||||
import renpy.display.focus
|
||||
import renpy.display.anim
|
||||
import renpy.display.particle
|
||||
import renpy.display.joystick
|
||||
import renpy.display.minigame
|
||||
import renpy.display.screen
|
||||
import renpy.display.dragdrop
|
||||
import renpy.display.imagemap
|
||||
import renpy.display.predict
|
||||
import renpy.display.core # object @UnresolvedImport
|
||||
import renpy.display.font #@UnresolvedImport
|
||||
import renpy.display.text # core, font @UnresolvedImport
|
||||
import renpy.display.layout # core @UnresolvedImport
|
||||
import renpy.display.motion # layout @UnresolvedImport
|
||||
import renpy.display.behavior # layout @UnresolvedImport
|
||||
import renpy.display.transition # core, layout @UnresolvedImport
|
||||
import renpy.display.im #@UnresolvedImport
|
||||
import renpy.display.imagelike #@UnresolvedImport
|
||||
import renpy.display.image # core, behavior, im, imagelike @UnresolvedImport
|
||||
import renpy.display.video #@UnresolvedImport
|
||||
import renpy.display.focus #@UnresolvedImport
|
||||
import renpy.display.anim #@UnresolvedImport
|
||||
import renpy.display.particle #@UnresolvedImport
|
||||
import renpy.display.joystick #@UnresolvedImport
|
||||
import renpy.display.minigame #@UnresolvedImport
|
||||
import renpy.display.screen #@UnresolvedImport
|
||||
import renpy.display.dragdrop #@UnresolvedImport
|
||||
import renpy.display.imagemap #@UnresolvedImport
|
||||
import renpy.display.predict #@UnresolvedImport
|
||||
|
||||
import renpy.display.error
|
||||
import renpy.display.error #@UnresolvedImport
|
||||
|
||||
# Note: For windows to work, renpy.audio.audio needs to be after
|
||||
# renpy.display.module.
|
||||
import renpy.audio.audio
|
||||
import renpy.audio.music
|
||||
import renpy.audio.sound
|
||||
import renpy.audio.audio #@UnresolvedImport
|
||||
import renpy.audio.music #@UnresolvedImport
|
||||
import renpy.audio.sound #@UnresolvedImport
|
||||
|
||||
import renpy.ui
|
||||
import renpy.screenlang
|
||||
import renpy.ui #@UnresolvedImport
|
||||
import renpy.screenlang #@UnresolvedImport
|
||||
|
||||
import renpy.lint
|
||||
import renpy.warp
|
||||
import renpy.lint #@UnresolvedImport
|
||||
import renpy.warp #@UnresolvedImport
|
||||
|
||||
import renpy.exports
|
||||
import renpy.character # depends on exports.
|
||||
import renpy.exports #@UnresolvedImport
|
||||
import renpy.character # depends on exports. @UnresolvedImport
|
||||
|
||||
import renpy.config # depends on lots.
|
||||
import renpy.store # depends on everything.
|
||||
import renpy.main
|
||||
import renpy.config # depends on lots. @UnresolvedImport
|
||||
import renpy.store # depends on everything. @UnresolvedImport
|
||||
import renpy.main #@UnresolvedImport
|
||||
|
||||
# Import everything into renpy.exports, provided it isn't
|
||||
# already there.
|
||||
@@ -161,7 +172,7 @@ def import_all():
|
||||
# This reloads all modules.
|
||||
def reload_all():
|
||||
|
||||
import renpy
|
||||
import renpy #@UnresolvedImport
|
||||
renpy.log.info("Reloading.")
|
||||
|
||||
# Shut down the cache thread.
|
||||
@@ -189,4 +200,3 @@ def reload_all():
|
||||
renpy.display.draw = None
|
||||
|
||||
import_all()
|
||||
|
||||
|
||||
+27
-8
@@ -27,6 +27,8 @@
|
||||
# updating.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
import re
|
||||
import time
|
||||
import md5
|
||||
@@ -144,8 +146,8 @@ class PyCode(object):
|
||||
pass
|
||||
|
||||
code = self.source
|
||||
if isinstance(code, renpy.python.ast.AST):
|
||||
code = renpy.python.ast.dump(code)
|
||||
if isinstance(code, renpy.python.ast.AST): #@UndefinedVariable
|
||||
code = renpy.python.ast.dump(code) #@UndefinedVariable
|
||||
|
||||
self.hash = chr(renpy.bytecode_version) + md5.md5(code.encode("utf-8")).digest()
|
||||
return self.hash
|
||||
@@ -312,12 +314,18 @@ class Say(Node):
|
||||
'what',
|
||||
'with_',
|
||||
'interact',
|
||||
'attributes',
|
||||
]
|
||||
|
||||
def diff_info(self):
|
||||
return (Say, self.who, self.what)
|
||||
|
||||
def __init__(self, loc, who, what, with_, interact=True):
|
||||
def __setstate__(self, state):
|
||||
self.attributes = None
|
||||
self.interact = True
|
||||
setstate(self, state)
|
||||
|
||||
def __init__(self, loc, who, what, with_, interact=True, attributes=None):
|
||||
|
||||
super(Say, self).__init__(loc)
|
||||
|
||||
@@ -336,8 +344,14 @@ class Say(Node):
|
||||
self.with_ = with_
|
||||
self.interact = interact
|
||||
|
||||
# A tuple of attributes that are applied to the character that's
|
||||
# speaking, or None to disable this behavior.
|
||||
self.attributes = attributes
|
||||
|
||||
def execute(self):
|
||||
|
||||
renpy.exports.say_attributes = self.attributes
|
||||
|
||||
if self.who is not None:
|
||||
if self.who_fast:
|
||||
who = getattr(renpy.store, self.who, None)
|
||||
@@ -364,12 +378,15 @@ class Say(Node):
|
||||
renpy.store._last_say_what = what
|
||||
|
||||
say_menu_with(self.with_, renpy.game.interface.set_transition)
|
||||
renpy.exports.say(who, what, interact=getattr(self, 'interact', True))
|
||||
renpy.exports.say(who, what, interact=self.interact)
|
||||
|
||||
return self.next
|
||||
|
||||
def predict(self):
|
||||
|
||||
old_attributes = renpy.exports.say_attributes
|
||||
renpy.exports.say_attributes = self.attributes
|
||||
|
||||
if self.who is not None:
|
||||
if self.who_fast:
|
||||
who = getattr(renpy.store, self.who)
|
||||
@@ -389,6 +406,8 @@ class Say(Node):
|
||||
|
||||
renpy.exports.predict_say(who, what)
|
||||
|
||||
renpy.exports.say_attributes = old_attributes
|
||||
|
||||
return [ self.next ]
|
||||
|
||||
def scry(self):
|
||||
@@ -733,7 +752,7 @@ def predict_imspec(imspec, scene=False):
|
||||
return
|
||||
|
||||
else:
|
||||
img = renpy.exports.images.get(name, None)
|
||||
img = renpy.display.image.images.get(name, None)
|
||||
if img is None:
|
||||
return
|
||||
|
||||
@@ -742,9 +761,9 @@ def predict_imspec(imspec, scene=False):
|
||||
full_name = (tag,) + full_name[1:]
|
||||
|
||||
if scene:
|
||||
renpy.game.context().predict_info.images.predict_scene(layer)
|
||||
renpy.game.context().images.predict_scene(layer)
|
||||
|
||||
renpy.game.context().predict_info.images.predict_show(tag or name, layer)
|
||||
renpy.game.context().images.predict_show(tag or name, layer)
|
||||
|
||||
renpy.display.predict.displayable(img)
|
||||
|
||||
@@ -900,7 +919,7 @@ class Hide(Node):
|
||||
if tag is None:
|
||||
tag = name[0]
|
||||
|
||||
renpy.game.context().predict_info.images.predict_hide(tag, layer)
|
||||
renpy.game.context().images.predict_hide(tag, layer)
|
||||
|
||||
return [ ]
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@ PROPERTIES = {
|
||||
"xoffset" : int,
|
||||
"yoffset" : int,
|
||||
"offset" : (int, int),
|
||||
"xcenter" : position,
|
||||
"ycenter" : position,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
# at least pcm_ok, we have no sound whatsoever.
|
||||
|
||||
import renpy
|
||||
import renpy.audio
|
||||
import renpy.display
|
||||
|
||||
import time
|
||||
import pygame
|
||||
@@ -48,7 +50,7 @@ if 'pss' not in disable:
|
||||
|
||||
if pss is None:
|
||||
try:
|
||||
import android_sound as pss
|
||||
import android_sound as pss #@UnresolvedImport
|
||||
print "Imported android_sound."
|
||||
except:
|
||||
pass
|
||||
@@ -56,10 +58,10 @@ if 'pss' not in disable:
|
||||
|
||||
if 'mix' not in disable:
|
||||
try:
|
||||
import winmixer as mix; mix
|
||||
import winmixer as mix; mix #@UnresolvedImport
|
||||
except:
|
||||
try:
|
||||
import linmixer as mix; mix
|
||||
import linmixer as mix; mix #@UnresolvedImport
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
# The public API for music in games.
|
||||
|
||||
import renpy
|
||||
import renpy.audio
|
||||
|
||||
# A list of music channels.
|
||||
music_channels = [ ]
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
# TODO: Check to see if SFX are enabled before playing sounds with play or
|
||||
# queue.
|
||||
|
||||
import renpy
|
||||
import renpy.audio
|
||||
|
||||
# This is basically a thin wrapper around music, with the default
|
||||
# channel set to "sound".
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ def extra_imports():
|
||||
import posixpath; posixpath # W0403
|
||||
import ctypes
|
||||
import ctypes.wintypes; ctypes.wintypes
|
||||
import EasyDialogs; EasyDialogs
|
||||
import EasyDialogs; EasyDialogs #@UnresolvedImport
|
||||
import argparse; argparse
|
||||
import compiler; compiler
|
||||
import textwrap; textwrap
|
||||
|
||||
+131
-50
@@ -22,6 +22,8 @@
|
||||
# The Character object (and friends).
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
import re
|
||||
|
||||
# This matches the dialogue-relevant text tags.
|
||||
@@ -558,6 +560,14 @@ class ADVCharacter(object):
|
||||
self.dynamic = v('dynamic')
|
||||
self.screen = v('screen')
|
||||
self.mode = v('mode')
|
||||
|
||||
if renpy.config.new_character_image_argument:
|
||||
if "image" in properties:
|
||||
self.image_tag = properties.pop("image")
|
||||
else:
|
||||
self.image_tag = kind.image_tag
|
||||
else:
|
||||
self.image_tag = None
|
||||
|
||||
self.display_args = dict(
|
||||
interact = d('interact'),
|
||||
@@ -587,8 +597,9 @@ class ADVCharacter(object):
|
||||
self.show_args = { }
|
||||
self.cb_args = { }
|
||||
|
||||
if "image" in properties:
|
||||
self.show_args["image"] = properties.pop("image")
|
||||
if not renpy.config.new_character_image_argument:
|
||||
if "image" in properties:
|
||||
self.show_args["image"] = properties.pop("image")
|
||||
|
||||
if "slow_abortable" in properties:
|
||||
self.what_args["slow_abortable"] = properties.pop("slow_abortable")
|
||||
@@ -662,57 +673,126 @@ class ADVCharacter(object):
|
||||
window_args=self.window_args,
|
||||
screen=self.screen,
|
||||
**self.show_args)
|
||||
|
||||
|
||||
def resolve_say_attributes(self, predict):
|
||||
"""
|
||||
Deals with image attributes associated with the current say
|
||||
statement.
|
||||
"""
|
||||
|
||||
attrs = renpy.exports.get_say_attributes()
|
||||
|
||||
if not attrs:
|
||||
return
|
||||
|
||||
if not self.image_tag:
|
||||
if not predict:
|
||||
raise Exception("Say has image attributes, but there's no image tag associated with the speaking character.")
|
||||
else:
|
||||
return
|
||||
|
||||
tagged_attrs = (self.image_tag,) + attrs
|
||||
images = renpy.game.context().images
|
||||
|
||||
# If image is showing already, resolve it, then show or predict it.
|
||||
if images.showing("master", (self.image_tag,)):
|
||||
|
||||
new_image = images.apply_attributes("master", self.image_tag, tagged_attrs)
|
||||
if new_image is None:
|
||||
new_image = tagged_attrs
|
||||
|
||||
if predict:
|
||||
images.predict_show(new_image)
|
||||
else:
|
||||
renpy.exports.show(new_image)
|
||||
|
||||
else:
|
||||
# Otherwise, just record the attributes of the image.
|
||||
images.predict_show("master", tagged_attrs)
|
||||
|
||||
def __call__(self, what, interact=True, **kwargs):
|
||||
|
||||
# Check self.condition to see if we should show this line at all.
|
||||
|
||||
if not (self.condition is None or renpy.python.py_eval(self.condition)):
|
||||
return True
|
||||
|
||||
if interact:
|
||||
renpy.exports.mode(self.mode)
|
||||
|
||||
# Figure out the arguments to display.
|
||||
display_args = self.display_args.copy()
|
||||
display_args.update(kwargs)
|
||||
display_args["interact"] = display_args["interact"] and interact
|
||||
self.resolve_say_attributes(False)
|
||||
|
||||
who = self.name
|
||||
old_side_image_attributes = renpy.exports.side_image_attributes
|
||||
|
||||
if self.image_tag:
|
||||
attrs = (self.image_tag,) + renpy.game.context().images.get_attributes("master", self.image_tag)
|
||||
else:
|
||||
attrs = None
|
||||
|
||||
renpy.exports.side_image_attributes = attrs
|
||||
|
||||
try:
|
||||
|
||||
if interact:
|
||||
renpy.exports.mode(self.mode)
|
||||
|
||||
# Figure out the arguments to display.
|
||||
display_args = self.display_args.copy()
|
||||
display_args.update(kwargs)
|
||||
display_args["interact"] = display_args["interact"] and interact
|
||||
|
||||
who = self.name
|
||||
|
||||
# If dynamic is set, evaluate the name expression.
|
||||
if self.dynamic:
|
||||
who = renpy.python.py_eval(who)
|
||||
|
||||
if who is not None:
|
||||
who = self.who_prefix + who + self.who_suffix
|
||||
|
||||
what = self.what_prefix + what + self.what_suffix
|
||||
|
||||
# Run the add_function, to add this character to the
|
||||
# things like NVL-mode.
|
||||
self.do_add(who, what)
|
||||
|
||||
# Now, display the damned thing.
|
||||
self.do_display(who, what, cb_args=self.cb_args, **display_args)
|
||||
|
||||
# Indicate that we're done.
|
||||
self.do_done(who, what)
|
||||
|
||||
# Finally, log this line of dialogue.
|
||||
if who and isinstance(who, (str, unicode)):
|
||||
renpy.exports.log(who)
|
||||
renpy.exports.log(what)
|
||||
renpy.exports.log("")
|
||||
|
||||
# If dynamic is set, evaluate the name expression.
|
||||
if self.dynamic:
|
||||
who = renpy.python.py_eval(who)
|
||||
|
||||
if who is not None:
|
||||
who = self.who_prefix + who + self.who_suffix
|
||||
|
||||
what = self.what_prefix + what + self.what_suffix
|
||||
|
||||
# Run the add_function, to add this character to the
|
||||
# things like NVL-mode.
|
||||
self.do_add(who, what)
|
||||
|
||||
# Now, display the damned thing.
|
||||
self.do_display(who, what, cb_args=self.cb_args, **display_args)
|
||||
|
||||
# Indicate that we're done.
|
||||
self.do_done(who, what)
|
||||
|
||||
# Finally, log this line of dialogue.
|
||||
if who and isinstance(who, (str, unicode)):
|
||||
renpy.exports.log(who)
|
||||
renpy.exports.log(what)
|
||||
renpy.exports.log("")
|
||||
finally:
|
||||
|
||||
renpy.exports.side_image_attributes = old_side_image_attributes
|
||||
|
||||
|
||||
def predict(self, what):
|
||||
|
||||
if self.dynamic:
|
||||
who = "<Dynamic>"
|
||||
self.resolve_say_attributes(True)
|
||||
|
||||
old_side_image_attributes = renpy.exports.side_image_attributes
|
||||
|
||||
if self.image_tag:
|
||||
attrs = self.image_tag + renpy.game.context().images.get_attributes("master", self.image_tag)
|
||||
else:
|
||||
who = self.name
|
||||
attrs = None
|
||||
|
||||
renpy.exports.side_image_attributes = attrs
|
||||
|
||||
return self.do_predict(who, what)
|
||||
try:
|
||||
|
||||
if self.dynamic:
|
||||
who = "<Dynamic>"
|
||||
else:
|
||||
who = self.name
|
||||
|
||||
return self.do_predict(who, what)
|
||||
|
||||
finally:
|
||||
renpy.exports.side_image_attributes = None
|
||||
|
||||
def will_interact(self):
|
||||
|
||||
@@ -745,6 +825,17 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
be used to define a template character, and then copy that
|
||||
character with changes.
|
||||
|
||||
**Linked Image**
|
||||
An image tag may be associated with a Character. This allows a
|
||||
say statement involving this character to display an image with
|
||||
the tag, and also allows Ren'Py to automatically select a side
|
||||
image to show when this character speaks.
|
||||
|
||||
`image`
|
||||
|
||||
A string giving the image tag that is linked with this
|
||||
character.
|
||||
|
||||
**Prefixes and Suffixes.**
|
||||
These allow a prefix and suffix to be applied to the name of the
|
||||
character, and to the text being shown. This can be used, for
|
||||
@@ -779,12 +870,6 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
expression. That string will be evaluated before each line
|
||||
of dialogue, and the result used as the name of the character.
|
||||
|
||||
`image`
|
||||
|
||||
If true, then `name` is expected to name an image file. That
|
||||
image is used as the name of the character.
|
||||
|
||||
|
||||
**Controlling Interactions.**
|
||||
These options control if the dialogue is displayed, if an
|
||||
interaction occurs, and the mode that is entered upon display.
|
||||
@@ -888,10 +973,6 @@ def Character(name=NotSet, kind=None, **properties):
|
||||
`window_style` arguments, respectively.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if kind is None:
|
||||
kind = renpy.store.adv
|
||||
|
||||
|
||||
+12
-2
@@ -24,7 +24,7 @@
|
||||
# methods that perform standard tasks, like the say and menu methods.
|
||||
|
||||
# This will be deleted by the end of this file.
|
||||
import renpy
|
||||
import renpy.display
|
||||
import os
|
||||
|
||||
# Can we add more config variables?
|
||||
@@ -434,6 +434,7 @@ screenshot_crop = None
|
||||
gamedir = None
|
||||
basedir = None
|
||||
renpy_base = None
|
||||
commondir = None
|
||||
|
||||
# Should we enable OpenGL mode?
|
||||
gl_enable = True
|
||||
@@ -472,10 +473,19 @@ variants = [ None ]
|
||||
# A function from (auto_parameter, variant) -> displayable.
|
||||
imagemap_auto_function = None
|
||||
|
||||
# Should we keep the running transform when we merely change the image?
|
||||
keep_running_transform = True
|
||||
|
||||
# Should we use image attributes?
|
||||
image_attributes = True
|
||||
|
||||
# Should we use the new version of the character image argument?
|
||||
new_character_image_argument = True
|
||||
|
||||
del renpy
|
||||
del os
|
||||
|
||||
def init():
|
||||
import renpy # W0404
|
||||
import renpy # W0404 @Reimport
|
||||
global style_properties
|
||||
style_properties = renpy.style.style_properties
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
# This file contains support for state-machine controlled animations.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import random
|
||||
|
||||
class State(object):
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
# This contains various Displayables that handle events.
|
||||
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import renpy.audio
|
||||
|
||||
from renpy.display.render import render, Render
|
||||
|
||||
import pygame
|
||||
@@ -628,6 +630,57 @@ def TextButton(text, style='button', text_style='button_text',
|
||||
text = renpy.display.text.Text(text, style=text_style)
|
||||
return Button(text, style=style, clicked=clicked, **properties)
|
||||
|
||||
class ImageButton(Button):
|
||||
"""
|
||||
Used to implement the guts of an image button.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
idle_image,
|
||||
hover_image,
|
||||
insensitive_image = None,
|
||||
activate_image = None,
|
||||
selected_idle_image = None,
|
||||
selected_hover_image = None,
|
||||
selected_insensitive_image = None,
|
||||
selected_activate_image = None,
|
||||
style='image_button',
|
||||
clicked=None,
|
||||
hovered=None,
|
||||
**properties):
|
||||
|
||||
insensitive_image = insensitive_image or idle_image
|
||||
activate_image = activate_image or hover_image
|
||||
|
||||
selected_idle_image = selected_idle_image or idle_image
|
||||
selected_hover_image = selected_hover_image or hover_image
|
||||
selected_insensitive_image = selected_insensitive_image or insensitive_image
|
||||
selected_activate_image = selected_activate_image or activate_image
|
||||
|
||||
self.state_children = dict(
|
||||
idle_ = renpy.easy.displayable(idle_image),
|
||||
hover_ = renpy.easy.displayable(hover_image),
|
||||
insensitive_ = renpy.easy.displayable(insensitive_image),
|
||||
activate_ = renpy.easy.displayable(activate_image),
|
||||
|
||||
selected_idle_ = renpy.easy.displayable(selected_idle_image),
|
||||
selected_hover_ = renpy.easy.displayable(selected_hover_image),
|
||||
selected_insensitive_ = renpy.easy.displayable(selected_insensitive_image),
|
||||
selected_activate_ = renpy.easy.displayable(selected_activate_image),
|
||||
)
|
||||
|
||||
super(ImageButton, self).__init__(renpy.display.layout.Null(),
|
||||
style=style,
|
||||
clicked=clicked,
|
||||
hovered=hovered,
|
||||
**properties)
|
||||
|
||||
def visit(self):
|
||||
return self.state_children.values()
|
||||
|
||||
def get_child(self):
|
||||
return self.style.child or self.state_children[self.style.prefix]
|
||||
|
||||
|
||||
# This is used for an input that takes its focus from a button.
|
||||
class HoveredProxy(object):
|
||||
@@ -1360,6 +1413,4 @@ class MouseArea(renpy.display.core.Displayable):
|
||||
|
||||
run(self.unhovered)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+41
-62
@@ -22,7 +22,8 @@
|
||||
# This file contains code for initializing and managing the display
|
||||
# window.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import renpy.audio
|
||||
|
||||
import pygame
|
||||
import sys
|
||||
@@ -39,7 +40,7 @@ except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import android
|
||||
import android #@UnresolvedImport
|
||||
except:
|
||||
android = None
|
||||
|
||||
@@ -378,53 +379,16 @@ class Displayable(renpy.object.Object):
|
||||
"""
|
||||
|
||||
return self
|
||||
|
||||
|
||||
class ImagePredictInfo(renpy.object.Object):
|
||||
"""
|
||||
This stores information involved in image prediction.
|
||||
"""
|
||||
def _change_transform_child(self, child):
|
||||
"""
|
||||
If this is a transform, makes a copy of the transform and sets
|
||||
the child of the innermost transform to this. Otherwise,
|
||||
simply returns child.
|
||||
"""
|
||||
|
||||
def after_setstate(self):
|
||||
for i in renpy.config.layers + renpy.config.top_layers:
|
||||
self.images.setdefault(i, {})
|
||||
|
||||
def __init__(self, ipi=None):
|
||||
return child
|
||||
|
||||
super(ImagePredictInfo, self).__init__()
|
||||
|
||||
# layer -> (tag -> image name)
|
||||
self.images = { }
|
||||
|
||||
if ipi is None:
|
||||
for i in renpy.config.layers + renpy.config.top_layers:
|
||||
self.images[i] = { }
|
||||
else:
|
||||
for i in renpy.config.layers + renpy.config.top_layers:
|
||||
self.images[i] = ipi.images[i].copy()
|
||||
|
||||
|
||||
def showing(self, layer, name):
|
||||
|
||||
shown = self.images[layer].get(name[0], None)
|
||||
|
||||
if shown is None or len(shown) < len(name):
|
||||
return False
|
||||
|
||||
for a, b in zip(name, shown):
|
||||
if a != b:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def predict_scene(self, layer):
|
||||
self.images[layer].clear()
|
||||
|
||||
def predict_show(self, name, layer):
|
||||
self.images[layer][name[0]] = name
|
||||
|
||||
def predict_hide(self, tag, layer):
|
||||
self.images[layer].pop(tag, None)
|
||||
|
||||
|
||||
class SceneListEntry(renpy.object.Object):
|
||||
@@ -477,7 +441,7 @@ class SceneLists(renpy.object.Object):
|
||||
things to the user.
|
||||
"""
|
||||
|
||||
__version__ = 5
|
||||
__version__ = 6
|
||||
|
||||
def after_setstate(self):
|
||||
for i in renpy.config.layers + renpy.config.top_layers:
|
||||
@@ -508,8 +472,11 @@ class SceneLists(renpy.object.Object):
|
||||
|
||||
if version < 5:
|
||||
self.drag_group = None
|
||||
|
||||
if version < 6:
|
||||
self.shown = self.image_predict_info
|
||||
|
||||
def __init__(self, oldsl, ipi):
|
||||
def __init__(self, oldsl, shown):
|
||||
|
||||
super(SceneLists, self).__init__()
|
||||
|
||||
@@ -526,8 +493,8 @@ class SceneLists(renpy.object.Object):
|
||||
# been applied to the layer as a whole.
|
||||
self.layer_at_list = { }
|
||||
|
||||
# Represents the current stare of image_prediction.
|
||||
self.image_predict_info = ipi
|
||||
# The current shown images,
|
||||
self.shown = shown
|
||||
|
||||
# A list of (layer, tag) pairs that are considered to be
|
||||
# transient.
|
||||
@@ -709,31 +676,43 @@ class SceneLists(renpy.object.Object):
|
||||
self.at_list[layer][key] = at_list
|
||||
|
||||
if key and name:
|
||||
self.image_predict_info.images[layer][key] = name
|
||||
self.shown.predict_show(layer, name)
|
||||
|
||||
if transient:
|
||||
self.additional_transient.append((layer, key))
|
||||
|
||||
l = self.layers[layer]
|
||||
|
||||
|
||||
if atl:
|
||||
thing = renpy.display.motion.ATLTransform(atl, child=thing)
|
||||
|
||||
if not isinstance(thing, renpy.display.motion.Transform):
|
||||
thing = self.transform_state(default_transform, thing)
|
||||
|
||||
add_index, remove_index = self.find_index(layer, key, zorder, behind)
|
||||
|
||||
at = None
|
||||
st = None
|
||||
|
||||
if remove_index is not None:
|
||||
at = l[remove_index].animation_time
|
||||
thing = self.transform_state(l[remove_index].displayable, thing)
|
||||
sle = l[remove_index]
|
||||
at = sle.animation_time
|
||||
old = sle.displayable
|
||||
|
||||
if (not atl and
|
||||
not at_list and
|
||||
renpy.config.keep_running_transform and
|
||||
isinstance(old, renpy.display.motion.Transform)):
|
||||
|
||||
thing = sle.displayable._change_transform_child(thing)
|
||||
else:
|
||||
thing = self.transform_state(l[remove_index].displayable, thing)
|
||||
|
||||
thing.set_transform_event("replace")
|
||||
thing._show()
|
||||
|
||||
else:
|
||||
|
||||
if not isinstance(thing, renpy.display.motion.Transform):
|
||||
thing = self.transform_state(default_transform, thing)
|
||||
|
||||
thing.set_transform_event("show")
|
||||
thing._show()
|
||||
|
||||
@@ -823,7 +802,7 @@ class SceneLists(renpy.object.Object):
|
||||
tag = self.layers[layer][remove_index].tag
|
||||
|
||||
if tag:
|
||||
self.image_predict_info.images[layer].pop(tag, None)
|
||||
self.shown.predict_hide(layer, (tag,))
|
||||
self.at_list[layer].pop(tag, None)
|
||||
|
||||
self.hide_or_replace(layer, remove_index, "hide")
|
||||
@@ -847,7 +826,7 @@ class SceneLists(renpy.object.Object):
|
||||
self.hide_or_replace(layer, i, hide)
|
||||
|
||||
self.at_list[layer].clear()
|
||||
self.image_predict_info.images[layer].clear()
|
||||
self.shown.predict_scene(layer)
|
||||
self.layer_at_list[layer] = (None, [ ])
|
||||
|
||||
def set_layer_at_list(self, layer, at_list):
|
||||
@@ -871,7 +850,7 @@ class SceneLists(renpy.object.Object):
|
||||
is found in the scene list.
|
||||
"""
|
||||
|
||||
return self.image_predict_info.showing(layer, name)
|
||||
return self.shown.showing(layer, name)
|
||||
|
||||
def make_layer(self, layer, properties):
|
||||
"""
|
||||
@@ -1230,7 +1209,7 @@ class Interface(object):
|
||||
draws = { }
|
||||
|
||||
try:
|
||||
import renpy.display.gldraw as gldraw
|
||||
import renpy.display.gldraw as gldraw #@UnresolvedImport
|
||||
draws["gl"] = gldraw.GLDraw
|
||||
except:
|
||||
renpy.log.info("Couldn't import gl renderer.")
|
||||
@@ -1693,7 +1672,7 @@ class Interface(object):
|
||||
|
||||
if android.check_pause():
|
||||
|
||||
import android_sound
|
||||
import android_sound #@UnresolvedImport
|
||||
android_sound.pause_all()
|
||||
|
||||
pygame.time.set_timer(PERIODIC, 0)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# TODO: Use overlap (rather than simple pointer location) to determine
|
||||
# drag and drop.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
from renpy.display.render import render, Render, redraw
|
||||
from renpy.display.core import absolute
|
||||
from renpy.display.behavior import map_event, run
|
||||
@@ -50,7 +50,8 @@ def default_drag_joined(drag):
|
||||
class Drag(renpy.display.core.Displayable, renpy.python.RevertableObject):
|
||||
"""
|
||||
:doc: drag_drop class
|
||||
|
||||
:args: (d=None, drag_name=None, draggable=True, droppable=True, drag_raise=True, dragged=None, dropped=None, drag_handle=(0.0, 0.0, 1.0, 1.0), drag_joined=..., clicked=None, hovered=None, unhovered=None, **properties)
|
||||
|
||||
A displayable that represents an object that can be dragged around
|
||||
its enclosing area. A Drag can also represent an area that
|
||||
other Drags can be dropped on.
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# This file contains code to manage focus on the display.
|
||||
|
||||
import pygame
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
class Focus(object):
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ except:
|
||||
import _renpy_font
|
||||
pygame.font = _renpy_font
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# This contains a map from (fn, size, bold, italics, underline) to the
|
||||
# unloaded font object corresponding to that specification.
|
||||
|
||||
@@ -167,8 +167,8 @@ cdef class GLDraw:
|
||||
# Should we use the fast (but incorrect) dissolve mode?
|
||||
self.fast_dissolve = False # renpy.android
|
||||
|
||||
# Should we use clipping planes or scissors?
|
||||
self.use_clipping_planes = False
|
||||
# Should we use clipping planes or stencils?
|
||||
self.use_clipping_planes = True
|
||||
|
||||
# Should we always report pixels as being always opaque?
|
||||
self.always_opaque = renpy.android
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
# size-based caching and constructing images from operations (like
|
||||
# cropping and scaling).
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
import math
|
||||
import zipfile
|
||||
import cStringIO
|
||||
|
||||
+211
-376
@@ -24,9 +24,31 @@
|
||||
# of the stuff thar uses images remaining.
|
||||
|
||||
import renpy
|
||||
from renpy.display.render import render, Render, Matrix2D
|
||||
import renpy.display
|
||||
from renpy.display.render import render, Render
|
||||
|
||||
import collections
|
||||
|
||||
# A map from image name to the displayable object corresponding to that
|
||||
# image.
|
||||
images = { }
|
||||
|
||||
# A map from image tag to lists of possible attributes for images with that
|
||||
# tag.
|
||||
image_attributes = collections.defaultdict(list)
|
||||
|
||||
def register_image(name, d):
|
||||
"""
|
||||
Registers the existence of an image with `name`, and that the image
|
||||
used displayable d.
|
||||
"""
|
||||
|
||||
tag = name[0]
|
||||
rest = name[1:]
|
||||
|
||||
images[name] = d
|
||||
image_attributes[tag].append(rest)
|
||||
|
||||
Image = renpy.display.im.image
|
||||
|
||||
def wrap_render(child, w, h, st, at):
|
||||
rend = render(child, w, h, st, at)
|
||||
@@ -88,8 +110,8 @@ class ImageReference(renpy.display.core.Displayable):
|
||||
# Scan through, searching for an image (defined with an
|
||||
# input statement) that is a prefix of the given name.
|
||||
while name:
|
||||
if name in renpy.exports.images:
|
||||
target = renpy.exports.images[name]
|
||||
if name in images:
|
||||
target = images[name]
|
||||
|
||||
try:
|
||||
self.target = target.parameterize(name, parameters)
|
||||
@@ -164,392 +186,205 @@ class ImageReference(renpy.display.core.Displayable):
|
||||
self.find_target()
|
||||
|
||||
return [ self.target ]
|
||||
|
||||
|
||||
|
||||
|
||||
class Solid(renpy.display.core.Displayable):
|
||||
class ShownImageInfo(renpy.object.Object):
|
||||
"""
|
||||
:doc: disp_imagelike
|
||||
|
||||
A displayable that fills the area its assigned with `color`.
|
||||
|
||||
::
|
||||
|
||||
image white = Solid("#fff")
|
||||
|
||||
This class keeps track of which images are being shown right now,
|
||||
and what the attributes of those images are. (It's used for a similar
|
||||
purpose during prediction, regarding the state in the future.)
|
||||
"""
|
||||
|
||||
def __init__(self, color, **properties):
|
||||
|
||||
super(Solid, self).__init__(**properties)
|
||||
|
||||
if color is not None:
|
||||
self.color = renpy.easy.color(color)
|
||||
else:
|
||||
self.color = None
|
||||
|
||||
def visit(self):
|
||||
if self.color:
|
||||
return [ renpy.display.im.SolidImage(self.color, 4, 4) ]
|
||||
else:
|
||||
return [ ]
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
color = self.color or self.style.color
|
||||
|
||||
rv = Render(width, height)
|
||||
|
||||
if color is None or width <= 0 or height <= 0:
|
||||
return rv
|
||||
|
||||
SIZE = 10
|
||||
|
||||
si = renpy.display.im.SolidImage(color, SIZE, SIZE)
|
||||
sr = render(si, SIZE, SIZE, st, at)
|
||||
|
||||
rv.forward = Matrix2D(1.0 * SIZE / width, 0, 0, 1.0 * SIZE / height)
|
||||
rv.reverse = Matrix2D(1.0 * width / SIZE, 0, 0, 1.0 * height / SIZE)
|
||||
rv.blit(sr, (0, 0))
|
||||
|
||||
return rv
|
||||
|
||||
class Frame(renpy.display.core.Displayable):
|
||||
"""
|
||||
:doc: disp_imagelike
|
||||
:args: (image, xborder, yborder, tile=False, **properties)
|
||||
|
||||
A displayable that resizes an image to fill the available area,
|
||||
while preserving the width and height of its borders. is often
|
||||
used as the background of a window or button.
|
||||
__version__ = 2
|
||||
|
||||
.. figure:: frame_example.png
|
||||
|
||||
Using a frame to resize an image to double its size.
|
||||
|
||||
`image`
|
||||
An image manipulator that will be resized by this frame.
|
||||
|
||||
`xborder`
|
||||
The width of the border on the left and right sides of the
|
||||
image.
|
||||
|
||||
`yborder`
|
||||
The height of the border on the top and bottom sides of the
|
||||
image.
|
||||
|
||||
`tile`
|
||||
If true, tiling is used to resize sections of the image,
|
||||
rather than scaling.
|
||||
|
||||
::
|
||||
|
||||
# Resize the background of the text window if it's too small.
|
||||
init python:
|
||||
style.window.background = Frame("frame.png", 10, 10)
|
||||
def __init__(self, old=None):
|
||||
"""
|
||||
Creates a new object. If `old` is given, copies the default state
|
||||
from old, otherwise initializes the object to a default state.
|
||||
"""
|
||||
|
||||
__version__ = 1
|
||||
if old is None:
|
||||
|
||||
def __init__(self, image, xborder, yborder, bilinear=True, tile=False, **properties):
|
||||
super(Frame, self).__init__(**properties)
|
||||
# A map from (layer, tag) -> tuple of attributes
|
||||
# This doesn't necessarily correspond to something that is
|
||||
# currently showing, as we can remember the state of a tag
|
||||
# for use in SideImage.
|
||||
self.attributes = { }
|
||||
|
||||
self.image = renpy.easy.displayable(image)
|
||||
self.xborder = xborder
|
||||
self.yborder = yborder
|
||||
self.tile = tile
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
crend = render(self.image, width, height, st, at)
|
||||
|
||||
if isinstance(renpy.display.draw, renpy.display.swdraw.SWDraw):
|
||||
return self.sw_render(crend, width, height)
|
||||
|
||||
def draw(x0, x1, y0, y1):
|
||||
|
||||
# Compute the coordinates of the left, right, top, and
|
||||
# bottom sides of the region, for both the source and
|
||||
# destination surfaces.
|
||||
|
||||
# left side.
|
||||
if x0 >= 0:
|
||||
dx0 = x0
|
||||
sx0 = x0
|
||||
else:
|
||||
dx0 = dw + x0
|
||||
sx0 = sw + x0
|
||||
|
||||
# right side.
|
||||
if x1 > 0:
|
||||
dx1 = x1
|
||||
sx1 = x1
|
||||
else:
|
||||
dx1 = dw + x1
|
||||
sx1 = sw + x1
|
||||
|
||||
# top side.
|
||||
if y0 >= 0:
|
||||
dy0 = y0
|
||||
sy0 = y0
|
||||
else:
|
||||
dy0 = dh + y0
|
||||
sy0 = sh + y0
|
||||
|
||||
# bottom side
|
||||
if y1 > 0:
|
||||
dy1 = y1
|
||||
sy1 = y1
|
||||
else:
|
||||
dy1 = dh + y1
|
||||
sy1 = sh + y1
|
||||
|
||||
# Quick exit.
|
||||
if sx0 == sx1 or sy0 == sy1:
|
||||
return
|
||||
|
||||
# Compute sizes.
|
||||
csw = sx1 - sx0
|
||||
csh = sy1 - sy0
|
||||
cdw = dx1 - dx0
|
||||
cdh = dy1 - dy0
|
||||
|
||||
if csw <= 0 or csh <= 0 or cdh <= 0 or cdw <= 0:
|
||||
return
|
||||
|
||||
# Get a subsurface.
|
||||
cr = crend.subsurface((sx0, sy0, csw, csh))
|
||||
|
||||
# Scale or tile if we have to.
|
||||
if csw != cdw or csh != cdh:
|
||||
|
||||
if self.tile:
|
||||
newcr = Render(cdw, cdh)
|
||||
newcr.clipping = True
|
||||
|
||||
for x in xrange(0, cdw, csw):
|
||||
for y in xrange(0, cdh, csh):
|
||||
newcr.blit(cr, (x, y))
|
||||
|
||||
cr = newcr
|
||||
|
||||
else:
|
||||
|
||||
newcr = Render(cdw, cdh)
|
||||
newcr.forward = Matrix2D(1.0 * csw / cdw, 0, 0, 1.0 * csh / cdh)
|
||||
newcr.reverse = Matrix2D(1.0 * cdw / csw, 0, 0, 1.0 * cdh / csh)
|
||||
newcr.blit(cr, (0, 0))
|
||||
|
||||
cr = newcr
|
||||
|
||||
# Blit.
|
||||
rv.blit(cr, (dx0, dy0))
|
||||
return
|
||||
|
||||
|
||||
sw, sh = crend.get_size()
|
||||
dw = int(width)
|
||||
dh = int(height)
|
||||
|
||||
xb = min(self.xborder, sw / 2 - 1, width / 2 - 1)
|
||||
yb = min(self.yborder, sh / 2 - 1, height / 2 - 1)
|
||||
|
||||
rv = Render(dw, dh)
|
||||
|
||||
self.draw_pattern(draw, xb, yb)
|
||||
|
||||
return rv
|
||||
|
||||
def draw_pattern(self, draw, xb, yb):
|
||||
# Top row.
|
||||
if yb:
|
||||
|
||||
if xb:
|
||||
draw(0, xb, 0, yb)
|
||||
|
||||
draw(xb, -xb, 0, yb)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, 0, yb)
|
||||
|
||||
# Middle row.
|
||||
if xb:
|
||||
draw(0, xb, yb, -yb)
|
||||
|
||||
draw(xb, -xb, yb, -yb)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, yb, -yb)
|
||||
|
||||
# Bottom row.
|
||||
if yb:
|
||||
if xb:
|
||||
draw(0, xb, -yb, 0)
|
||||
|
||||
draw(xb, -xb, -yb, 0)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, -yb, 0)
|
||||
# A set of (layer, tag) pairs that are being shown on the
|
||||
# screen right now.
|
||||
self.shown = set()
|
||||
|
||||
else:
|
||||
self.attributes = old.attributes.copy()
|
||||
self.shown = old.shown.copy()
|
||||
|
||||
|
||||
def sw_render(self, crend, width, height):
|
||||
|
||||
source = crend.render_to_texture(True)
|
||||
|
||||
dw = int(width)
|
||||
dh = int(height)
|
||||
|
||||
dest = renpy.display.pgrender.surface((dw, dh), True)
|
||||
rv = dest
|
||||
|
||||
dest = renpy.display.scale.real(dest)
|
||||
source = renpy.display.scale.real(source)
|
||||
|
||||
xb = renpy.display.scale.scale(self.xborder)
|
||||
yb = renpy.display.scale.scale(self.yborder)
|
||||
|
||||
sw, sh = source.get_size()
|
||||
dw, dh = dest.get_size()
|
||||
|
||||
xb = min(xb, sw / 2 - 1, dw / 2 - 1)
|
||||
yb = min(yb, sh / 2 - 1, dh / 2 - 1)
|
||||
|
||||
def draw(x0, x1, y0, y1):
|
||||
|
||||
# Compute the coordinates of the left, right, top, and
|
||||
# bottom sides of the region, for both the source and
|
||||
# destination surfaces.
|
||||
|
||||
# left side.
|
||||
if x0 >= 0:
|
||||
dx0 = x0
|
||||
sx0 = x0
|
||||
else:
|
||||
dx0 = dw + x0
|
||||
sx0 = sw + x0
|
||||
|
||||
# right side.
|
||||
if x1 > 0:
|
||||
dx1 = x1
|
||||
sx1 = x1
|
||||
else:
|
||||
dx1 = dw + x1
|
||||
sx1 = sw + x1
|
||||
|
||||
# top side.
|
||||
if y0 >= 0:
|
||||
dy0 = y0
|
||||
sy0 = y0
|
||||
else:
|
||||
dy0 = dh + y0
|
||||
sy0 = sh + y0
|
||||
|
||||
# bottom side
|
||||
if y1 > 0:
|
||||
dy1 = y1
|
||||
sy1 = y1
|
||||
else:
|
||||
dy1 = dh + y1
|
||||
|
||||
sy1 = sh + y1
|
||||
|
||||
# Quick exit.
|
||||
if sx0 == sx1 or sy0 == sy1 or dx1 <= dx0 or dy1 <= dy0:
|
||||
return
|
||||
|
||||
# Compute sizes.
|
||||
srcsize = (sx1 - sx0, sy1 - sy0)
|
||||
dstsize = (int(dx1 - dx0), int(dy1 - dy0))
|
||||
def after_upgrade(self, version):
|
||||
if version < 2:
|
||||
|
||||
self.attributes = { }
|
||||
self.shown = { }
|
||||
|
||||
|
||||
# Get a subsurface.
|
||||
surf = source.subsurface((sx0, sy0, srcsize[0], srcsize[1]))
|
||||
|
||||
# Scale or tile if we have to.
|
||||
if dstsize != srcsize:
|
||||
if self.tile:
|
||||
tilew, tileh = srcsize
|
||||
dstw, dsth = dstsize
|
||||
|
||||
surf2 = renpy.display.pgrender.surface_unscaled(dstsize, surf)
|
||||
|
||||
for y in range(0, dsth, tileh):
|
||||
for x in range(0, dstw, tilew):
|
||||
surf2.blit(surf, (x, y))
|
||||
|
||||
surf = surf2
|
||||
|
||||
else:
|
||||
surf2 = renpy.display.scale.real_transform_scale(surf, dstsize)
|
||||
surf = surf2
|
||||
|
||||
# Blit.
|
||||
dest.blit(surf, (dx0, dy0))
|
||||
|
||||
self.draw_pattern(draw, xb, yb)
|
||||
|
||||
rrv = renpy.display.render.Render(width, height)
|
||||
rrv.blit(rv, (0, 0))
|
||||
rrv.depends_on(crend)
|
||||
|
||||
# And, finish up.
|
||||
return rrv
|
||||
|
||||
|
||||
|
||||
def visit(self):
|
||||
return [ self.image ]
|
||||
|
||||
|
||||
class ImageButton(renpy.display.behavior.Button):
|
||||
"""
|
||||
Used to implement the guts of an image button.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
idle_image,
|
||||
hover_image,
|
||||
insensitive_image = None,
|
||||
activate_image = None,
|
||||
selected_idle_image = None,
|
||||
selected_hover_image = None,
|
||||
selected_insensitive_image = None,
|
||||
selected_activate_image = None,
|
||||
style='image_button',
|
||||
clicked=None,
|
||||
hovered=None,
|
||||
**properties):
|
||||
|
||||
insensitive_image = insensitive_image or idle_image
|
||||
activate_image = activate_image or hover_image
|
||||
|
||||
selected_idle_image = selected_idle_image or idle_image
|
||||
selected_hover_image = selected_hover_image or hover_image
|
||||
selected_insensitive_image = selected_insensitive_image or insensitive_image
|
||||
selected_activate_image = selected_activate_image or activate_image
|
||||
|
||||
self.state_children = dict(
|
||||
idle_ = renpy.easy.displayable(idle_image),
|
||||
hover_ = renpy.easy.displayable(hover_image),
|
||||
insensitive_ = renpy.easy.displayable(insensitive_image),
|
||||
activate_ = renpy.easy.displayable(activate_image),
|
||||
|
||||
selected_idle_ = renpy.easy.displayable(selected_idle_image),
|
||||
selected_hover_ = renpy.easy.displayable(selected_hover_image),
|
||||
selected_insensitive_ = renpy.easy.displayable(selected_insensitive_image),
|
||||
selected_activate_ = renpy.easy.displayable(selected_activate_image),
|
||||
)
|
||||
|
||||
super(ImageButton, self).__init__(renpy.display.layout.Null(),
|
||||
style=style,
|
||||
clicked=clicked,
|
||||
hovered=hovered,
|
||||
**properties)
|
||||
for layer in self.images:
|
||||
for tag in layer:
|
||||
self.attributes[layer, tag] = layer[tag][1:]
|
||||
self.shown.add((layer, tag))
|
||||
|
||||
def get_attributes(self, layer, tag):
|
||||
"""
|
||||
Get the attributes associated the image with tag on the given
|
||||
layer.
|
||||
"""
|
||||
|
||||
def visit(self):
|
||||
return self.state_children.values()
|
||||
return self.attributes.get((layer, tag), ())
|
||||
|
||||
def get_child(self):
|
||||
return self.style.child or self.state_children[self.style.prefix]
|
||||
|
||||
def showing(self, layer, name):
|
||||
"""
|
||||
Returns true if name is the prefix of an image that is showing
|
||||
on layer, or false otherwise.
|
||||
"""
|
||||
|
||||
|
||||
tag = name[0]
|
||||
rest = name[1:]
|
||||
|
||||
if (layer, tag) not in self.shown:
|
||||
return None
|
||||
|
||||
shown = self.attributes[layer, tag]
|
||||
|
||||
if len(shown) < len(rest):
|
||||
return False
|
||||
|
||||
for a, b in zip(name, rest):
|
||||
if a != b:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def predict_scene(self, layer):
|
||||
"""
|
||||
Predicts the scene statement being called on layer.
|
||||
"""
|
||||
|
||||
for l, t in self.attributes.keys():
|
||||
if l == layer:
|
||||
del self.attributes[l, t]
|
||||
|
||||
self.shown = set((l, t) for l, t in self.shown if l != layer)
|
||||
|
||||
def predict_show(self, layer, name):
|
||||
"""
|
||||
Predicts name being shown on layer.
|
||||
"""
|
||||
|
||||
tag = name[0]
|
||||
rest = name[1:]
|
||||
|
||||
self.attributes[layer, tag] = rest
|
||||
self.shown.add((layer, tag))
|
||||
|
||||
def predict_hide(self, layer, name):
|
||||
tag = name[0]
|
||||
|
||||
if (layer, tag) in self.attributes:
|
||||
del self.attributes[layer, tag]
|
||||
|
||||
self.shown.discard((layer, tag))
|
||||
|
||||
|
||||
def apply_attributes(self, layer, tag, name):
|
||||
"""
|
||||
Given a layer, tag, and an image name (with attributes),
|
||||
returns the canonical name of an image, if one exists. Raises
|
||||
an exception if it's ambiguious, and returns None if an image
|
||||
with that name couldn't be found.
|
||||
"""
|
||||
|
||||
# If the name matches one that exactly exists, return it.
|
||||
if name in images:
|
||||
return name
|
||||
|
||||
nametag = name[0]
|
||||
|
||||
# The set of attributes a matching image must have.
|
||||
required = set(name[1:])
|
||||
|
||||
# The set of attributes a matching image may have.
|
||||
optional = set(self.attributes.get((layer, tag), [ ]))
|
||||
|
||||
# Deal with banned attributes..
|
||||
for i in name[1:]:
|
||||
if i[0] == "-":
|
||||
optional.discard(i[1:])
|
||||
required.discard(i)
|
||||
|
||||
return self.choose_image(nametag, required, optional, name)
|
||||
|
||||
def choose_image(self, tag, required, optional, exception_name):
|
||||
"""
|
||||
Choose a single unique image for
|
||||
|
||||
"""
|
||||
|
||||
# The longest length of an image that matches.
|
||||
max_len = 0
|
||||
|
||||
# The list of matching images.
|
||||
matches = None
|
||||
|
||||
for attrs in image_attributes[tag]:
|
||||
|
||||
num_required = 0
|
||||
|
||||
for i in attrs:
|
||||
if i in required:
|
||||
num_required += 1
|
||||
continue
|
||||
|
||||
elif i not in optional:
|
||||
break
|
||||
|
||||
else:
|
||||
|
||||
# We don't have any not-found attributes. But we might not
|
||||
# have all of the attributes.
|
||||
|
||||
if num_required != len(required):
|
||||
continue
|
||||
|
||||
len_attrs = len(attrs)
|
||||
|
||||
if len_attrs < max_len:
|
||||
continue
|
||||
|
||||
if len_attrs > max_len:
|
||||
max_len = len_attrs
|
||||
matches = [ ]
|
||||
|
||||
matches.append((tag, ) + attrs)
|
||||
|
||||
if matches is None:
|
||||
return None
|
||||
|
||||
if len(matches) == 1:
|
||||
return matches[0]
|
||||
|
||||
if exception_name:
|
||||
raise Exception("Showing '" + " ".join(exception_name) + "' is ambiguous, possible images include: " + ", ".join(" ".join(i) for i in matches))
|
||||
else:
|
||||
return None
|
||||
|
||||
renpy.display.core.ImagePredictInfo = ShownImageInfo
|
||||
|
||||
|
||||
# Functions that have moved from this module to other modules,
|
||||
# that live here for the purpose of backward-compatibility.
|
||||
Image = renpy.display.im.image
|
||||
Solid = renpy.display.imagelike.Solid
|
||||
Frame = renpy.display.imagelike.Frame
|
||||
ImageButton = renpy.display.behavior.ImageButton
|
||||
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
# Copyright 2004-2011 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.
|
||||
|
||||
import renpy.display
|
||||
from renpy.display.render import render, Render, Matrix2D
|
||||
|
||||
# This file contains displayables that are image-like, because they take
|
||||
# up a rectangular area of the screen, and do not respond to input.
|
||||
|
||||
class Solid(renpy.display.core.Displayable):
|
||||
"""
|
||||
:doc: disp_imagelike
|
||||
|
||||
A displayable that fills the area its assigned with `color`.
|
||||
|
||||
::
|
||||
|
||||
image white = Solid("#fff")
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, color, **properties):
|
||||
|
||||
super(Solid, self).__init__(**properties)
|
||||
|
||||
if color is not None:
|
||||
self.color = renpy.easy.color(color)
|
||||
else:
|
||||
self.color = None
|
||||
|
||||
def visit(self):
|
||||
if self.color:
|
||||
return [ renpy.display.im.SolidImage(self.color, 4, 4) ]
|
||||
else:
|
||||
return [ ]
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
color = self.color or self.style.color
|
||||
|
||||
rv = Render(width, height)
|
||||
|
||||
if color is None or width <= 0 or height <= 0:
|
||||
return rv
|
||||
|
||||
SIZE = 10
|
||||
|
||||
si = renpy.display.im.SolidImage(color, SIZE, SIZE)
|
||||
sr = render(si, SIZE, SIZE, st, at)
|
||||
|
||||
rv.forward = Matrix2D(1.0 * SIZE / width, 0, 0, 1.0 * SIZE / height)
|
||||
rv.reverse = Matrix2D(1.0 * width / SIZE, 0, 0, 1.0 * height / SIZE)
|
||||
rv.blit(sr, (0, 0))
|
||||
|
||||
return rv
|
||||
|
||||
class Frame(renpy.display.core.Displayable):
|
||||
"""
|
||||
:doc: disp_imagelike
|
||||
:args: (image, xborder, yborder, tile=False, **properties)
|
||||
|
||||
A displayable that resizes an image to fill the available area,
|
||||
while preserving the width and height of its borders. is often
|
||||
used as the background of a window or button.
|
||||
|
||||
.. figure:: frame_example.png
|
||||
|
||||
Using a frame to resize an image to double its size.
|
||||
|
||||
`image`
|
||||
An image manipulator that will be resized by this frame.
|
||||
|
||||
`xborder`
|
||||
The width of the border on the left and right sides of the
|
||||
image.
|
||||
|
||||
`yborder`
|
||||
The height of the border on the top and bottom sides of the
|
||||
image.
|
||||
|
||||
`tile`
|
||||
If true, tiling is used to resize sections of the image,
|
||||
rather than scaling.
|
||||
|
||||
::
|
||||
|
||||
# Resize the background of the text window if it's too small.
|
||||
init python:
|
||||
style.window.background = Frame("frame.png", 10, 10)
|
||||
"""
|
||||
|
||||
__version__ = 1
|
||||
|
||||
def __init__(self, image, xborder, yborder, bilinear=True, tile=False, **properties):
|
||||
super(Frame, self).__init__(**properties)
|
||||
|
||||
self.image = renpy.easy.displayable(image)
|
||||
self.xborder = xborder
|
||||
self.yborder = yborder
|
||||
self.tile = tile
|
||||
|
||||
def render(self, width, height, st, at):
|
||||
|
||||
crend = render(self.image, width, height, st, at)
|
||||
|
||||
if isinstance(renpy.display.draw, renpy.display.swdraw.SWDraw):
|
||||
return self.sw_render(crend, width, height)
|
||||
|
||||
def draw(x0, x1, y0, y1):
|
||||
|
||||
# Compute the coordinates of the left, right, top, and
|
||||
# bottom sides of the region, for both the source and
|
||||
# destination surfaces.
|
||||
|
||||
# left side.
|
||||
if x0 >= 0:
|
||||
dx0 = x0
|
||||
sx0 = x0
|
||||
else:
|
||||
dx0 = dw + x0
|
||||
sx0 = sw + x0
|
||||
|
||||
# right side.
|
||||
if x1 > 0:
|
||||
dx1 = x1
|
||||
sx1 = x1
|
||||
else:
|
||||
dx1 = dw + x1
|
||||
sx1 = sw + x1
|
||||
|
||||
# top side.
|
||||
if y0 >= 0:
|
||||
dy0 = y0
|
||||
sy0 = y0
|
||||
else:
|
||||
dy0 = dh + y0
|
||||
sy0 = sh + y0
|
||||
|
||||
# bottom side
|
||||
if y1 > 0:
|
||||
dy1 = y1
|
||||
sy1 = y1
|
||||
else:
|
||||
dy1 = dh + y1
|
||||
sy1 = sh + y1
|
||||
|
||||
# Quick exit.
|
||||
if sx0 == sx1 or sy0 == sy1:
|
||||
return
|
||||
|
||||
# Compute sizes.
|
||||
csw = sx1 - sx0
|
||||
csh = sy1 - sy0
|
||||
cdw = dx1 - dx0
|
||||
cdh = dy1 - dy0
|
||||
|
||||
if csw <= 0 or csh <= 0 or cdh <= 0 or cdw <= 0:
|
||||
return
|
||||
|
||||
# Get a subsurface.
|
||||
cr = crend.subsurface((sx0, sy0, csw, csh))
|
||||
|
||||
# Scale or tile if we have to.
|
||||
if csw != cdw or csh != cdh:
|
||||
|
||||
if self.tile:
|
||||
newcr = Render(cdw, cdh)
|
||||
newcr.clipping = True
|
||||
|
||||
for x in xrange(0, cdw, csw):
|
||||
for y in xrange(0, cdh, csh):
|
||||
newcr.blit(cr, (x, y))
|
||||
|
||||
cr = newcr
|
||||
|
||||
else:
|
||||
|
||||
newcr = Render(cdw, cdh)
|
||||
newcr.forward = Matrix2D(1.0 * csw / cdw, 0, 0, 1.0 * csh / cdh)
|
||||
newcr.reverse = Matrix2D(1.0 * cdw / csw, 0, 0, 1.0 * cdh / csh)
|
||||
newcr.blit(cr, (0, 0))
|
||||
|
||||
cr = newcr
|
||||
|
||||
# Blit.
|
||||
rv.blit(cr, (dx0, dy0))
|
||||
return
|
||||
|
||||
|
||||
sw, sh = crend.get_size()
|
||||
dw = int(width)
|
||||
dh = int(height)
|
||||
|
||||
xb = min(self.xborder, sw / 2 - 1, width / 2 - 1)
|
||||
yb = min(self.yborder, sh / 2 - 1, height / 2 - 1)
|
||||
|
||||
rv = Render(dw, dh)
|
||||
|
||||
self.draw_pattern(draw, xb, yb)
|
||||
|
||||
return rv
|
||||
|
||||
def draw_pattern(self, draw, xb, yb):
|
||||
# Top row.
|
||||
if yb:
|
||||
|
||||
if xb:
|
||||
draw(0, xb, 0, yb)
|
||||
|
||||
draw(xb, -xb, 0, yb)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, 0, yb)
|
||||
|
||||
# Middle row.
|
||||
if xb:
|
||||
draw(0, xb, yb, -yb)
|
||||
|
||||
draw(xb, -xb, yb, -yb)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, yb, -yb)
|
||||
|
||||
# Bottom row.
|
||||
if yb:
|
||||
if xb:
|
||||
draw(0, xb, -yb, 0)
|
||||
|
||||
draw(xb, -xb, -yb, 0)
|
||||
|
||||
if xb:
|
||||
draw(-xb, 0, -yb, 0)
|
||||
|
||||
|
||||
|
||||
def sw_render(self, crend, width, height):
|
||||
|
||||
source = crend.render_to_texture(True)
|
||||
|
||||
dw = int(width)
|
||||
dh = int(height)
|
||||
|
||||
dest = renpy.display.pgrender.surface((dw, dh), True)
|
||||
rv = dest
|
||||
|
||||
dest = renpy.display.scale.real(dest)
|
||||
source = renpy.display.scale.real(source)
|
||||
|
||||
xb = renpy.display.scale.scale(self.xborder)
|
||||
yb = renpy.display.scale.scale(self.yborder)
|
||||
|
||||
sw, sh = source.get_size()
|
||||
dw, dh = dest.get_size()
|
||||
|
||||
xb = min(xb, sw / 2 - 1, dw / 2 - 1)
|
||||
yb = min(yb, sh / 2 - 1, dh / 2 - 1)
|
||||
|
||||
def draw(x0, x1, y0, y1):
|
||||
|
||||
# Compute the coordinates of the left, right, top, and
|
||||
# bottom sides of the region, for both the source and
|
||||
# destination surfaces.
|
||||
|
||||
# left side.
|
||||
if x0 >= 0:
|
||||
dx0 = x0
|
||||
sx0 = x0
|
||||
else:
|
||||
dx0 = dw + x0
|
||||
sx0 = sw + x0
|
||||
|
||||
# right side.
|
||||
if x1 > 0:
|
||||
dx1 = x1
|
||||
sx1 = x1
|
||||
else:
|
||||
dx1 = dw + x1
|
||||
sx1 = sw + x1
|
||||
|
||||
# top side.
|
||||
if y0 >= 0:
|
||||
dy0 = y0
|
||||
sy0 = y0
|
||||
else:
|
||||
dy0 = dh + y0
|
||||
sy0 = sh + y0
|
||||
|
||||
# bottom side
|
||||
if y1 > 0:
|
||||
dy1 = y1
|
||||
sy1 = y1
|
||||
else:
|
||||
dy1 = dh + y1
|
||||
|
||||
sy1 = sh + y1
|
||||
|
||||
# Quick exit.
|
||||
if sx0 == sx1 or sy0 == sy1 or dx1 <= dx0 or dy1 <= dy0:
|
||||
return
|
||||
|
||||
# Compute sizes.
|
||||
srcsize = (sx1 - sx0, sy1 - sy0)
|
||||
dstsize = (int(dx1 - dx0), int(dy1 - dy0))
|
||||
|
||||
|
||||
|
||||
# Get a subsurface.
|
||||
surf = source.subsurface((sx0, sy0, srcsize[0], srcsize[1]))
|
||||
|
||||
# Scale or tile if we have to.
|
||||
if dstsize != srcsize:
|
||||
if self.tile:
|
||||
tilew, tileh = srcsize
|
||||
dstw, dsth = dstsize
|
||||
|
||||
surf2 = renpy.display.pgrender.surface_unscaled(dstsize, surf)
|
||||
|
||||
for y in range(0, dsth, tileh):
|
||||
for x in range(0, dstw, tilew):
|
||||
surf2.blit(surf, (x, y))
|
||||
|
||||
surf = surf2
|
||||
|
||||
else:
|
||||
surf2 = renpy.display.scale.real_transform_scale(surf, dstsize)
|
||||
surf = surf2
|
||||
|
||||
# Blit.
|
||||
dest.blit(surf, (dx0, dy0))
|
||||
|
||||
self.draw_pattern(draw, xb, yb)
|
||||
|
||||
rrv = renpy.display.render.Render(width, height)
|
||||
rrv.blit(rv, (0, 0))
|
||||
rrv.depends_on(crend)
|
||||
|
||||
# And, finish up.
|
||||
return rrv
|
||||
|
||||
def visit(self):
|
||||
return [ self.image ]
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# This file handles imagemap caching.
|
||||
|
||||
import pygame
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
from renpy.display.render import render
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
import os
|
||||
import pygame
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# Do we have a joystick enabled?
|
||||
enabled = False
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# This file contains classes that handle layout of displayables on
|
||||
# the screen.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
from renpy.display.render import render, Render
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
# The minigame API.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# A map from (text, font, size, color, bold, italics, underline) -> surface.
|
||||
# This one is for the old frame.
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
VERSION = (6, 12, 0)
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import pygame; pygame # prevents pyflakes warning.
|
||||
|
||||
import sys
|
||||
@@ -94,9 +94,6 @@ def scale(s, size):
|
||||
Always works, but may not be high quality.
|
||||
"""
|
||||
|
||||
width, height = s.get_size()
|
||||
dx, dy = size
|
||||
|
||||
d = renpy.display.pgrender.surface(size, True)
|
||||
|
||||
bilinear_scale(s, d)
|
||||
|
||||
+40
-7
@@ -25,7 +25,7 @@
|
||||
import math
|
||||
import types
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
from renpy.display.render import render
|
||||
from renpy.display.layout import Container
|
||||
|
||||
@@ -325,6 +325,22 @@ class TransformState(renpy.object.Object):
|
||||
|
||||
offset = property(get_offset, set_offset)
|
||||
|
||||
def set_xcenter(self, value):
|
||||
self.xpos = value
|
||||
self.xanchor = 0.5
|
||||
|
||||
def get_xcenter(self):
|
||||
return self.xpos
|
||||
|
||||
def set_ycenter(self, value):
|
||||
self.ypos = value
|
||||
self.yanchor = 0.5
|
||||
|
||||
def get_ycenter(self):
|
||||
return self.ypos
|
||||
|
||||
xcenter = property(get_xcenter, set_xcenter)
|
||||
ycenter = property(get_ycenter, set_ycenter)
|
||||
|
||||
class Proxy(object):
|
||||
"""
|
||||
@@ -388,6 +404,9 @@ class Transform(Container):
|
||||
offset = Proxy("offset")
|
||||
|
||||
subpixel = Proxy("subpixel")
|
||||
|
||||
xcenter = Proxy("xcenter")
|
||||
ycenter = Proxy("ycenter")
|
||||
|
||||
def after_upgrade(self, version):
|
||||
|
||||
@@ -568,14 +587,30 @@ class Transform(Container):
|
||||
|
||||
return
|
||||
|
||||
|
||||
def copy(self):
|
||||
"""
|
||||
Makes a copy of this transform.
|
||||
"""
|
||||
|
||||
d = self()
|
||||
d.kwargs = { }
|
||||
d.take_state(self)
|
||||
d.take_execution_state(self)
|
||||
d.st = self.st
|
||||
d.at = self.at
|
||||
|
||||
return d
|
||||
|
||||
def _change_transform_child(self, child):
|
||||
rv = self.copy()
|
||||
rv.set_child(self.child._change_transform_child(child))
|
||||
return rv
|
||||
|
||||
def _hide(self, st, at, kind):
|
||||
|
||||
if not (self.hide_request or self.replaced_request):
|
||||
d = self()
|
||||
d.kwargs = { }
|
||||
d.take_state(self)
|
||||
d.take_execution_state(self)
|
||||
d = self.copy()
|
||||
else:
|
||||
d = self
|
||||
|
||||
@@ -1117,8 +1152,6 @@ def zoom_render(crend, x, y, w, h, zw, zh, bilinear):
|
||||
|
||||
rv.blit(crend, rv.reverse.transform(-x, -y))
|
||||
|
||||
# TODO: Bilinear?
|
||||
|
||||
return rv
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
from renpy.display.render import render, BLIT
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import random
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
import sys
|
||||
import pygame
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# This class is used to make a copy of a pygame module's functions. We
|
||||
# can then access those functions, and be relatively sure that those
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
|
||||
# This file contains the routines that manage image prediction.
|
||||
|
||||
import traceback
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# Called to indicate an image should be loaded or preloaded. This is
|
||||
# a function that takes an image manipulator, set by reset and predict,
|
||||
|
||||
@@ -31,7 +31,6 @@ proc = None
|
||||
# user. If it decides to show something to the user, uses subprocess
|
||||
# to actually handle the showing.
|
||||
def start(gamedir):
|
||||
import os
|
||||
import os.path
|
||||
|
||||
if "RENPY_LESS_UPDATES" in os.environ:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
import os
|
||||
import math
|
||||
import pygame
|
||||
import renpy
|
||||
import renpy.display
|
||||
import renpy.display.pgrender as pgrender
|
||||
|
||||
# These need to be here before we mess with Pygame.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
class Screen(renpy.object.Object):
|
||||
"""
|
||||
@@ -553,7 +553,7 @@ def get_widget(screen, id, layer='screens'):
|
||||
screen = get_screen(screen, layer)
|
||||
|
||||
if not isinstance(screen, ScreenDisplayable):
|
||||
return None
|
||||
return None
|
||||
|
||||
if screen.child is None:
|
||||
screen.update()
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import pygame
|
||||
import math
|
||||
import weakref
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import re
|
||||
import renpy
|
||||
import renpy.display
|
||||
import sys
|
||||
|
||||
try:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
# are None, at least to the point of making it through __init__. This is
|
||||
# so that prediction of images works.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
from renpy.display.render import render
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ def Fade(out_time,
|
||||
|
||||
if color:
|
||||
widget = renpy.display.image.Solid(color)
|
||||
|
||||
|
||||
if not widget:
|
||||
widget = renpy.display.image.Solid((0, 0, 0, 255))
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
|
||||
# Functions that make the user's life easier.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
def color(c):
|
||||
if isinstance(c, tuple) and len(c) == 4:
|
||||
|
||||
+18
-25
@@ -28,22 +28,11 @@ import renpy
|
||||
class Delete(object):
|
||||
pass
|
||||
|
||||
|
||||
class PredictInfo(renpy.object.Object):
|
||||
"""
|
||||
This stores information involved in prediction.
|
||||
Not used anymore, but needed for backwards compatibility.
|
||||
"""
|
||||
|
||||
def __init__(self, pi=None):
|
||||
|
||||
super(PredictInfo, self).__init__()
|
||||
|
||||
if pi:
|
||||
self.images = renpy.display.core.ImagePredictInfo(pi.images)
|
||||
else:
|
||||
self.images = renpy.display.core.ImagePredictInfo(None)
|
||||
|
||||
|
||||
class Context(renpy.object.Object):
|
||||
"""
|
||||
This is the context object which stores the current context
|
||||
@@ -67,11 +56,10 @@ class Context(renpy.object.Object):
|
||||
does participates in rollback.
|
||||
"""
|
||||
|
||||
__version__ = 5
|
||||
__version__ = 6
|
||||
|
||||
def after_upgrade(self, version):
|
||||
if version < 1:
|
||||
self.predict_info = PredictInfo()
|
||||
self.scene_lists.image_predict_info = self.predict_info.images
|
||||
|
||||
if version < 2:
|
||||
@@ -87,6 +75,9 @@ class Context(renpy.object.Object):
|
||||
if version < 5:
|
||||
self.modes = renpy.python.RevertableList([ "start" ])
|
||||
self.use_modes = True
|
||||
|
||||
if version < 6:
|
||||
self.images = self.predict_info.images
|
||||
|
||||
def __init__(self, rollback, context=None, clear=False):
|
||||
"""
|
||||
@@ -138,13 +129,14 @@ class Context(renpy.object.Object):
|
||||
|
||||
for k, v in context.music.iteritems():
|
||||
self.music[k] = v.copy()
|
||||
|
||||
self.predict_info = PredictInfo(context.predict_info)
|
||||
|
||||
self.images = renpy.display.image.ShownImageInfo(context.images)
|
||||
|
||||
else:
|
||||
oldsl = None
|
||||
self.predict_info = PredictInfo()
|
||||
self.images = renpy.display.image.ShownImageInfo(None)
|
||||
|
||||
self.scene_lists = renpy.display.core.SceneLists(oldsl, self.predict_info.images)
|
||||
self.scene_lists = renpy.display.core.SceneLists(oldsl, self.images)
|
||||
|
||||
self.make_dynamic([ "_return", "_args", "_kwargs", "mouse_visible", "suppress_overlay" ])
|
||||
self.dynamic_stack.append({ })
|
||||
@@ -342,9 +334,9 @@ class Context(renpy.object.Object):
|
||||
if not self.current:
|
||||
return
|
||||
|
||||
old_predict_info = self.predict_info
|
||||
old_images = self.images
|
||||
|
||||
nodes = [ (renpy.game.script.lookup(self.current), self.predict_info) ]
|
||||
nodes = [ (renpy.game.script.lookup(self.current), self.images) ]
|
||||
node_set = set()
|
||||
|
||||
for i in range(0, renpy.config.predict_statements):
|
||||
@@ -352,8 +344,9 @@ class Context(renpy.object.Object):
|
||||
if i >= len(nodes):
|
||||
break
|
||||
|
||||
node, predict_info = nodes[i]
|
||||
self.predict_info = PredictInfo(predict_info)
|
||||
node, images = nodes[i]
|
||||
|
||||
self.images = renpy.display.image.ShownImageInfo(images)
|
||||
|
||||
# Ignore exceptions in prediction, so long as
|
||||
# prediction is not needed.
|
||||
@@ -364,7 +357,7 @@ class Context(renpy.object.Object):
|
||||
continue
|
||||
|
||||
if n not in node_set:
|
||||
nodes.append((n, self.predict_info))
|
||||
nodes.append((n, self.images))
|
||||
node_set.add(n)
|
||||
except:
|
||||
|
||||
@@ -376,8 +369,8 @@ class Context(renpy.object.Object):
|
||||
print "While predicting images."
|
||||
|
||||
# We accept that sometimes prediction won't work.
|
||||
|
||||
self.predict_info = old_predict_info
|
||||
|
||||
self.images = old_images
|
||||
|
||||
|
||||
def seen_current(self, ever):
|
||||
|
||||
+70
-13
@@ -28,6 +28,9 @@
|
||||
_file = file
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import renpy.audio
|
||||
|
||||
from renpy.display.text import ParameterizedText
|
||||
from renpy.display.font import register_sfont, register_mudgefont, register_bmfont
|
||||
from renpy.display.behavior import Keymap
|
||||
@@ -81,10 +84,6 @@ del public_api
|
||||
|
||||
import collections
|
||||
|
||||
# This is a map from image name to a Displayable object corresponding
|
||||
# to that image name.
|
||||
images = { }
|
||||
|
||||
def roll_forward_info():
|
||||
return renpy.game.log.forward_info()
|
||||
|
||||
@@ -147,8 +146,7 @@ def image(name, img):
|
||||
name = tuple(name.split())
|
||||
|
||||
img = renpy.easy.displayable(img)
|
||||
|
||||
images[name] = img
|
||||
renpy.display.image.register_image(name, img)
|
||||
|
||||
def copy_images(old, new):
|
||||
if not isinstance(old, tuple):
|
||||
@@ -159,12 +157,12 @@ def copy_images(old, new):
|
||||
|
||||
lenold = len(old)
|
||||
|
||||
for k in list(images.keys()):
|
||||
for k, v in renpy.display.image.images.items():
|
||||
if len(k) < lenold:
|
||||
continue
|
||||
|
||||
if k[:lenold] == old:
|
||||
images[new + k[lenold:]] = images[k]
|
||||
renpy.display.image.register_image(new + k[lenold:], v)
|
||||
|
||||
def showing(name, layer='master'):
|
||||
"""
|
||||
@@ -181,7 +179,7 @@ def showing(name, layer='master'):
|
||||
if not isinstance(name, tuple):
|
||||
name = tuple(name.split())
|
||||
|
||||
return renpy.game.context().predict_info.images.showing(layer, name)
|
||||
return renpy.game.context().images.showing(layer, name)
|
||||
|
||||
def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behind=[ ], atl=None, transient=False, munge_name=True):
|
||||
"Documented in wiki as renpy.show."
|
||||
@@ -206,7 +204,15 @@ def show(name, at_list=[ ], layer='master', what=None, zorder=0, tag=None, behin
|
||||
|
||||
if isinstance(what, renpy.display.core.Displayable):
|
||||
base = img = what
|
||||
|
||||
else:
|
||||
|
||||
if renpy.config.image_attributes:
|
||||
new_what = renpy.game.context().images.apply_attributes(layer, key, name)
|
||||
if new_what is not None:
|
||||
what = new_what
|
||||
name = (key,) + new_what[1:]
|
||||
|
||||
base = img = renpy.display.image.ImageReference(what, style='image_placement')
|
||||
|
||||
if not base.find_target() and renpy.config.missing_show:
|
||||
@@ -594,7 +600,7 @@ def predict_say(who, what):
|
||||
"""
|
||||
|
||||
if who is None:
|
||||
who = renpy.store.narrator # E1101
|
||||
who = renpy.store.narrator # E1101 @UndefinedVariable
|
||||
|
||||
if isinstance(who, (str, unicode)):
|
||||
return renpy.store.predict_say(who, what)
|
||||
@@ -625,7 +631,7 @@ def say(who, what, interact=True):
|
||||
what = what % tag_quoting_dict
|
||||
|
||||
if who is None:
|
||||
who = renpy.store.narrator # E1101
|
||||
who = renpy.store.narrator # E1101 @UndefinedVariable
|
||||
|
||||
if isinstance(who, (str, unicode)):
|
||||
renpy.store.say(who, what, interact=interact)
|
||||
@@ -1131,7 +1137,7 @@ def launch_editor(filenames, line=1, transient=0):
|
||||
cmd = cmd.replace('""', '')
|
||||
|
||||
try:
|
||||
subprocess.Popen(split_args(cmd)) # E1101
|
||||
subprocess.Popen(split_args(cmd)) # E1101 @UndefinedVariable
|
||||
return True
|
||||
except:
|
||||
if renpy.config.debug:
|
||||
@@ -1258,7 +1264,7 @@ def free_memory():
|
||||
force_full_redraw()
|
||||
renpy.display.im.free_memory()
|
||||
renpy.display.font.free_memory()
|
||||
renpy.display.render.free_memory()
|
||||
renpy.display.render.free_memory() # @UndefinedVariable
|
||||
|
||||
def easy_displayable(d, none=False):
|
||||
if none:
|
||||
@@ -1562,3 +1568,54 @@ def variant(name):
|
||||
|
||||
return name in renpy.config.variants
|
||||
|
||||
def vibrate(duration):
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Causes the device to vibrate for `duration` seconds. Currently, this
|
||||
is only supported on Android.
|
||||
"""
|
||||
|
||||
try:
|
||||
import android #@UnresolvedImport
|
||||
android.vibrate(duration)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# The attributes that are applied to the current say statement.
|
||||
say_attributes = None
|
||||
|
||||
def get_say_attributes():
|
||||
"""
|
||||
:doc: other
|
||||
|
||||
Gets the attributes associated with the current say statement, or
|
||||
None if no attributes are associated with this statement.
|
||||
|
||||
This is only valid when executing or predicting a say statement.
|
||||
"""
|
||||
|
||||
return say_attributes
|
||||
|
||||
side_image_attributes = None
|
||||
|
||||
def get_side_image(tag):
|
||||
"""
|
||||
This attempts to find an image to show as the side image. It attempts to
|
||||
find an image that begins with tag, and matches side_image_attributes. It
|
||||
returns the name of the image (as a tuple of strings) if possible, or
|
||||
None if that's not possible.
|
||||
"""
|
||||
|
||||
if side_image_attributes is None:
|
||||
return
|
||||
|
||||
images = renpy.game.context().images
|
||||
|
||||
required = set()
|
||||
optional = set(side_image_attributes)
|
||||
|
||||
return images.choose_image(tag, required, optional, None)
|
||||
|
||||
|
||||
+14
-3
@@ -31,6 +31,7 @@
|
||||
# in this module as fields on game.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
# The basepath.
|
||||
basepath = None
|
||||
@@ -95,6 +96,9 @@ less_updates = False
|
||||
# Should we never show the mouse?
|
||||
less_mouse = False
|
||||
|
||||
# Should we not imagedissiolve?
|
||||
less_imagedissolve = False
|
||||
|
||||
# The class that's used to hold the persistent data.
|
||||
class Persistent(object):
|
||||
|
||||
@@ -109,7 +113,7 @@ class Persistent(object):
|
||||
return None
|
||||
|
||||
# The persistent data that's kept from session to session
|
||||
persistent = None
|
||||
persistent = Persistent()
|
||||
|
||||
class Preferences(renpy.object.Object):
|
||||
"""
|
||||
@@ -171,7 +175,7 @@ class Preferences(renpy.object.Object):
|
||||
return self.mute[mixer]
|
||||
|
||||
# The current preferences.
|
||||
preferences = None
|
||||
preferences = Preferences()
|
||||
|
||||
class RestartException(Exception):
|
||||
"""
|
||||
@@ -312,4 +316,11 @@ def call_in_new_context(label, *args, **kwargs):
|
||||
if interface.restart_interaction:
|
||||
contexts[-1].scene_lists.focused = None
|
||||
|
||||
|
||||
# Type information.
|
||||
if False:
|
||||
script = renpy.script.Script()
|
||||
interface = renpy.display.core.Interface()
|
||||
log = renpy.python.RollbackLog()
|
||||
|
||||
|
||||
|
||||
+86
-13
@@ -19,7 +19,7 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import codecs
|
||||
import time
|
||||
import re
|
||||
@@ -97,9 +97,51 @@ def try_compile(where, expr, additional=None):
|
||||
add(additional)
|
||||
|
||||
|
||||
# The sets of names + attributes that
|
||||
imprecise_cache = set()
|
||||
|
||||
def image_exists_imprecise(name):
|
||||
if name in imprecise_cache:
|
||||
return True
|
||||
|
||||
nametag = name[0]
|
||||
|
||||
required = set()
|
||||
banned = set()
|
||||
|
||||
for i in name[1:]:
|
||||
if i[0] == "-":
|
||||
banned.add(i[1:])
|
||||
else:
|
||||
required.add(i)
|
||||
|
||||
for im in renpy.display.image.images:
|
||||
|
||||
if im[0] != nametag:
|
||||
continue
|
||||
|
||||
attrs = set(im[1:])
|
||||
|
||||
if [ i for i in required if i not in attrs ]:
|
||||
continue
|
||||
|
||||
if [ i for i in banned if i in attrs ]:
|
||||
continue
|
||||
|
||||
imprecise_cache.add(name)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
|
||||
# This reports an error if we're sure that the image with the given name
|
||||
# does not exist.
|
||||
def image_exists(name, expression, tag):
|
||||
def image_exists(name, expression, tag, precise=True):
|
||||
"""
|
||||
Checks a scene or show statement for image existence.
|
||||
"""
|
||||
|
||||
|
||||
# Add the tag to the set of known tags.
|
||||
tag = tag or name[0]
|
||||
@@ -108,17 +150,26 @@ def image_exists(name, expression, tag):
|
||||
if expression:
|
||||
return
|
||||
|
||||
name = list(name)
|
||||
names = " ".join(name)
|
||||
namelist = list(name)
|
||||
names = " ".join(namelist)
|
||||
|
||||
while name:
|
||||
if tuple(name) in renpy.exports.images:
|
||||
# Look for the precise name.
|
||||
while namelist:
|
||||
if tuple(namelist) in renpy.display.image.images:
|
||||
return
|
||||
|
||||
name.pop()
|
||||
namelist.pop()
|
||||
|
||||
# If we're not precise, then we have to start looking for images
|
||||
# that we can possibly match.
|
||||
if not precise and image_exists_imprecise(name):
|
||||
return
|
||||
|
||||
report("The image named '%s' was not declared.", names)
|
||||
|
||||
|
||||
|
||||
|
||||
# Only check each file once.
|
||||
check_file_cache = { }
|
||||
|
||||
@@ -166,7 +217,7 @@ def check_image(node):
|
||||
|
||||
name = " ".join(node.imgname)
|
||||
|
||||
check_displayable('image %s' % name, renpy.exports.images[node.imgname])
|
||||
check_displayable('image %s' % name, renpy.display.image.images[node.imgname])
|
||||
|
||||
def imspec(t):
|
||||
if len(t) == 3:
|
||||
@@ -178,7 +229,7 @@ def imspec(t):
|
||||
|
||||
|
||||
# Lints ast.Show and ast.Scene nodets.
|
||||
def check_show(node):
|
||||
def check_show(node, precise):
|
||||
|
||||
# A Scene may have an empty imspec.
|
||||
if not node.imspec:
|
||||
@@ -189,7 +240,7 @@ def check_show(node):
|
||||
if layer not in renpy.config.layers and layer not in renpy.config.top_layers:
|
||||
report("Uses layer '%s', which is not in config.layers.", layer)
|
||||
|
||||
image_exists(name, expression, tag)
|
||||
image_exists(name, expression, tag, precise=precise)
|
||||
|
||||
for i in at_list:
|
||||
try_eval("the at list of a scene or show statment", i, "Perhaps you forgot to declare, or misspelled, a position?")
|
||||
@@ -284,6 +335,28 @@ def check_say(node):
|
||||
try_eval("the with clause of a say statement", node.with_, "Perhaps you forgot to declare, or misspelled, a transition?")
|
||||
|
||||
text_checks(node.what)
|
||||
|
||||
# Code to check image attributes. (If we're lucky.)
|
||||
if node.who is None:
|
||||
return
|
||||
|
||||
char = getattr(renpy.store, node.who, None)
|
||||
|
||||
if not isinstance(char, renpy.character.ADVCharacter):
|
||||
return
|
||||
|
||||
if node.attributes is None:
|
||||
return
|
||||
|
||||
if char.image_tag is None:
|
||||
return
|
||||
|
||||
name = (char.image_tag,) + node.attributes
|
||||
|
||||
if not image_exists_imprecise(name):
|
||||
report("Could not find image (%s) corresponding to attributes on say statement.", " ".join(name))
|
||||
|
||||
|
||||
|
||||
def check_menu(node):
|
||||
|
||||
@@ -406,7 +479,7 @@ def lint():
|
||||
global image_prefixes
|
||||
image_prefixes = { }
|
||||
|
||||
for k in renpy.exports.images:
|
||||
for k in renpy.display.image.images:
|
||||
image_prefixes[k[0]] = True
|
||||
|
||||
# Iterate through every statement in the program, processing
|
||||
@@ -429,10 +502,10 @@ def lint():
|
||||
check_image(node)
|
||||
|
||||
elif isinstance(node, renpy.ast.Show):
|
||||
check_show(node)
|
||||
check_show(node, True)
|
||||
|
||||
elif isinstance(node, renpy.ast.Scene):
|
||||
check_show(node)
|
||||
check_show(node, False)
|
||||
|
||||
elif isinstance(node, renpy.ast.Hide):
|
||||
check_hide(node)
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import renpy
|
||||
import renpy.display
|
||||
import renpy.game as game
|
||||
import os
|
||||
import sys
|
||||
|
||||
+21
-2
@@ -1774,6 +1774,25 @@ def say_statement(l, loc):
|
||||
|
||||
# Try for a two-argument say statement.
|
||||
who = l.simple_expression()
|
||||
|
||||
attributes = [ ]
|
||||
while True:
|
||||
prefix = l.match(r'-')
|
||||
if not prefix:
|
||||
prefix = ""
|
||||
|
||||
component = l.word()
|
||||
|
||||
if component is None:
|
||||
break
|
||||
|
||||
attributes.append(prefix + component)
|
||||
|
||||
if attributes:
|
||||
attributes = tuple(attributes)
|
||||
else:
|
||||
attributes = None
|
||||
|
||||
what = l.string()
|
||||
|
||||
if l.keyword('with'):
|
||||
@@ -1785,7 +1804,7 @@ def say_statement(l, loc):
|
||||
l.expect_eol()
|
||||
l.expect_noblock('say statement')
|
||||
l.advance()
|
||||
return ast.Say(loc, who, what, with_)
|
||||
return ast.Say(loc, who, what, with_, attributes=attributes)
|
||||
|
||||
# This reports a parse error for any bad statement.
|
||||
l.error('expected statement.')
|
||||
@@ -1898,7 +1917,7 @@ def report_parse_errors():
|
||||
if renpy.config.editor:
|
||||
renpy.exports.launch_editor([ 'errors.txt' ], 1, transient=1)
|
||||
else:
|
||||
os.startfile('errors.txt') # E1101
|
||||
os.startfile('errors.txt') # E1101 @UndefinedVariable
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
+4
-4
@@ -267,7 +267,7 @@ def mutator(method):
|
||||
|
||||
global mutate_flag
|
||||
|
||||
mutated = renpy.game.log.mutated
|
||||
mutated = renpy.game.log.mutated #@UndefinedVariable
|
||||
|
||||
if id(self) not in mutated:
|
||||
mutated[id(self)] = ( weakref.ref(self), self.get_rollback())
|
||||
@@ -292,7 +292,7 @@ class RevertableList(list):
|
||||
reverse = mutator(list.reverse)
|
||||
sort = mutator(list.sort)
|
||||
|
||||
def wrapper(method): # E0213
|
||||
def wrapper(method): # E0213 @NoSelf
|
||||
def newmethod(*args, **kwargs):
|
||||
return RevertableList(method(*args, **kwargs)) # E1102
|
||||
|
||||
@@ -325,7 +325,7 @@ class RevertableDict(dict):
|
||||
popitem = mutator(dict.popitem)
|
||||
setdefault = mutator(dict.setdefault)
|
||||
|
||||
def list_wrapper(method): # E0213
|
||||
def list_wrapper(method): # E0213 @NoSelf
|
||||
def newmethod(*args, **kwargs):
|
||||
return RevertableList(method(*args, **kwargs)) # E1102
|
||||
|
||||
@@ -368,7 +368,7 @@ class RevertableSet(sets.Set):
|
||||
union_update = mutator(sets.Set.union_update)
|
||||
update = mutator(sets.Set.update)
|
||||
|
||||
def wrapper(method): # E0213
|
||||
def wrapper(method): # E0213 @NoSelf
|
||||
def newmethod(*args, **kwargs):
|
||||
rv = method(*args, **kwargs) # E1102
|
||||
if isinstance(rv, sets.Set):
|
||||
|
||||
@@ -478,6 +478,9 @@ position_properties = [ Style(i) for i in [
|
||||
"clipping",
|
||||
"xfill",
|
||||
"yfill",
|
||||
# no center, since it can conflict with the center transform.
|
||||
"xcenter",
|
||||
"ycenter",
|
||||
] ]
|
||||
|
||||
text_properties = [ Style(i) for i in [
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ class Script(object):
|
||||
|
||||
# A key that's used to lock the script file, should that
|
||||
# prove necessary.
|
||||
self.key = renpy.game.options.lock
|
||||
self.key = renpy.game.options.lock #@UndefinedVariable
|
||||
|
||||
if self.key is None:
|
||||
if os.path.exists(renpy.config.renpy_base + "/lock.txt"):
|
||||
|
||||
+6
-4
@@ -28,6 +28,7 @@
|
||||
# But please note that this will not be available in the body
|
||||
# of user code, unless we re-import it.
|
||||
import renpy
|
||||
import renpy.display
|
||||
|
||||
import renpy.ui as ui
|
||||
import renpy.display.im as im
|
||||
@@ -121,10 +122,11 @@ Bar = renpy.display.behavior.Bar
|
||||
Button = renpy.display.behavior.Button
|
||||
Input = renpy.display.behavior.Input
|
||||
|
||||
Frame = renpy.display.image.Frame
|
||||
Image = renpy.display.image.Image
|
||||
ImageReference = renpy.display.image.ImageReference
|
||||
Solid = renpy.display.image.Solid
|
||||
Image = renpy.display.im.image
|
||||
|
||||
Frame = renpy.display.imagelike.Frame
|
||||
Solid = renpy.display.imagelike.Solid
|
||||
|
||||
LiveComposite = renpy.display.layout.LiveComposite
|
||||
LiveCrop = renpy.display.layout.LiveCrop
|
||||
@@ -318,7 +320,7 @@ adv = ADVCharacter(None,
|
||||
|
||||
condition=None,
|
||||
dynamic=False,
|
||||
image=False,
|
||||
image=None,
|
||||
|
||||
interact=True,
|
||||
slow=True,
|
||||
|
||||
+14
-1
@@ -201,6 +201,8 @@ def always_true(a):
|
||||
return True
|
||||
def always_0(a):
|
||||
return 0
|
||||
def always_half(a):
|
||||
return 0.5
|
||||
|
||||
substitutes = dict(
|
||||
xmargin = [
|
||||
@@ -292,7 +294,18 @@ substitutes = dict(
|
||||
('ymaximum', index_3),
|
||||
('xminimum', index_2),
|
||||
('yminimum', index_3),
|
||||
],
|
||||
],
|
||||
|
||||
xcenter = [
|
||||
('xpos', None),
|
||||
('xanchor', always_half),
|
||||
],
|
||||
|
||||
ycenter = [
|
||||
('ypos', None),
|
||||
('yanchor', always_half),
|
||||
],
|
||||
|
||||
)
|
||||
|
||||
# Map from property to number.
|
||||
|
||||
+1
-1
@@ -695,7 +695,7 @@ def _imagebutton(idle_image = None,
|
||||
selected_hover = choice(selected_hover, selected_hover_image, "selected_hover")
|
||||
selected_insensitive = choice(selected_insensitive, selected_insensitive_image, "selected_insensitive")
|
||||
|
||||
return renpy.display.image.ImageButton(
|
||||
return renpy.display.behavior.ImageButton(
|
||||
idle,
|
||||
hover,
|
||||
insensitive_image = insensitive,
|
||||
|
||||
@@ -672,6 +672,22 @@ positions.
|
||||
|
||||
Equivalent to setting ypos and yanchor to this value.
|
||||
|
||||
.. transform-property:: xcenter
|
||||
|
||||
:type: float
|
||||
:default: 0.0
|
||||
|
||||
Equivalent to setting xpos to the value of this property, and
|
||||
xanchor to 0.5.
|
||||
|
||||
.. transform-property:: ycenter
|
||||
|
||||
:type: float
|
||||
:default: 0.0
|
||||
|
||||
Equivalent to setting ypos to the value of this property, and
|
||||
yanchor to 0.5.
|
||||
|
||||
.. transform-property:: rotate
|
||||
|
||||
:type: float or None
|
||||
|
||||
@@ -2,6 +2,92 @@
|
||||
Full Changelog
|
||||
==============
|
||||
|
||||
Ren'Py 6.12.1
|
||||
=============
|
||||
|
||||
Image Attributes
|
||||
----------------
|
||||
|
||||
The process of showing images is now attribute-based. Image names now
|
||||
consist of a tag, and zero or more attributes. When showing an image,
|
||||
the order of attributes is no longer important - it's now possible to
|
||||
define an image using one set of attributes, and show it using those
|
||||
attributes in a different order.
|
||||
|
||||
Attributes are also "sticky". This means that we attempt to preserve
|
||||
as many attributes as possible when showing a new image.
|
||||
|
||||
For example, say we had the following images::
|
||||
|
||||
image eileen beach happy = "eileen_beach_happy.png"
|
||||
image eileen beach woozy = "eileen_beach_woozy.png"
|
||||
|
||||
We can now show the first image using the command::
|
||||
|
||||
show eileen happy beach
|
||||
|
||||
Since the order of attributes no longer matters, this will show the
|
||||
"eileen beach happy" image. If we follow this with the show statement::
|
||||
|
||||
show eileen woozy
|
||||
|
||||
the image "eileen beach woozy" will be shown. (Assuming no other
|
||||
images exist. If the image "eileen happy woozy" existed, an ambiguity
|
||||
error would occur.)
|
||||
|
||||
When an image tag is shown without any attributes, then the current
|
||||
attributes are retained. Now, one can write::
|
||||
|
||||
show eileen at right
|
||||
|
||||
to display Eileen on the right side of the screen, without changing
|
||||
the attributes supplied to an image.
|
||||
|
||||
** Say Attributes. **
|
||||
Image attributes can be updated as part of a say statement. A
|
||||
character can be given an `image` argument, giving the name of an
|
||||
image that character is linked to. As part of the say statement, image
|
||||
attributes can be given before the dialogue string. These attributes
|
||||
are given to the linked image.
|
||||
|
||||
For example, if we define a character using the code::
|
||||
|
||||
define e = Character('Eileen', image="eileen")
|
||||
|
||||
the code::
|
||||
|
||||
e woozy "I think I'm getting too much sun."
|
||||
|
||||
is equivalent to::
|
||||
|
||||
show eileen woozy
|
||||
e "I think I'm getting too much sun."
|
||||
|
||||
whenever an image with the tag eileen is being shown.
|
||||
|
||||
** Side Image. **
|
||||
This release features a new implementation of :ref:`Side Images`, which
|
||||
allows side images to be defined like other images, and allows side
|
||||
images to be integrated with screens easily.
|
||||
|
||||
** Sticky Transforms. **
|
||||
Finally, showing an image without providing a transform or ATL block
|
||||
will now continue the previous transform that an image with that tag
|
||||
was using. Previously, it caused those transforms to stop.
|
||||
|
||||
|
||||
|
||||
Other
|
||||
-----
|
||||
|
||||
Added the :propref:`xcenter` and :propref:`ycenter` position and
|
||||
transform properties. These set the position of the center of a
|
||||
displayable. [Test]
|
||||
|
||||
The :func:`renpy.vibrate` function allows Ren'Py to ask Android devices
|
||||
to vibrate.
|
||||
|
||||
|
||||
Ren'Py 6.12.0
|
||||
=============
|
||||
|
||||
|
||||
@@ -684,6 +684,13 @@ Rarely or Internally Used
|
||||
|
||||
If True, joystic support is enabled.
|
||||
|
||||
.. var:: config.keep_running_transform = True
|
||||
|
||||
If true, showing an image without supplying a transform or ATL
|
||||
block will cause the image to continue the previous transform
|
||||
an image with that tag was using, if any. If false, the transform
|
||||
is stopped.
|
||||
|
||||
.. var:: config.keymap = dict(...)
|
||||
|
||||
This variable contains a keymap giving the keys and mouse buttons
|
||||
|
||||
@@ -190,7 +190,7 @@ code::
|
||||
|
||||
first desaturates the image, and then tints it blue. When the
|
||||
intermediate image is not needed, multiplying matrices is far
|
||||
more efficent, in both time and image cache space, than using
|
||||
more efficient, in both time and image cache space, than using
|
||||
two im.MatrixColors.
|
||||
|
||||
.. include:: inc/im_matrixcolor
|
||||
|
||||
@@ -19,6 +19,17 @@
|
||||
be used to define a template character, and then copy that
|
||||
character with changes.
|
||||
|
||||
**Linked Image**
|
||||
An image tag may be associated with a Character. This allows a
|
||||
say statement involving this character to display an image with
|
||||
the tag, and also allows Ren'Py to automatically select a side
|
||||
image to show when this character speaks.
|
||||
|
||||
`image`
|
||||
|
||||
A string giving the image tag that is linked with this
|
||||
character.
|
||||
|
||||
**Prefixes and Suffixes.**
|
||||
These allow a prefix and suffix to be applied to the name of the
|
||||
character, and to the text being shown. This can be used, for
|
||||
@@ -53,12 +64,6 @@
|
||||
expression. That string will be evaluated before each line
|
||||
of dialogue, and the result used as the name of the character.
|
||||
|
||||
`image`
|
||||
|
||||
If true, then `name` is expected to name an image file. That
|
||||
image is used as the name of the character.
|
||||
|
||||
|
||||
**Controlling Interactions.**
|
||||
These options control if the dialogue is displayed, if an
|
||||
interaction occurs, and the mode that is entered upon display.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.. Automatically generated file - do not modify.
|
||||
|
||||
.. class:: Drag(d=None, drag_name=None, draggable=True, droppable=True, drag_raise=True, dragged=None, dropped=None, drag_handle=(0.0, 0.0, 1.0, 1.0), drag_joined=<function default_drag_joined at 0x1de72a8>, clicked=None, hovered=None, unhovered=None, replaces=None, **properties)
|
||||
.. class:: Drag(d=None, drag_name=None, draggable=True, droppable=True, drag_raise=True, dragged=None, dropped=None, drag_handle=(0.0, 0.0, 1.0, 1.0), drag_joined=..., clicked=None, hovered=None, unhovered=None, **properties)
|
||||
|
||||
A displayable that represents an object that can be dragged around
|
||||
its enclosing area. A Drag can also represent an area that
|
||||
|
||||
@@ -1011,6 +1011,13 @@
|
||||
be treated as immutable. This should only be called once the display
|
||||
has been started (that is, after the init code is finished).
|
||||
|
||||
.. function:: renpy.get_say_attributes()
|
||||
|
||||
Gets the attributes associated with the current say statement, or
|
||||
None if no attributes are associated with this statement.
|
||||
|
||||
This is only valid when executing or predicting a say statement.
|
||||
|
||||
.. function:: renpy.image_size(im)
|
||||
|
||||
Given an image manipulator, loads it and returns a (``width``,
|
||||
@@ -1040,6 +1047,11 @@
|
||||
Only one notification is displayed at a time. If a second notification
|
||||
is displayed, the first notification is replaced.
|
||||
|
||||
.. function:: renpy.vibrate(duration)
|
||||
|
||||
Causes the device to vibrate for `duration` seconds. Currently, this
|
||||
is only supported on Android.
|
||||
|
||||
.. function:: renpy.music.register_channel(name, mixer=None, loop=None, stop_on_mute=True, tight=False, file_prefix='', file_suffix='', buffer_queue=True)
|
||||
|
||||
This registers a new audio channel named `name`. Audio can then be
|
||||
|
||||
@@ -9,6 +9,27 @@ Note that setting :var:`config.script_version` will cause many of
|
||||
these changes to be reverted, at the cost of losing access to recent
|
||||
features.
|
||||
|
||||
.. _incompatible-6.12.1:
|
||||
|
||||
6.12.1
|
||||
------
|
||||
|
||||
Image names have changed from being static names to being
|
||||
attribute-based. This can lead to image names that were previously
|
||||
distinct becoming ambiguous. To disable attribute-based image names,
|
||||
set :var:`config.image_attributes` to False.
|
||||
|
||||
Showing an image without providing a transform or ATL block will now
|
||||
continue the previous transform that the image was using. This means
|
||||
that a moving image may continue moving once it has changed. To revert
|
||||
to the old behavior, set :var:`config.keep_running_transform` to False.
|
||||
|
||||
The `image` argument to :func:`Character` has changed meaning. While
|
||||
the old meaning was unsupported in the screens-based environment, it
|
||||
can be restored for compatibility purposes by setting
|
||||
:var:`new_character_image_argument` to False.
|
||||
|
||||
|
||||
.. _incompatible-6.12.0:
|
||||
|
||||
6.12.0
|
||||
|
||||
@@ -50,6 +50,7 @@ Customizing Ren'Py
|
||||
screens
|
||||
screen_actions
|
||||
screen_special
|
||||
side_image
|
||||
config
|
||||
|
||||
Advanced Displayables
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -105,4 +105,9 @@ same default page as the file actions.
|
||||
|
||||
.. include:: inc/file_action_function
|
||||
|
||||
Side Image Functions
|
||||
--------------------
|
||||
|
||||
This function returns the side image to use.
|
||||
|
||||
.. include:: inc/side_image_function
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
Side Images
|
||||
===========
|
||||
|
||||
Many visual novels include a picture of the character that is speaking as
|
||||
part of their interface. Ren'Py calls this image a side image, and has
|
||||
support for automatically selecting and displaying a side image as part
|
||||
of the dialogue.
|
||||
|
||||
The side image support assumes that a :func:`Character` is declared with
|
||||
a linked image tag::
|
||||
|
||||
define e = Character("Eileen", image="eileen")
|
||||
|
||||
When a character with a linked image tag speaks, Ren'Py creates a pool of
|
||||
image attributes. The linked image tag is added to this pool, as are the
|
||||
current image attributes that are associated with that tag.
|
||||
|
||||
To determine the side image associated with a tag, Ren'Py tries to find
|
||||
an image with the tag "side", and the largest number of attributes from
|
||||
the pool. If no image can be found, or more than one image has the same
|
||||
number of attributes, an :class:`Null` is shown instead.
|
||||
|
||||
For example, say we have the following script::
|
||||
|
||||
define e = Character("Eileen", image="eileen")
|
||||
|
||||
image eileen happy = "eileen_happy.png"
|
||||
image eileen concerned = "eileen_concerned.png"
|
||||
|
||||
image side eileen happy = "side_eileen_happy.png"
|
||||
image side eileen = "side_eileen.png"
|
||||
|
||||
label start:
|
||||
|
||||
show eileen happy
|
||||
|
||||
e "Let's call this line Point A."
|
||||
|
||||
e concerned "And this one is point B."
|
||||
|
||||
At point A, the character ``e`` is speaking, which is linked to the image
|
||||
tag "eileen". The "eileen happy" image is showing, so the pool of attributes
|
||||
is "eileen" and "happy". We look for an image with the "side" tag, and as
|
||||
many of those attributes as possible - and we match "side eileen happy",
|
||||
which is the side image Ren'Py will display.
|
||||
|
||||
At point B, the "eileen concerned" image is showing. The pool of attributes
|
||||
is now "eileen" and "concerned". The only matching image is "side eileen",
|
||||
so that's what Ren'Py selects. If the was a "side concerned" image, there
|
||||
would be ambiguity, and Ren'Py wouldn't display an image.
|
||||
|
||||
|
||||
Invisible Characters
|
||||
--------------------
|
||||
|
||||
Another use of the side image is to show an image of the player character,
|
||||
when that character has dialogue. The way to do this is to link an image to
|
||||
the character, and then use the say with attributes construct to select
|
||||
the side image to show.
|
||||
|
||||
For example::
|
||||
|
||||
define p = Character("Player", image="player")
|
||||
|
||||
image side player happy = "side_player_happy.png"
|
||||
image side player concerned = "side_player_concerned.png"
|
||||
|
||||
label start:
|
||||
|
||||
p happy "This is shown with the 'side player happy' image."
|
||||
|
||||
p "This is also shown with 'side player happy'."
|
||||
|
||||
p concerned "This is shown with 'side player concerned'."
|
||||
|
||||
Leaving Room / Customization
|
||||
----------------------------
|
||||
|
||||
By default, the entire width of the screen is taken up by the text. If one
|
||||
tries to display a side image, it will be displayed on top of the text. To
|
||||
fix this, one should include margin or padding on the appropriate side of
|
||||
the text window, using code like::
|
||||
|
||||
init python:
|
||||
style.window.padding_left = 150
|
||||
|
||||
The position of the side image can be changed by customizing the ``say``
|
||||
or ``nvl`` screens. Both include the line::
|
||||
|
||||
add SideImage() xalign 0.0 yalign 1.0
|
||||
|
||||
By changing the xalign and yalign properties, you can control the positioning
|
||||
of the side image on the screen.
|
||||
|
||||
Finally, the :func:`SideImage` function returns, as a displayable, the
|
||||
current side image. This can be used as part of more advanced screen
|
||||
customization.
|
||||
|
||||
@@ -238,6 +238,16 @@ layout.
|
||||
Equivalent to setting xalign to the first component of the tuple,
|
||||
and yalign to the second.
|
||||
|
||||
.. style-property:: xcenter position
|
||||
|
||||
Equivalent to setting xpos to the value of this property, and
|
||||
xanchor to 0.5.
|
||||
|
||||
.. style-property:: ycenter position
|
||||
|
||||
Equivalent to setting ypos to the value of tihis property, and
|
||||
yanchor to 0.5.
|
||||
|
||||
.. style-property:: xoffset int
|
||||
|
||||
Gives a number of pixels that are added to the horizontal position
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
rsync -a /home/tom/ab/renpy-mainline/doc/ tom@onegeek.org:/home/tom/WWW.renpyorg/doc/html/
|
||||
rsync -a ../doc/ tom@onegeek.org:/home/tom/WWW.renpyorg/doc/html/
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
rsync -a ../doc/ tom@onegeek.org:/home/tom/WWW.renpyorg/dev-doc/html/
|
||||
File diff suppressed because one or more lines are too long
@@ -271,7 +271,7 @@ image main_menu:
|
||||
size (800, 509)
|
||||
|
||||
contains:
|
||||
Text("Ren'Py 6.12.0 \"Positronic Brain\"", size=18)
|
||||
Text("Ren'Py 6.12.1 \"No Name Yet\"", size=18)
|
||||
yalign .98
|
||||
xalign .02
|
||||
|
||||
|
||||
@@ -48,11 +48,12 @@ screen say:
|
||||
style "say_vbox"
|
||||
|
||||
text what id "what"
|
||||
|
||||
|
||||
# If there's a side image, display it above the text.
|
||||
if side_image:
|
||||
add side_image
|
||||
|
||||
else:
|
||||
add SideImage() xalign 0.0 yalign 1.0
|
||||
|
||||
|
||||
##############################################################################
|
||||
@@ -158,7 +159,7 @@ screen nvl:
|
||||
|
||||
text caption style "nvl_dialogue"
|
||||
|
||||
|
||||
add SideImage() xalign 0.0 yalign 1.0
|
||||
|
||||
##############################################################################
|
||||
# Main Menu
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
# Version of renpy.display.render for use in python-only type inferencing.
|
||||
raise NotImplemented()
|
||||
|
||||
import renpy.display
|
||||
|
||||
def free_memory():
|
||||
"""
|
||||
Frees memory used by the render system.
|
||||
"""
|
||||
|
||||
|
||||
def check_at_shutdown():
|
||||
"""
|
||||
This is called at shutdown time to check that everything went okay.
|
||||
The big thing it checks for is memory leaks.
|
||||
"""
|
||||
|
||||
def render(d, widtho, heighto, st, at):
|
||||
"""
|
||||
Causes the displayable `d` to be rendered in an area of size
|
||||
width, height. st and at are the times of this render, but once
|
||||
rendered the Render will remain cached until the displayable needs
|
||||
to be redrawn.
|
||||
"""
|
||||
|
||||
return Render(0, 0)
|
||||
|
||||
|
||||
def invalidate(d):
|
||||
"""
|
||||
Removes d from the render cache. If we're not in a redraw, triggers
|
||||
a redraw to start.
|
||||
"""
|
||||
|
||||
|
||||
def process_redraws():
|
||||
"""
|
||||
Called to determine if any redraws are pending. Returns true if we
|
||||
need to redraw the screen now, false otherwise.
|
||||
"""
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def redraw_time():
|
||||
"""
|
||||
Returns the time at which the next redraw is scheduled.
|
||||
"""
|
||||
|
||||
return 0.0
|
||||
|
||||
|
||||
|
||||
def redraw(d, when):
|
||||
"""
|
||||
Called to cause `d` to be redrawn in `when` seconds.
|
||||
"""
|
||||
|
||||
|
||||
class Matrix2D:
|
||||
"""
|
||||
This represents a 2d matrix that can be used to transform
|
||||
points and things like that.
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, xdx, xdy, ydx, ydy):
|
||||
self.xdx = xdx
|
||||
self.xdy = xdy
|
||||
self.ydx = ydx
|
||||
self.ydy = ydy
|
||||
|
||||
def transform(self, x, y):
|
||||
return (x * self.xdx + y * self.xdy), (x * self.ydx + y * self.ydy)
|
||||
|
||||
def __mul__(self, other):
|
||||
return Matrix2D(
|
||||
other.xdx * self.xdx + other.xdy * self.ydx,
|
||||
other.xdx * self.xdy + other.xdy * self.ydy,
|
||||
other.ydx * self.xdx + other.ydy * self.ydx,
|
||||
other.ydx * self.xdy + other.ydy * self.ydy)
|
||||
|
||||
def __repr__(self):
|
||||
return "Matrix2D(xdx=%f, xdy=%f, ydx=%f, ydy=%f)" % (self.xdx, self.xdy, self.ydx, self.ydy)
|
||||
|
||||
IDENTITY = Matrix2D(1, 0, 0, 1)
|
||||
|
||||
def take_focuses(focuses):
|
||||
"""
|
||||
Adds a list of rectangular focus regions to the focuses list.
|
||||
"""
|
||||
|
||||
# The result of focus_at_point for a modal render. This overrides any
|
||||
# specific focus from below us.
|
||||
Modal = object()
|
||||
|
||||
def focus_at_point(x, y):
|
||||
"""
|
||||
Returns a focus object corresponding to the uppermost displayable
|
||||
at point, or None if nothing focusable is at point.
|
||||
"""
|
||||
|
||||
return renpy.display.focus.Focus(None, None, None, None, None, None)
|
||||
|
||||
|
||||
def mutated_surface(surf):
|
||||
"""
|
||||
Called to indicate that the given surface has changed.
|
||||
"""
|
||||
|
||||
|
||||
def render_screen(root, width, height):
|
||||
"""
|
||||
Renders `root` (a displayable) as the root of a screen with the given
|
||||
`width` and `height`.
|
||||
"""
|
||||
|
||||
return Render(0, 0)
|
||||
|
||||
def mark_sweep():
|
||||
"""
|
||||
This performs mark-and-sweep garbage collection on the live_renders
|
||||
list.
|
||||
"""
|
||||
|
||||
def compute_subline(sx0, sw, cx0, cw):
|
||||
"""
|
||||
Given a source line (start sx0, width sw) and a crop line (cx0, cw),
|
||||
return three things:
|
||||
|
||||
* The offset of the portion of the source line that overlaps with
|
||||
the crop line, relative to the crop line.
|
||||
* The offset of the portion of the source line that overlaps with the
|
||||
the crop line, relative to the source line.
|
||||
* The length of the overlap in pixels. (can be <= 0)
|
||||
"""
|
||||
|
||||
|
||||
# Possible operations that can be done as part of a render.
|
||||
BLIT = 0
|
||||
DISSOLVE = 1
|
||||
IMAGEDISSOLVE = 2
|
||||
PIXELLATE = 3
|
||||
|
||||
class Render:
|
||||
|
||||
def __init__(self, width, height, draw_func=None, layer_name=None, opaque=None):
|
||||
"""
|
||||
Creates a new render corresponding to the given widget with
|
||||
the specified width and height.
|
||||
|
||||
If `layer_name` is given, then this render corresponds to a
|
||||
layer.
|
||||
"""
|
||||
|
||||
|
||||
def blit(self, source, pos, focus=True, main=True, index=None):
|
||||
"""
|
||||
Blits `source` (a Render or Surface) to this Render, offset by
|
||||
xo and yo.
|
||||
|
||||
If `focus` is true, then focuses are added from the child to the
|
||||
parent.
|
||||
|
||||
This will only blit on integer pixel boundaries.
|
||||
"""
|
||||
|
||||
|
||||
def subpixel_blit(self, source, pos, focus=True, main=True, index=None):
|
||||
"""
|
||||
Blits `source` (a Render or Surface) to this Render, offset by
|
||||
xo and yo.
|
||||
|
||||
If `focus` is true, then focuses are added from the child to the
|
||||
parent.
|
||||
|
||||
This blits at fractional pixel boundaries.
|
||||
"""
|
||||
|
||||
def get_size(self):
|
||||
"""
|
||||
Returns the size of this Render, a mostly ficticious value
|
||||
that's taken from the inputs to the constructor. (As in, we
|
||||
don't clip to this size.)
|
||||
"""
|
||||
|
||||
return 0, 0
|
||||
|
||||
|
||||
def render_to_texture(self, alpha=True):
|
||||
"""
|
||||
Returns a texture constructed from this render. This may return
|
||||
a cached textue, if one has already been rendered.
|
||||
|
||||
`alpha` is a hint that controls if the surface should have
|
||||
alpha or not.
|
||||
"""
|
||||
|
||||
pygame_surface = render_to_texture
|
||||
|
||||
|
||||
def subsurface(self, rect, focus=False):
|
||||
"""
|
||||
Returns a subsurface of this render. If `focus` is true, then
|
||||
the focuses are copied from this render to the child.
|
||||
"""
|
||||
|
||||
return Render(0, 0)
|
||||
|
||||
|
||||
|
||||
def depends_on(self, source, focus=False):
|
||||
"""
|
||||
Used to indicate that this render depends on another
|
||||
render. Useful, for example, if we use pygame_surface to make
|
||||
a surface, and then blit that surface into another render.
|
||||
"""
|
||||
|
||||
|
||||
def kill_cache(self):
|
||||
"""
|
||||
Removes this render and its transitive parents from the cache.
|
||||
"""
|
||||
|
||||
def kill(self):
|
||||
"""
|
||||
Retained for compatibility.
|
||||
"""
|
||||
|
||||
def add_focus(self, d, arg=None, x=0, y=0, w=None, h=None, mx=None, my=None, mask=None):
|
||||
"""
|
||||
This is called to indicate a region of the screen that can be
|
||||
focused.
|
||||
|
||||
`d` - the displayable that is being focused.
|
||||
`arg` - an argument.
|
||||
|
||||
The rest of the parameters are a rectangle giving the portion of
|
||||
this region corresponding to the focus. If they are all None, than
|
||||
this focus is assumed to be the singular full-screen focus.
|
||||
"""
|
||||
|
||||
def take_focuses(self, cminx, cminy, cmaxx, cmaxy, reverse, x, y, focuses):
|
||||
"""
|
||||
This adds to focuses Focus objects corresponding to the focuses
|
||||
added to this object and its children, transformed into screen
|
||||
coordinates.
|
||||
|
||||
`cminx`, `cminy`, `cmaxx`, `cmaxy` - The clipping rectangle.
|
||||
`reverse` - The transform from render to screen coordinates.
|
||||
`x`, `y` - The offset of the upper-left corner of the render.
|
||||
`focuses` - The list of focuses to add to.
|
||||
"""
|
||||
|
||||
|
||||
def focus_at_point(self, x, y):
|
||||
"""
|
||||
This returns the focus of this object at the given point.
|
||||
"""
|
||||
|
||||
return renpy.display.layout.Null()
|
||||
|
||||
|
||||
def main_displayables_at_point(self, x, y, layers, depth=None):
|
||||
"""
|
||||
Returns the displayable at `x`, `y` on one of the layers in
|
||||
the set or list `layers`.
|
||||
"""
|
||||
|
||||
return [ ]
|
||||
|
||||
def is_opaque(self):
|
||||
"""
|
||||
Returns true if this displayable is opaque, or False otherwise.
|
||||
Also sets self.visible_children.
|
||||
"""
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def is_pixel_opaque(self, x, y):
|
||||
"""
|
||||
Determine if the pixel at x and y is opaque or not.
|
||||
"""
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def fill(self, color):
|
||||
"""
|
||||
Fills this Render with the given color.
|
||||
"""
|
||||
|
||||
def canvas(self):
|
||||
"""
|
||||
Returns a canvas object that draws to this Render.
|
||||
"""
|
||||
|
||||
return Canvas(None)
|
||||
|
||||
|
||||
class Canvas(object):
|
||||
|
||||
def __init__(self, surf):
|
||||
self.surf = surf
|
||||
|
||||
def rect(self, color, rect, width=0):
|
||||
return
|
||||
|
||||
def polygon(self, color, pointlist, width=0):
|
||||
return
|
||||
|
||||
def circle(self, color, pos, radius, width=0):
|
||||
return
|
||||
|
||||
def ellipse(self, color, rect, width=0):
|
||||
return
|
||||
|
||||
def arc(self, color, rect, start_angle, stop_angle, width=1):
|
||||
return
|
||||
|
||||
def line(self, color, start_pos, end_pos, width=1):
|
||||
return
|
||||
|
||||
def lines(self, color, closed, pointlist, width=1):
|
||||
return
|
||||
|
||||
def aaline(self, color, startpos, endpos, blend=1):
|
||||
return
|
||||
|
||||
def aalines(self, color, closed, pointlist, blend=1):
|
||||
return
|
||||
Reference in New Issue
Block a user