summaryrefslogtreecommitdiff
path: root/unrpyc/renpy/display/motion.py
diff options
context:
space:
mode:
Diffstat (limited to 'unrpyc/renpy/display/motion.py')
-rw-r--r--unrpyc/renpy/display/motion.py1526
1 files changed, 0 insertions, 1526 deletions
diff --git a/unrpyc/renpy/display/motion.py b/unrpyc/renpy/display/motion.py
deleted file mode 100644
index 1c9d667..0000000
--- a/unrpyc/renpy/display/motion.py
+++ /dev/null
@@ -1,1526 +0,0 @@
-# Copyright 2004-2013 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.
-
-# This file contains displayables that move, zoom, rotate, or otherwise
-# transform displayables. (As well as displayables that support them.)
-import math
-import types #@UnresolvedImport
-
-import renpy.display #@UnusedImport
-from renpy.display.render import render
-from renpy.display.layout import Container
-
-import renpy.display.accelerator
-
-# The null object that's used if we don't have a defined child.
-null = None
-
-def get_null():
- global null
-
- if null is None:
- null = renpy.display.layout.Null()
-
- return null
-
-# Convert a position from cartesian to polar coordinates.
-def cartesian_to_polar(x, y, xaround, yaround):
- """
- Converts cartesian coordinates to polar coordinates.
- """
-
- dx = x - xaround
- dy = y - yaround
-
- radius = math.hypot(dx, dy)
- angle = math.atan2(dx, -dy) / math.pi * 180
-
- if angle < 0:
- angle += 360
-
- return angle, radius
-
-def polar_to_cartesian(angle, radius, xaround, yaround):
- """
- Converts polart coordinates to cartesian coordinates.
- """
-
- angle = angle * math.pi / 180
-
- dx = radius * math.sin(angle)
- dy = -radius * math.cos(angle)
-
- x = type(xaround)(xaround + dx)
- y = type(yaround)(yaround + dy)
-
- return x, y
-
-def first_not_none(*args):
- """
- Returns the first argument that is not None.
- """
-
- for i in args:
- if i is not None:
- return i
- return i
-
-
-class TransformState(renpy.object.Object):
-
- xoffset = None
- yoffset = None
- default_xpos = None
- default_ypos = None
- default_xanchor = None
- default_yanchor = None
- default_xoffset = None
- default_yoffset = None
- transform_anchor = False
-
- def __init__(self): # W0231
- self.alpha = 1
- self.rotate = None
- self.rotate_pad = True
- self.transform_anchor = False
- self.zoom = 1
- self.xzoom = 1
- self.yzoom = 1
-
- self.xpos = None
- self.ypos = None
- self.xanchor = None
- self.yanchor = None
- self.xoffset = 0
- self.yoffset = 0
-
- self.xaround = 0.0
- self.yaround = 0.0
- self.xanchoraround = 0.0
- self.yanchoraround = 0.0
-
- self.subpixel = False
-
- self.crop = None
- self.corner1 = None
- self.corner2 = None
- self.size = None
-
- self.delay = 0
-
- # Note: When adding a new property, we need to add it to:
- # - take_state
- # - diff
- # - renpy.atl.PROPERTIES
- # - Proxies in Transform
-
- # Default values for various properties, taken from our
- # parent.
- self.default_xpos = None
- self.default_ypos = None
- self.default_xanchor = None
- self.default_yanchor = None
-
- def take_state(self, ts):
-
- self.alpha = ts.alpha
- self.rotate = ts.rotate
- self.rotate_pad = ts.rotate_pad
- self.transform_anchor = ts.transform_anchor
- self.zoom = ts.zoom
- self.xzoom = ts.xzoom
- self.yzoom = ts.yzoom
-
- self.xaround = ts.xaround
- self.yaround = ts.yaround
- self.xanchoraround = ts.xanchoraround
- self.yanchoraround = ts.yanchoraround
-
- self.subpixel = ts.subpixel
-
- self.crop = ts.crop
- self.corner1 = ts.corner1
- self.corner2 = ts.corner2
- self.size = ts.size
-
- # Take the computed position properties, not the
- # raw ones.
- (self.default_xpos,
- self.default_ypos,
- self.default_xanchor,
- self.default_yanchor,
- self.xoffset,
- self.yoffset,
- self.subpixel) = ts.get_placement()
-
- # Returns a dict, with p -> (old, new) where p is a property that
- # has changed between this object and the new object.
- def diff(self, newts):
-
- rv = { }
-
- def diff2(prop, new, old):
- if new != old:
- rv[prop] = (old, new)
-
- def diff4(prop, new, default_new, old, default_old):
- if new is None:
- new_value = default_new
- else:
- new_value = new
-
- if old is None:
- old_value = default_old
- else:
- old_value = old
-
- if new_value != old_value:
- rv[prop] = (old_value, new_value)
-
- diff2("alpha", newts.alpha, self.alpha)
- diff2("rotate", newts.rotate, self.rotate)
- diff2("rotate_pad", newts.rotate_pad, self.rotate_pad)
- diff2("transform_anchor", newts.transform_anchor, self.transform_anchor)
- diff2("zoom", newts.zoom, self.zoom)
- diff2("xzoom", newts.xzoom, self.xzoom)
- diff2("yzoom", newts.yzoom, self.yzoom)
-
- diff2("xaround", newts.xaround, self.xaround)
- diff2("yaround", newts.yaround, self.yaround)
- diff2("xanchoraround", newts.xanchoraround, self.xanchoraround)
- diff2("yanchoraround", newts.yanchoraround, self.yanchoraround)
-
- diff2("subpixel", newts.subpixel, self.subpixel)
-
- diff2("crop", newts.crop, self.crop)
- diff2("corner1", newts.corner1, self.corner1)
- diff2("corner2", newts.corner2, self.corner2)
- diff2("size", newts.size, self.size)
-
- diff4("xpos", newts.xpos, newts.default_xpos, self.xpos, self.default_xpos)
-
- diff4("xanchor", newts.xanchor, newts.default_xanchor, self.xanchor, self.default_xanchor)
- diff2("xoffset", newts.xoffset, self.xoffset)
-
- diff4("ypos", newts.ypos, newts.default_ypos, self.ypos, self.default_ypos)
- diff4("yanchor", newts.yanchor, newts.default_yanchor, self.yanchor, self.default_yanchor)
- diff2("yoffset", newts.yoffset, self.yoffset)
-
- return rv
-
- def get_placement(self, cxoffset=0, cyoffset=0):
-
- return (
- first_not_none(self.xpos, self.default_xpos),
- first_not_none(self.ypos, self.default_ypos),
- first_not_none(self.xanchor, self.default_xanchor),
- first_not_none(self.yanchor, self.default_yanchor),
- self.xoffset + cxoffset,
- self.yoffset + cyoffset,
- self.subpixel,
- )
-
- # These update various properties.
- def get_xalign(self):
- return self.xpos
-
- def set_xalign(self, v):
- self.xpos = v
- self.xanchor = v
-
- xalign = property(get_xalign, set_xalign)
-
- def get_yalign(self):
- return self.ypos
-
- def set_yalign(self, v):
- self.ypos = v
- self.yanchor = v
-
- yalign = property(get_yalign, set_yalign)
-
- def get_around(self):
- return (self.xaround, self.yaround)
-
- def set_around(self, value):
- self.xaround, self.yaround = value
- self.xanchoraround, self.yanchoraround = None, None
-
- def set_alignaround(self, value):
- self.xaround, self.yaround = value
- self.xanchoraround, self.yanchoraround = value
-
- around = property(get_around, set_around)
- alignaround = property(get_around, set_alignaround)
-
- def get_angle(self):
- xpos = first_not_none(self.xpos, self.default_xpos, 0)
- ypos = first_not_none(self.ypos, self.default_ypos, 0)
- angle, _radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
- return angle
-
- def get_radius(self):
- xpos = first_not_none(self.xpos, self.default_xpos, 0)
- ypos = first_not_none(self.ypos, self.default_ypos, 0)
- _angle, radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
- return radius
-
- def set_angle(self, value):
- xpos = first_not_none(self.xpos, self.default_xpos, 0)
- ypos = first_not_none(self.ypos, self.default_ypos, 0)
- _angle, radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
- angle = value
- self.xpos, self.ypos = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
-
- if self.xanchoraround:
- self.xanchor, self.yanchor = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
-
- def set_radius(self, value):
- xpos = first_not_none(self.xpos, self.default_xpos, 0)
- ypos = first_not_none(self.ypos, self.default_ypos, 0)
- angle, _radius = cartesian_to_polar(xpos, ypos, self.xaround, self.yaround)
- radius = value
- self.xpos, self.ypos = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
-
- if self.xanchoraround:
- self.xanchor, self.yanchor = polar_to_cartesian(angle, radius, self.xaround, self.yaround)
-
- angle = property(get_angle, set_angle)
- radius = property(get_radius, set_radius)
-
- def get_pos(self):
- return self.xpos, self.ypos
-
- def set_pos(self, value):
- self.xpos, self.ypos = value
-
- pos = property(get_pos, set_pos)
-
- def get_anchor(self):
- return self.xanchor, self.yanchor
-
- def set_anchor(self, value):
- self.xanchor, self.yanchor = value
-
- anchor = property(get_anchor, set_anchor)
-
- def get_align(self):
- return self.xpos, self.ypos
-
- def set_align(self, value):
- self.xanchor, self.yanchor = value
- self.xpos, self.ypos = value
-
- align = property(get_align, set_align)
-
- def get_offset(self):
- return self.xoffset, self.yoffset
-
- def set_offset(self, value):
- self.xoffset, self.yoffset = value
-
- 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):
- """
- This class proxies a field from the transform to its state.
- """
-
- def __init__(self, name):
- self.name = name
-
- def __get__(self, instance, owner):
- return getattr(instance.state, self.name)
-
- def __set__(self, instance, value):
- return setattr(instance.state, self.name, value)
-
-class Transform(Container):
- """
- Documented in sphinx, because we can't scan this object.
- """
-
- __version__ = 5
- transform_event_responder = True
-
- # Proxying things over to our state.
- alpha = Proxy("alpha")
- rotate = Proxy("rotate")
- rotate_pad = Proxy("rotate_pad")
- transform_anchor = Proxy("rotate_pad")
- zoom = Proxy("zoom")
- xzoom = Proxy("xzoom")
- yzoom = Proxy("yzoom")
-
- xpos = Proxy("xpos")
- ypos = Proxy("ypos")
- xanchor = Proxy("xanchor")
- yanchor = Proxy("yanchor")
-
- xalign = Proxy("xalign")
- yalign = Proxy("yalign")
-
- around = Proxy("around")
- alignaround = Proxy("alignaround")
- angle = Proxy("angle")
- radius = Proxy("radius")
-
- xaround = Proxy("xaround")
- yaround = Proxy("yaround")
- xanchoraround = Proxy("xanchoraround")
- yanchoraround = Proxy("yanchoraround")
-
- pos = Proxy("pos")
- anchor = Proxy("anchor")
- align = Proxy("align")
-
- crop = Proxy("crop")
- corner1 = Proxy("corner1")
- corner2 = Proxy("corner2")
- size = Proxy("size")
-
- delay = Proxy("delay")
-
- xoffset = Proxy("xoffset")
- yoffset = Proxy("yoffset")
- offset = Proxy("offset")
-
- subpixel = Proxy("subpixel")
-
- xcenter = Proxy("xcenter")
- ycenter = Proxy("ycenter")
-
- def after_upgrade(self, version):
-
- if version < 1:
- self.active = False
- self.state = TransformState()
-
- self.state.xpos = self.xpos or 0
- self.state.ypos = self.ypos or 0
- self.state.xanchor = self.xanchor or 0
- self.state.yanchor = self.yanchor or 0
- self.state.alpha = self.alpha
- self.state.rotate = self.rotate
- self.state.zoom = self.zoom
- self.state.xzoom = self.xzoom
- self.state.yzoom = self.yzoom
-
- self.hide_request = False
- self.hide_response = True
-
- if version < 2:
- self.st = 0
- self.at = 0
-
- if version < 3:
- self.st_offset = 0
- self.at_offset = 0
- self.child_st_base = 0
-
- if version < 4:
- self.style_arg = 'transform'
-
- if version < 5:
- self.replaced_request = False
- self.replaced_response = True
-
- DEFAULT_ARGUMENTS = {
- "selected_activate" : { },
- "selected_hover" : { },
- "selected_idle" : { },
- "selected_insensitive" : { },
- "activate" : { },
- "hover" : { },
- "idle" : { },
- "insensitive" : { },
- "" : { },
- }
-
- # Compatibility with old versions of the class.
- active = False
- children = False
- arguments = DEFAULT_ARGUMENTS
-
- def __init__(self,
- child=None,
- function=None,
-
- style='transform',
- focus=None,
- default=False,
-
- **kwargs):
-
- self.kwargs = kwargs
- self.style_arg = style
-
- super(Transform, self).__init__(style=style, focus=focus, default=default)
-
- self.function = function
-
- child = renpy.easy.displayable_or_none(child)
- if child is not None:
- self.add(child)
-
- self.state = TransformState()
-
- self.arguments = dict((k, {}) for k in self.DEFAULT_ARGUMENTS)
-
- # Split up the keyword arguments.
- for k, v in kwargs.items():
- if "_" in k:
- prefix, prop = k.rsplit("_", 1)
- else:
- prefix = ""
- prop = k
-
- if prefix not in self.arguments:
- raise Exception("Unknown transform property prefix: %r" % prefix)
-
- if prop not in renpy.atl.PROPERTIES:
- raise Exception("Unknown transform property: %r")
-
- self.arguments[prefix][prop] = v
-
-
- # Apply the keyword arguments.
- for k, v in kwargs.items():
- setattr(self.state, k, v)
-
- # This is the matrix transforming our coordinates into child coordinates.
- self.forward = None
-
- # Have we called the function at least once?
- self.active = False
-
- # Have we been requested to hide?
- self.hide_request = False
-
- # True if it's okay for us to hide.
- self.hide_response = True
-
- # Have we been requested to replaced?
- self.replaced_request = False
-
- # True if it's okay for us to replaced.
- self.replaced_response = True
-
- self.st = 0
- self.at = 0
- self.st_offset = 0
- self.at_offset = 0
-
- self.child_st_base = 0
-
- def visit(self):
- if self.child is None:
- return [ ]
- else:
- return [ self.child ]
-
- # The default function chooses entries from self.arguments that match
- # the style prefix, and applies them to the state.
- def default_function(self, state, st, at):
-
- prefix = self.style.prefix.strip("_")
- prefixes = [ ]
-
- while prefix:
- prefixes.insert(0, prefix)
- _, _, prefix = prefix.partition("_")
-
- prefixes.insert(0, "")
-
- for i in prefixes:
- for k, v in self.arguments[i].items():
- setattr(state, k, v)
-
- return None
-
- def set_transform_event(self, event):
- if self.child is not None:
- self.child.set_transform_event(event)
-
- super(Transform, self).set_transform_event(event)
-
-
- def take_state(self, t):
- """
- Takes the transformation state from object t into this object.
- """
-
- self.state.take_state(t.state)
-
- # The arguments will be applied when the default function is
- # called.
-
-
- def take_execution_state(self, t):
- """
- Takes the execution state from object t into this object. This is
- overridden by renpy.atl.TransformBase.
- """
-
- self.hide_request = t.hide_request
- self.replaced_request = t.replaced_request
-
- self.state.xpos = t.state.xpos
- self.state.ypos = t.state.ypos
- self.state.xanchor = t.state.xanchor
- self.state.yanchor = t.state.yanchor
-
- if isinstance(self.child, Transform) and isinstance(t.child, Transform):
- self.child.take_execution_state(t.child)
-
-
- 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()
-
- if self.child is not None:
- rv.set_child(self.child._change_transform_child(child))
-
- return rv
-
- def _hide(self, st, at, kind):
-
- if not self.child:
- return None
-
- if not (self.hide_request or self.replaced_request):
- d = self.copy()
- else:
- d = self
-
- d.st_offset = self.st_offset
- d.at_offset = self.at_offset
-
- if kind == "hide":
- d.hide_request = True
- else:
- d.replaced_request = True
-
- d.hide_response = True
- d.replaced_response = True
-
- if d.function is not None:
- d.function(d, st + d.st_offset, at + d.at_offset)
-
- new_child = d.child._hide(st, at, kind)
-
- if new_child is not None:
- d.child = new_child
- d.hide_response = False
- d.replaced_response = False
-
- if (not d.hide_response) or (not d.replaced_response):
- renpy.display.render.redraw(d, 0)
- return d
-
- return None
-
- def set_child(self, child):
-
- child = renpy.easy.displayable(child)
-
- self.child = child
- self.child_st_base = self.st
-
- child.per_interact()
-
- renpy.display.render.redraw(self, 0)
-
- def update_state(self):
- """
- This updates the state to that at self.st, self.at.
- """
-
- # If we have to, call the function that updates this transform.
- if self.function is not None:
- fr = self.function(self, self.st, self.at)
- else:
- fr = self.default_function(self, self.st, self.at)
-
- # Order a redraw, if necessary.
- if fr is not None:
- renpy.display.render.redraw(self, fr)
-
- state = self.state
-
- self.active = True
-
- # Use non-None elements of the child placement as defaults.
- child = self.child
- if child is not None and renpy.config.transform_uses_child_position:
-
- pos = child.get_placement()
-
- if pos[0] is not None:
- state.default_xpos = pos[0]
- if pos[2] is not None:
- state.default_xanchor = pos[2]
- if pos[1] is not None:
- state.default_ypos = pos[1]
- if pos[3] is not None:
- state.default_yanchor = pos[3]
-
- state.subpixel |= pos[6]
-
- # The render method is now defined in accelerator.pyx.
-
- def event(self, ev, x, y, st):
-
- if self.hide_request:
- return None
-
- children = self.children
- offsets = self.offsets
-
- if not offsets:
- return None
-
- for i in range(len(self.children)-1, -1, -1):
-
- d = children[i]
- xo, yo = offsets[i]
-
- cx = x - xo
- cy = y - yo
-
- # Transform screen coordinates to child coordinates.
- cx, cy = self.forward.transform(cx, cy)
-
- rv = d.event(ev, cx, cy, st)
- if rv is not None:
- return rv
-
- return None
-
- def __call__(self, child=None, take_state=True):
-
- if child is None:
- child = self.child
-
- # If we don't have a child for some reason, set it to null.
- if child is None:
- child = get_null()
-
- rv = Transform(
- child=child,
- function=self.function,
- style=self.style_arg,
- **self.kwargs)
-
- rv.take_state(self)
-
- return rv
-
- def get_placement(self):
-
- if not self.active:
- self.update_state()
-
- if self.child is not None:
- _cxpos, _cypos, _cxanchor, _cyanchor, cxoffset, cyoffset, _csubpixel = self.child.get_placement()
- else:
- cxoffset = 0
- cyoffset = 0
-
- cxoffset = cxoffset or 0
- cyoffset = cyoffset or 0
-
- rv = self.state.get_placement(cxoffset, cyoffset)
-
- if self.state.transform_anchor:
-
- xpos, ypos, xanchor, yanchor, xoffset, yoffset, subpixel = rv
- if (xanchor is not None) and (yanchor is not None):
-
- cw, ch = self.child_size
- rw, rh = self.render_size
-
- if isinstance(xanchor, float):
- xanchor *= cw
- if isinstance(yanchor, float):
- yanchor *= ch
-
- xanchor -= cw / 2.0
- yanchor -= ch / 2.0
-
- xanchor, yanchor = self.reverse.transform(xanchor, yanchor)
-
- xanchor += rw / 2.0
- yanchor += rh / 2.0
-
- xanchor = renpy.display.core.absolute(xanchor)
- yanchor = renpy.display.core.absolute(yanchor)
-
- rv = (xpos, ypos, xanchor, yanchor, xoffset, yoffset, subpixel)
-
- return rv
-
- def update(self):
- """
- This should be called when a transform property field is updated outside
- of the callback method, to ensure that the change takes effect.
- """
-
- renpy.display.render.invalidate(self)
-
- def parameterize(self, name, parameters):
- if parameters:
- raise Exception("Image '%s' can't take parameters '%s'. (Perhaps you got the name wrong?)" %
- (' '.join(name), ' '.join(parameters)))
-
- # Note the call here.
- return self()
-
- def _show(self):
- self.update_state()
-
-Transform.render = types.MethodType(renpy.display.accelerator.transform_render, None, Transform)
-
-class ATLTransform(renpy.atl.ATLTransformBase, Transform):
-
- def __init__(self, atl, child=None, context={}, parameters=None, **properties):
- renpy.atl.ATLTransformBase.__init__(self, atl, context, parameters)
- Transform.__init__(self, child=child, function=self.execute, **properties)
-
- self.raw_child = self.child
-
- def _show(self):
- super(ATLTransform, self)._show()
- self.execute(self, self.st, self.at)
-
-
-class Motion(Container):
- """
- This is used to move a child displayable around the screen. It
- works by supplying a time value to a user-supplied function,
- which is in turn expected to return a pair giving the x and y
- location of the upper-left-hand corner of the child, or a
- 4-tuple giving that and the xanchor and yanchor of the child.
-
- The time value is a floating point number that ranges from 0 to
- 1. If repeat is True, then the motion repeats every period
- sections. (Otherwise, it stops.) If bounce is true, the
- time value varies from 0 to 1 to 0 again.
-
- The function supplied needs to be pickleable, which means it needs
- to be defined as a name in an init block. It cannot be a lambda or
- anonymous inner function. If you can get away with using Pan or
- Move, use them instead.
-
- Please note that floats and ints are interpreted as for xpos and
- ypos, with floats being considered fractions of the screen.
- """
-
- def __init__(self, function, period, child=None, new_widget=None, old_widget=None, repeat=False, bounce=False, delay=None, anim_timebase=False, tag_start=None, time_warp=None, add_sizes=False, style='motion', **properties):
- """
- @param child: The child displayable.
-
- @param new_widget: If child is None, it is set to new_widget,
- so that we can speak the transition protocol.
-
- @param old_widget: Ignored, for compatibility with the transition protocol.
-
- @param function: A function that takes a floating point value and returns
- an xpos, ypos tuple.
-
- @param period: The amount of time it takes to go through one cycle, in seconds.
-
- @param repeat: Should we repeat after a period is up?
-
- @param bounce: Should we bounce?
-
- @param delay: How long this motion should take. If repeat is None, defaults to period.
-
- @param anim_timebase: If True, use the animation timebase rather than the shown timebase.
-
- @param time_warp: If not None, this is a function that takes a
- fraction of the period (between 0.0 and 1.0), and returns a
- new fraction of the period. Use this to warp time, applying
- acceleration and deceleration to motions.
-
- This can also be used as a transition. When used as a
- transition, the motion is applied to the new_widget for delay
- seconds.
- """
-
- if child is None:
- child = new_widget
-
- if delay is None and not repeat:
- delay = period
-
- super(Motion, self).__init__(style=style, **properties)
-
- if child is not None:
- self.add(child)
-
- self.function = function
- self.period = period
- self.repeat = repeat
- self.bounce = bounce
- self.delay = delay
- self.anim_timebase = anim_timebase
- self.time_warp = time_warp
- self.add_sizes = add_sizes
-
- self.position = None
-
-
- def get_placement(self):
-
- if self.position is None:
- return super(Motion, self).get_placement()
- else:
- return self.position + (self.style.xoffset, self.style.yoffset, self.style.subpixel)
-
- def render(self, width, height, st, at):
-
- if self.anim_timebase:
- t = at
- else:
- t = st
-
- if renpy.game.less_updates:
- if self.delay:
- t = self.delay
- if self.repeat:
- t = t % self.period
- else:
- t = self.period
- elif self.delay and t >= self.delay:
- t = self.delay
- if self.repeat:
- t = t % self.period
- elif self.repeat:
- t = t % self.period
- renpy.display.render.redraw(self, 0)
- else:
- if t > self.period:
- t = self.period
- else:
- renpy.display.render.redraw(self, 0)
-
- if self.period > 0:
- t /= self.period
- else:
- t = 1
-
- if self.time_warp:
- t = self.time_warp(t)
-
- if self.bounce:
- t = t * 2
- if t > 1.0:
- t = 2.0 - t
-
- child = render(self.child, width, height, st, at)
- cw, ch = child.get_size()
-
- if self.add_sizes:
- res = self.function(t, (width, height, cw, ch))
- else:
- res = self.function(t)
-
- res = tuple(res)
-
- if len(res) == 2:
- self.position = res + (self.style.xanchor, self.style.yanchor)
- else:
- self.position = res
-
- rv = renpy.display.render.Render(cw, ch)
- rv.blit(child, (0, 0))
-
- self.offsets = [ (0, 0) ]
-
- return rv
-
-
-class Interpolate(object):
-
- anchors = {
- 'top' : 0.0,
- 'center' : 0.5,
- 'bottom' : 1.0,
- 'left' : 0.0,
- 'right' : 1.0,
- }
-
- def __init__(self, start, end):
-
- if len(start) != len(end):
- raise Exception("The start and end must have the same number of arguments.")
-
- self.start = [ self.anchors.get(i, i) for i in start ]
- self.end = [ self.anchors.get(i, i) for i in end ]
-
- def __call__(self, t, sizes=(None, None, None, None)):
-
- def interp(a, b, c):
-
- if c is not None:
- if type(a) is float:
- a = a * c
- if type(b) is float:
- b = b * c
-
- rv = a + t * (b - a)
-
- return renpy.display.core.absolute(rv)
-
- return [ interp(a, b, c) for a, b, c in zip(self.start, self.end, sizes) ]
-
-
-def Pan(startpos, endpos, time, child=None, repeat=False, bounce=False,
- anim_timebase=False, style='motion', time_warp=None, **properties):
- """
- This is used to pan over a child displayable, which is almost
- always an image. It works by interpolating the placement of the
- upper-left corner of the screen, over time. It's only really
- suitable for use with images that are larger than the screen,
- and we don't do any cropping on the image.
-
- @param startpos: The initial coordinates of the upper-left
- corner of the screen, relative to the image.
-
- @param endpos: The coordinates of the upper-left corner of the
- screen, relative to the image, after time has elapsed.
-
- @param time: The time it takes to pan from startpos to endpos.
-
- @param child: The child displayable.
-
- @param repeat: True if we should repeat this forever.
-
- @param bounce: True if we should bounce from the start to the end
- to the start.
-
- @param anim_timebase: True if we use the animation timebase, False to use the
- displayable timebase.
-
- @param time_warp: If not None, this is a function that takes a
- fraction of the period (between 0.0 and 1.0), and returns a
- new fraction of the period. Use this to warp time, applying
- acceleration and deceleration to motions.
-
- This can be used as a transition. See Motion for details.
- """
-
- x0, y0 = startpos
- x1, y1 = endpos
-
- return Motion(Interpolate((-x0, -y0), (-x1, -y1)),
- time,
- child,
- repeat=repeat,
- bounce=bounce,
- style=style,
- anim_timebase=anim_timebase,
- time_warp=time_warp,
- add_sizes=True,
- **properties)
-
-def Move(startpos, endpos, time, child=None, repeat=False, bounce=False,
- anim_timebase=False, style='motion', time_warp=None, **properties):
- """
- This is used to pan over a child displayable relative to
- the containing area. It works by interpolating the placement of the
- the child, over time.
-
- @param startpos: The initial coordinates of the child
- relative to the containing area.
-
- @param endpos: The coordinates of the child at the end of the
- move.
-
- @param time: The time it takes to move from startpos to endpos.
-
- @param child: The child displayable.
-
- @param repeat: True if we should repeat this forever.
-
- @param bounce: True if we should bounce from the start to the end
- to the start.
-
- @param anim_timebase: True if we use the animation timebase, False to use the
- displayable timebase.
-
- @param time_warp: If not None, this is a function that takes a
- fraction of the period (between 0.0 and 1.0), and returns a
- new fraction of the period. Use this to warp time, applying
- acceleration and deceleration to motions.
-
- This can be used as a transition. See Motion for details.
- """
-
- return Motion(Interpolate(startpos, endpos),
- time,
- child,
- repeat=repeat,
- bounce=bounce,
- anim_timebase=anim_timebase,
- style=style,
- time_warp=time_warp,
- add_sizes=True,
- **properties)
-
-
-class Revolver(object):
-
- def __init__(self, start, end, child, around=(0.5, 0.5), cor=(0.5, 0.5), pos=None):
- self.start = start
- self.end = end
- self.around = around
- self.cor = cor
- self.pos = pos
- self.child = child
-
- def __call__(self, t, xxx_todo_changeme):
-
- # Converts a float to an integer in the given range, passes
- # integers through unchanged.
- (w, h, cw, ch) = xxx_todo_changeme
- def fti(x, r):
- if x is None:
- x = 0
-
- if isinstance(x, float):
- return int(x * r)
- else:
- return x
-
- if self.pos is None:
- pos = self.child.get_placement()
- else:
- pos = self.pos
-
- xpos, ypos, xanchor, yanchor, _xoffset, _yoffset, _subpixel = pos
-
- xpos = fti(xpos, w)
- ypos = fti(ypos, h)
- xanchor = fti(xanchor, cw)
- yanchor = fti(yanchor, ch)
-
- xaround, yaround = self.around
-
- xaround = fti(xaround, w)
- yaround = fti(yaround, h)
-
- xcor, ycor = self.cor
-
- xcor = fti(xcor, cw)
- ycor = fti(ycor, ch)
-
- angle = self.start + (self.end - self.start) * t
- angle *= math.pi / 180
-
- # The center of rotation, relative to the xaround.
- x = xpos - xanchor + xcor - xaround
- y = ypos - yanchor + ycor - yaround
-
- # Rotate it.
- nx = x * math.cos(angle) - y * math.sin(angle)
- ny = x * math.sin(angle) + y * math.cos(angle)
-
- # Project it back.
- nx = nx - xcor + xaround
- ny = ny - ycor + yaround
-
- return (renpy.display.core.absolute(nx), renpy.display.core.absolute(ny), 0, 0)
-
-
-def Revolve(start, end, time, child, around=(0.5, 0.5), cor=(0.5, 0.5), pos=None, **properties):
-
- return Motion(Revolver(start, end, child, around=around, cor=cor, pos=pos),
- time,
- child,
- add_sizes=True,
- **properties)
-
-
-
-def zoom_render(crend, x, y, w, h, zw, zh, bilinear):
- """
- This creates a render that zooms its child.
-
- `crend` - The render of the child.
- `x`, `y`, `w`, `h` - A rectangle inside the child.
- `zw`, `zh` - The size the rectangle is rendered to.
- `bilinear` - Should we be rendering in bilinear mode?
- """
-
- rv = renpy.display.render.Render(zw, zh)
-
- if zw == 0 or zh == 0 or w == 0 or h == 0:
- return rv
-
-
- rv.forward = renpy.display.render.Matrix2D(w / zw, 0, 0, h / zh)
- rv.reverse = renpy.display.render.Matrix2D(zw / w, 0, 0, zh / h)
-
- rv.clipping = True
-
- rv.blit(crend, rv.reverse.transform(-x, -y))
-
- return rv
-
-
-class ZoomCommon(renpy.display.core.Displayable):
- def __init__(self,
- time, child,
- end_identity=False,
- after_child=None,
- time_warp=None,
- bilinear=True,
- opaque=True,
- anim_timebase=False,
- repeat=False,
- style='motion',
- **properties):
- """
- @param time: The amount of time it will take to
- interpolate from the start to the end rectange.
-
- @param child: The child displayable.
-
- @param after_child: If present, a second child
- widget. This displayable will be rendered after the zoom
- completes. Use this to snap to a sharp displayable after
- the zoom is done.
-
- @param time_warp: If not None, this is a function that takes a
- fraction of the period (between 0.0 and 1.0), and returns a
- new fraction of the period. Use this to warp time, applying
- acceleration and deceleration to motions.
- """
-
- super(ZoomCommon, self).__init__(style=style, **properties)
-
- child = renpy.easy.displayable(child)
-
- self.time = time
- self.child = child
- self.repeat = repeat
-
- if after_child:
- self.after_child = renpy.easy.displayable(after_child)
- else:
- if end_identity:
- self.after_child = child
- else:
- self.after_child = None
-
- self.time_warp = time_warp
- self.bilinear = bilinear
- self.opaque = opaque
- self.anim_timebase = anim_timebase
-
-
- def visit(self):
- return [ self.child, self.after_child ]
-
- def render(self, width, height, st, at):
-
- if self.anim_timebase:
- t = at
- else:
- t = st
-
- if self.time:
- done = min(t / self.time, 1.0)
- else:
- done = 1.0
-
- if self.repeat:
- done = done % 1.0
-
- if renpy.game.less_updates:
- done = 1.0
-
- self.done = done
-
- if self.after_child and done == 1.0:
- return renpy.display.render.render(self.after_child, width, height, st, at)
-
- if self.time_warp:
- done = self.time_warp(done)
-
- rend = renpy.display.render.render(self.child, width, height, st, at)
-
- rx, ry, rw, rh, zw, zh = self.zoom_rectangle(done, rend.width, rend.height)
-
- if rx < 0 or ry < 0 or rx + rw > rend.width or ry + rh > rend.height:
- raise Exception("Zoom rectangle %r falls outside of %dx%d parent surface." % ((rx, ry, rw, rh), rend.width, rend.height))
-
- rv = zoom_render(rend, rx, ry, rw, rh, zw, zh, self.bilinear)
-
- if self.done < 1.0:
- renpy.display.render.redraw(self, 0)
-
- return rv
-
- def event(self, ev, x, y, st):
-
- if not self.time:
- done = 1.0
- else:
- done = min(st / self.time, 1.0)
-
- if done == 1.0 and self.after_child:
- return self.after_child.event(ev, x, y, st)
- else:
- return None
-
-
-class Zoom(ZoomCommon):
-
- def __init__(self, size, start, end, time, child, **properties):
-
- end_identity = (end == (0.0, 0.0) + size)
-
- super(Zoom, self).__init__(time, child, end_identity=end_identity, **properties)
-
- self.size = size
- self.start = start
- self.end = end
-
- def zoom_rectangle(self, done, width, height):
-
- rx, ry, rw, rh = [ (a + (b - a) * done) for a, b in zip(self.start, self.end) ]
-
- return rx, ry, rw, rh, self.size[0], self.size[1]
-
-
-class FactorZoom(ZoomCommon):
-
- def __init__(self, start, end, time, child, **properties):
-
- end_identity = (end == 1.0)
-
- super(FactorZoom, self).__init__(time, child, end_identity=end_identity, **properties)
-
- self.start = start
- self.end = end
-
- def zoom_rectangle(self, done, width, height):
-
- factor = self.start + (self.end - self.start) * done
-
- return 0, 0, width, height, factor * width, factor * height
-
-
-
-class SizeZoom(ZoomCommon):
-
- def __init__(self, start, end, time, child, **properties):
-
- end_identity = False
-
- super(SizeZoom, self).__init__(time, child, end_identity=end_identity, **properties)
-
- self.start = start
- self.end = end
-
- def zoom_rectangle(self, done, width, height):
-
- sw, sh = self.start
- ew, eh = self.end
-
- zw = sw + (ew - sw) * done
- zh = sh + (eh - sh) * done
-
- return 0, 0, width, height, zw, zh
-
-
-class RotoZoom(renpy.display.core.Displayable):
-
- transform = None
-
- def __init__(self,
- rot_start,
- rot_end,
- rot_delay,
- zoom_start,
- zoom_end,
- zoom_delay,
- child,
- rot_repeat=False,
- zoom_repeat=False,
- rot_bounce=False,
- zoom_bounce=False,
- rot_anim_timebase=False,
- zoom_anim_timebase=False,
- rot_time_warp=None,
- zoom_time_warp=None,
- opaque=False,
- style='motion',
- **properties):
-
- super(RotoZoom, self).__init__(style=style, **properties)
-
- self.rot_start = rot_start
- self.rot_end = rot_end
- self.rot_delay = rot_delay
-
- self.zoom_start = zoom_start
- self.zoom_end = zoom_end
- self.zoom_delay = zoom_delay
-
- self.child = renpy.easy.displayable(child)
-
- self.rot_repeat = rot_repeat
- self.zoom_repeat = zoom_repeat
-
- self.rot_bounce = rot_bounce
- self.zoom_bounce = zoom_bounce
-
- self.rot_anim_timebase = rot_anim_timebase
- self.zoom_anim_timebase = zoom_anim_timebase
-
- self.rot_time_warp = rot_time_warp
- self.zoom_time_warp = zoom_time_warp
-
- self.opaque = opaque
-
-
- def visit(self):
- return [ self.child ]
-
-
- def render(self, width, height, st, at):
-
- if self.rot_anim_timebase:
- rot_time = at
- else:
- rot_time = st
-
- if self.zoom_anim_timebase:
- zoom_time = at
- else:
- zoom_time = st
-
- if self.rot_delay == 0:
- rot_time = 1.0
- else:
- rot_time /= self.rot_delay
-
- if self.zoom_delay == 0:
- zoom_time = 1.0
- else:
- zoom_time /= self.zoom_delay
-
- if self.rot_repeat:
- rot_time %= 1.0
-
- if self.zoom_repeat:
- zoom_time %= 1.0
-
- if self.rot_bounce:
- rot_time *= 2
- rot_time = min(rot_time, 2.0 - rot_time)
-
- if self.zoom_bounce:
- zoom_time *= 2
- zoom_time = min(zoom_time, 2.0 - zoom_time)
-
- if renpy.game.less_updates:
- rot_time = 1.0
- zoom_time = 1.0
-
- rot_time = min(rot_time, 1.0)
- zoom_time = min(zoom_time, 1.0)
-
- if self.rot_time_warp:
- rot_time = self.rot_time_warp(rot_time)
-
- if self.zoom_time_warp:
- zoom_time = self.zoom_time_warp(zoom_time)
-
-
- angle = self.rot_start + (1.0 * self.rot_end - self.rot_start) * rot_time
- zoom = self.zoom_start + (1.0 * self.zoom_end - self.zoom_start) * zoom_time
- # angle = -angle * math.pi / 180
-
- zoom = max(zoom, 0.001)
-
- if self.transform is None:
- self.transform = Transform(self.child)
-
- self.transform.rotate = angle
- self.transform.zoom = zoom
-
- rv = renpy.display.render.render(self.transform, width, height, st, at)
-
- if rot_time <= 1.0 or zoom_time <= 1.0:
- renpy.display.render.redraw(self.transform, 0)
-
- return rv
-
-
-# For compatibility with old games.
-renpy.display.layout.Transform = Transform
-renpy.display.layout.RotoZoom = RotoZoom
-renpy.display.layout.SizeZoom = SizeZoom
-renpy.display.layout.FactorZoom = FactorZoom
-renpy.display.layout.Zoom = Zoom
-renpy.display.layout.Revolver = Revolver
-renpy.display.layout.Motion = Motion
-renpy.display.layout.Interpolate = Interpolate
-
-# Leave these functions around - they might have been pickled somewhere.
-renpy.display.layout.Revolve = Revolve # function
-renpy.display.layout.Move = Move # function
-renpy.display.layout.Pan = Pan # function