summaryrefslogtreecommitdiff
path: root/unrpyc/renpy/display/behavior.py
diff options
context:
space:
mode:
Diffstat (limited to 'unrpyc/renpy/display/behavior.py')
-rw-r--r--unrpyc/renpy/display/behavior.py1531
1 files changed, 0 insertions, 1531 deletions
diff --git a/unrpyc/renpy/display/behavior.py b/unrpyc/renpy/display/behavior.py
deleted file mode 100644
index 02eccf2..0000000
--- a/unrpyc/renpy/display/behavior.py
+++ /dev/null
@@ -1,1531 +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 contains various Displayables that handle events.
-
-
-import renpy.display
-import renpy.audio
-
-from renpy.display.render import render, Render
-
-import pygame
-
-def compile_event(key, keydown):
- """
- Compiles a keymap entry into a python expression.
-
- keydown determines if we are dealing with keys going down (press),
- or keys going up (release).
- """
-
- # Lists or tuples get turned into or expressions.
- if isinstance(key, (list, tuple)):
- if not key:
- return "(False)"
-
- return "(" + " or ".join([compile_event(i, keydown) for i in key]) + ")"
-
- # If it's in config.keymap, compile what's in config.keymap.
- if key in renpy.config.keymap:
- return compile_event(renpy.config.keymap[key], keydown)
-
- if key is None:
- return "(False)"
-
- part = key.split("_")
-
- # Deal with the mouse.
- if part[0] == "mousedown":
- if keydown:
- return "(ev.type == %d and ev.button == %d)" % (pygame.MOUSEBUTTONDOWN, int(part[1]))
- else:
- return "(False)"
-
- if part[0] == "mouseup":
- if keydown:
- return "(ev.type == %d and ev.button == %d)" % (pygame.MOUSEBUTTONUP, int(part[1]))
- else:
- return "(False)"
-
- # Deal with the Joystick.
- if part[0] == "joy":
- if keydown:
- return "(ev.type == %d and ev.press and ev.press == renpy.game.preferences.joymap.get(%r, None))" % (renpy.display.core.JOYEVENT, key)
- else:
- return "(ev.type == %d and ev.release and ev.release == renpy.game.preferences.joymap.get(%r, None))" % (renpy.display.core.JOYEVENT, key)
-
- # Otherwise, deal with it as a key.
- if keydown:
- rv = "(ev.type == %d" % pygame.KEYDOWN
- else:
- rv = "(ev.type == %d" % pygame.KEYUP
-
- if part[0] == "alt":
- part.pop(0)
- rv += " and (ev.mod & %d)" % pygame.KMOD_ALT
- else:
- rv += " and not (ev.mod & %d)" % pygame.KMOD_ALT
-
- if part[0] == "meta":
- part.pop(0)
- rv += " and (ev.mod & %d)" % pygame.KMOD_META
- else:
- rv += " and not (ev.mod & %d)" % pygame.KMOD_META
-
- if part[0] == "shift":
- part.pop(0)
- rv += " and (ev.mod & %d)" % pygame.KMOD_SHIFT
-
- if part[0] == "noshift":
- part.pop(0)
- rv += " and not (ev.mod & %d)" % pygame.KMOD_SHIFT
-
- if len(part) == 1:
- if len(part[0]) != 1:
- if renpy.config.developer:
- raise Exception("Invalid key specifier %s" % key)
- else:
- return "(False)"
-
- rv += " and ev.unicode == %r)" % part[0]
-
- else:
- if part[0] != "K":
- if renpy.config.developer:
- raise Exception("Invalid key specifier %s" % key)
- else:
- return "(False)"
-
- key = "_".join(part)
-
- rv += " and ev.key == %d)" % (getattr(pygame.constants, key))
-
- return rv
-
-# These store a lambda for each compiled key in the system.
-event_cache = { }
-keyup_cache = { }
-
-def map_event(ev, name):
- """Returns true if the event matches the named keycode being pressed."""
-
- check_code = event_cache.get(name, None)
- if check_code is None:
- check_code = eval("lambda ev : " + compile_event(name, True), globals())
- event_cache[name] = check_code
-
- return check_code(ev)
-
-def map_keyup(ev, name):
- """Returns true if the event matches the named keycode being released."""
-
- check_code = keyup_cache.get(name, None)
- if check_code is None:
- check_code = eval("lambda ev : " + compile_event(name, False), globals())
- keyup_cache[name] = check_code
-
- return check_code(ev)
-
-
-def skipping(ev):
- """
- This handles setting skipping in response to the press of one of the
- CONTROL keys. The library handles skipping in response to TAB.
- """
-
- if not renpy.config.allow_skipping:
- return
-
- if map_event(ev, "skip"):
- renpy.config.skipping = "slow"
- renpy.exports.restart_interaction()
-
- if map_keyup(ev, "skip"):
- renpy.config.skipping = None
- renpy.exports.restart_interaction()
-
- return
-
-
-def inspector(ev):
- return map_event(ev, "inspector")
-
-
-##############################################################################
-# Utility functions for dealing with actions.
-
-def predict_action(var):
- """
- Predicts some of the actions that may be caused by a variable.
- """
-
- if var is None:
- return
-
- if isinstance(var, renpy.ui.Action):
- var.predict()
-
- if isinstance(var, (list, tuple)):
- for i in var:
- predict_action(i)
-
-def run(var, *args, **kwargs):
- """
- Runs a variable. This is done by calling all the functions, and
- iterating over the lists and tuples.
- """
-
- if var is None:
- return None
-
- if isinstance(var, (list, tuple)):
- rv = None
-
- for i in var:
- new_rv = run(i, *args, **kwargs)
-
- if new_rv is not None:
- rv = new_rv
-
- return rv
-
- return var(*args, **kwargs)
-
-def run_unhovered(var):
- """
- Calls the unhovered method on the variable, if it exists.
- """
-
- if var is None:
- return None
-
- if isinstance(var, (list, tuple)):
- for i in var:
- run_unhovered(i)
-
- return
-
- f = getattr(var, "unhovered", None)
- if f is not None:
- f()
-
-def run_periodic(var, st):
-
- if isinstance(var, (list, tuple)):
- rv = None
-
- for i in var:
- v = run_periodic(i, st)
-
- if rv is None or v < rv:
- rv = v
-
- return rv
-
- if isinstance(var, renpy.ui.Action):
- return var.periodic(st)
-
-
-def is_selected(clicked):
-
- if isinstance(clicked, (list, tuple)):
- return any(is_selected(i) for i in clicked)
-
- elif isinstance(clicked, renpy.ui.Action):
- return clicked.get_selected()
- else:
- return False
-
-
-def is_sensitive(clicked):
-
- if isinstance(clicked, (list, tuple)):
- return all(is_sensitive(i) for i in clicked)
-
- elif isinstance(clicked, renpy.ui.Action):
- return clicked.get_sensitive()
- else:
- return True
-
-
-##############################################################################
-# Special-Purpose Displayables
-
-class Keymap(renpy.display.layout.Null):
- """
- This is a behavior that maps keys to actions that are called when
- the key is pressed. The keys are specified by giving the appropriate
- k_constant from pygame.constants, or the unicode for the key.
- """
-
- def __init__(self, replaces=None, **keymap):
- super(Keymap, self).__init__(style='default')
- self.keymap = keymap
-
- def event(self, ev, x, y, st):
-
- for name, action in self.keymap.items():
- if map_event(ev, name):
-
- rv = run(action)
-
- if rv is not None:
- return rv
-
- raise renpy.display.core.IgnoreEvent()
-
- def predict_one_action(self):
- for i in self.keymap.values():
- predict_action(i)
-
-
-class RollForward(renpy.display.layout.Null):
- """
- This behavior implements rollforward.
- """
-
- def __init__(self, value, **properties):
- super(RollForward, self).__init__(**properties)
- self.value = value
-
-
- def event(self, ev, x, y, st):
-
- if map_event(ev, "rollforward"):
- renpy.game.interface.suppress_transition = True
- renpy.game.after_rollback = True
- renpy.game.log.rolled_forward = True
- return self.value
-
-
-class PauseBehavior(renpy.display.layout.Null):
- """
- This is a class implementing the Pause behavior, which is to
- return a value after a certain amount of time has elapsed.
- """
-
- def __init__(self, delay, result=False, **properties):
- super(PauseBehavior, self).__init__(**properties)
-
- self.delay = delay
- self.result = result
-
- def event(self, ev, x, y, st):
-
- if st >= self.delay:
-
- # If we have been drawn since the timeout, simply return
- # true. Otherwise, force a redraw, and return true when
- # it comes back.
- if renpy.game.interface.drawn_since(st - self.delay):
- return self.result
- else:
- renpy.game.interface.force_redraw = True
-
-
- renpy.game.interface.timeout(max(self.delay - st, 0))
-
-class SoundStopBehavior(renpy.display.layout.Null):
- """
- This is a class implementing the sound stop behavior,
- which is to return False when a sound is no longer playing
- on the named channel.
- """
-
- def __init__(self, channel, result=False, **properties):
- super(SoundStopBehavior, self).__init__(**properties)
-
- self.channel = channel
- self.result = result
-
-
- def event(self, ev, x, y, st):
-
- if not renpy.audio.music.get_playing(self.channel):
- return self.result
-
- renpy.game.interface.timeout(.025)
-
-
-class SayBehavior(renpy.display.layout.Null):
- """
- This is a class that implements the say behavior,
- which is to return True (ending the interaction) if
- the user presses space or enter, or clicks the left
- mouse button.
- """
-
- focusable = True
-
- def __init__(self, default=True, afm=None, dismiss=[ 'dismiss' ], allow_dismiss=None, **properties):
- super(SayBehavior, self).__init__(default=default, **properties)
-
- if not isinstance(dismiss, (list, tuple)):
- dismiss = [ dismiss ]
-
- if afm is not None:
- self.afm_length = len(afm)
- else:
- self.afm_length = None
-
- # What keybindings lead to dismissal?
- self.dismiss = dismiss
-
- self.allow_dismiss = allow_dismiss
-
- def set_afm_length(self, afm_length):
- self.afm_length = max(afm_length, 1)
-
- def event(self, ev, x, y, st):
-
- if self.afm_length and renpy.game.preferences.afm_time and renpy.game.preferences.afm_enable:
-
- afm_delay = ( 1.0 * ( renpy.config.afm_bonus + self.afm_length ) / renpy.config.afm_characters ) * renpy.game.preferences.afm_time
-
- if renpy.game.preferences.text_cps:
- afm_delay += 1.0 / renpy.game.preferences.text_cps * self.afm_length
-
- if st > afm_delay:
- if renpy.config.afm_callback:
- if renpy.config.afm_callback():
- return True
- else:
- renpy.game.interface.timeout(0.1)
- else:
- return True
- else:
- renpy.game.interface.timeout(afm_delay - st)
-
- for dismiss in self.dismiss:
-
- if map_event(ev, dismiss) and self.is_focused():
-
- if renpy.config.skipping:
- renpy.config.skipping = None
- renpy.exports.restart_interaction()
- raise renpy.display.core.IgnoreEvent()
-
- if renpy.game.preferences.using_afm_enable and renpy.game.preferences.afm_enable:
- renpy.game.preferences.afm_enable = False
- renpy.exports.restart_interaction()
- raise renpy.display.core.IgnoreEvent()
-
- if self.allow_dismiss:
- if not self.allow_dismiss():
- raise renpy.display.core.IgnoreEvent()
-
- return True
-
- skip_delay = renpy.config.skip_delay / 1000.0
-
- if renpy.config.allow_skipping and renpy.config.skipping:
-
- if st >= skip_delay:
- if renpy.game.preferences.skip_unseen:
- return True
- elif renpy.config.skipping == "fast":
- return True
- elif renpy.game.context().seen_current(True):
- return True
- else:
- renpy.game.interface.timeout(skip_delay - st)
-
-
- return None
-
-
-##############################################################################
-# Button
-
-class Button(renpy.display.layout.Window):
-
- keymap = { }
- action = None
-
- def __init__(self, child=None, style='button', clicked=None,
- hovered=None, unhovered=None, action=None, role=None,
- time_policy=None, keymap={},
- **properties):
-
- super(Button, self).__init__(child, style=style, **properties)
-
- if isinstance(clicked, renpy.ui.Action):
- action = clicked
-
- if action is not None:
- clicked = action
-
- if not is_sensitive(action):
- clicked = None
-
- if role is None:
- if action:
- if is_selected(action):
- role = 'selected_'
- else:
- role = ''
- else:
- role = ''
-
- self.action = action
- self.activated = False
- self.clicked = clicked
- self.hovered = hovered
- self.unhovered = unhovered
- self.focusable = clicked is not None
- self.role = role
- self.keymap = keymap
-
- self.time_policy_data = None
-
- def predict_one_action(self):
- predict_action(self.clicked)
- predict_action(self.hovered)
- predict_action(self.unhovered)
-
- if self.keymap:
- for v in self.keymap.values():
- predict_action(v)
-
- def render(self, width, height, st, at):
-
- if self.style.time_policy:
- st, self.time_policy_data = self.style.time_policy(st, self.time_policy_data, self.style)
-
- rv = super(Button, self).render(width, height, st, at)
-
- if self.clicked:
-
- rect = self.style.focus_rect
- if rect is not None:
- fx, fy, fw, fh = rect
- else:
- fx = self.style.left_margin
- fy = self.style.top_margin
- fw = rv.width - self.style.right_margin
- fh = rv.height - self.style.bottom_margin
-
- mask = self.style.focus_mask
-
- if mask is True:
- mask = rv
- elif mask is not None:
- mask = renpy.easy.displayable(mask)
- mask = renpy.display.render.render(mask, rv.width, rv.height, st, at)
-
- if mask is not None:
- fmx = 0
- fmy = 0
- else:
- fmx = None
- fmy = None
-
- rv.add_focus(self, None,
- fx, fy, fw, fh,
- fmx, fmy, mask)
-
- return rv
-
-
- def focus(self, default=False):
- super(Button, self).focus(default)
-
- if self.activated:
- return None
-
- rv = None
-
- if not default:
- rv = run(self.hovered)
-
- self.set_transform_event(self.role + "hover")
- self.child.set_transform_event(self.role + "hover")
-
- return rv
-
-
- def unfocus(self, default=False):
- super(Button, self).unfocus(default)
-
- if self.activated:
- return None
-
- if not default:
- run_unhovered(self.hovered)
- run(self.unhovered)
-
- self.set_transform_event(self.role + "idle")
- self.child.set_transform_event(self.role + "idle")
-
-
- def per_interact(self):
- if not self.clicked:
- self.set_style_prefix(self.role + "insensitive_", True)
- else:
- self.set_style_prefix(self.role + "idle_", True)
-
- super(Button, self).per_interact()
-
- def event(self, ev, x, y, st):
-
- # Call self.action.periodic()
- timeout = run_periodic(self.action, st)
-
- if timeout is not None:
- renpy.game.interface.timeout(timeout)
-
- # If we have a child, try passing the event to it. (For keyboard
- # events, this only happens if we're focused.)
- if self.is_focused() or not (ev.type == pygame.KEYDOWN or ev.type == pygame.KEYUP):
- rv = super(Button, self).event(ev, x, y, st)
- if rv is not None:
- return rv
-
- # If not focused, ignore all events.
- if not self.is_focused():
- return None
-
- # Check the keymap.
- for name, action in self.keymap.items():
- if map_event(ev, name):
- return run(action)
-
- # Ignore as appropriate:
- if map_event(ev, "button_ignore") and self.clicked:
- raise renpy.display.core.IgnoreEvent()
-
- # If clicked,
- if map_event(ev, "button_select") and self.clicked:
-
- self.activated = True
- self.style.set_prefix(self.role + 'activate_')
-
- if self.style.sound:
- renpy.audio.music.play(self.style.sound, channel="sound")
-
- rv = run(self.clicked)
-
- if rv is not None:
- return rv
- else:
- self.activated = False
-
- if self.is_focused():
- self.set_style_prefix(self.role + "hover_", True)
- else:
- self.set_style_prefix(self.role + "idle_", True)
-
- raise renpy.display.core.IgnoreEvent()
-
- return None
-
-
- def set_style_prefix(self, prefix, root):
- if root:
- super(Button, self).set_style_prefix(prefix, root)
-
-
-# Reimplementation of the TextButton widget as a Button and a Text
-# widget.
-def TextButton(text, style='button', text_style='button_text',
- clicked=None, **properties):
-
- text = renpy.text.text.Text(text, style=text_style) #@UndefinedVariable
- 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 list(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):
- def __init__(self, a, b):
- self.a = a
- self.b = b
-
- def __call__(self):
- self.a()
- if self.b:
- return self.b()
-
-
-class Input(renpy.text.text.Text): #@UndefinedVariable
- """
- This is a Displayable that takes text as input.
- """
-
- changed = None
- prefix = ""
- suffix = ""
- caret_pos = 0
-
- def __init__(self,
- default="",
- length=None,
- style='input',
- allow=None,
- exclude=None,
- prefix="",
- suffix="",
- changed=None,
- button=None,
- replaces=None,
- editable=True,
- **properties):
-
- super(Input, self).__init__("", style=style, replaces=replaces, substitute=False, **properties)
-
- self.content = str(default)
- self.length = length
-
- self.allow = allow
- self.exclude = exclude
- self.prefix = prefix
- self.suffix = suffix
-
- self.changed = changed
-
- self.editable = editable
-
- caretprops = { 'color' : None }
-
- for i in properties:
- if i.endswith("color"):
- caretprops[i] = properties[i]
-
- self.caret = renpy.display.image.Solid(xmaximum=1, style=style, **caretprops)
- self.caret_pos = len(self.content)
-
- if button:
- self.editable = False
- button.hovered = HoveredProxy(self.enable, button.hovered)
- button.unhovered = HoveredProxy(self.disable, button.unhovered)
-
- if isinstance(replaces, Input):
- self.content = replaces.content
- self.editable = replaces.editable
- self.caret_pos = replaces.caret_pos
-
- self.update_text(self.content, self.editable)
-
-
- def update_text(self, content, editable):
-
- if content != self.content or editable != self.editable:
- renpy.display.render.redraw(self, 0)
-
- if content != self.content:
- self.content = content
-
- if self.changed:
- self.changed(content)
-
- if content == "":
- content = "\u200b"
-
- self.editable = editable
-
- # Choose the caret.
- caret = self.style.caret
- if caret is None:
- caret = self.caret
-
- if editable:
- l = len(content)
- self.set_text([self.prefix, content[0:self.caret_pos].replace("{", "{{"), caret,
- content[self.caret_pos:l].replace("{", "{{"), self.suffix])
- else:
- self.set_text([self.prefix, content.replace("{", "{{"), self.suffix ])
-
- # This is needed to ensure the caret updates properly.
- def set_style_prefix(self, prefix, root):
- if prefix != self.style.prefix:
- self.update_text(self.content, self.editable)
-
- super(Input, self).set_style_prefix(prefix, root)
-
- def enable(self):
- self.update_text(self.content, True)
-
- def disable(self):
- self.update_text(self.content, False)
-
- def event(self, ev, x, y, st):
-
- if not self.editable:
- return None
-
- l = len(self.content)
-
- if map_event(ev, "input_backspace"):
-
- if self.content and self.caret_pos > 0:
- content = self.content[0:self.caret_pos-1] + self.content[self.caret_pos:l]
- self.caret_pos -= 1
- self.update_text(content, self.editable)
-
- renpy.display.render.redraw(self, 0)
- raise renpy.display.core.IgnoreEvent()
-
- elif map_event(ev, "input_enter"):
- if not self.changed:
- return self.content
-
- elif map_event(ev, "input_left"):
- if self.caret_pos > 0:
- self.caret_pos -= 1
- self.update_text(self.content, self.editable)
-
- renpy.display.render.redraw(self, 0)
- raise renpy.display.core.IgnoreEvent()
-
- elif map_event(ev, "input_right"):
- if self.caret_pos < l:
- self.caret_pos += 1
- self.update_text(self.content, self.editable)
-
- renpy.display.render.redraw(self, 0)
- raise renpy.display.core.IgnoreEvent()
-
- elif map_event(ev, "input_delete"):
- if self.caret_pos < l:
- content = self.content[0:self.caret_pos] + self.content[self.caret_pos+1:l]
- self.update_text(content, self.editable)
-
- renpy.display.render.redraw(self, 0)
- raise renpy.display.core.IgnoreEvent()
-
- elif ev.type == pygame.KEYDOWN and ev.str:
- if ord(ev.str[0]) < 32:
- return None
-
- if self.length and len(self.content) >= self.length:
- raise renpy.display.core.IgnoreEvent()
-
- if self.allow and ev.str not in self.allow:
- raise renpy.display.core.IgnoreEvent()
-
- if self.exclude and ev.str in self.exclude:
- raise renpy.display.core.IgnoreEvent()
-
- content = self.content[0:self.caret_pos] + ev.str + self.content[self.caret_pos:l]
- self.caret_pos += 1
-
- self.update_text(content, self.editable)
-
- raise renpy.display.core.IgnoreEvent()
-
-# A map from adjustment to lists of displayables that want to be redrawn
-# if the adjustment changes.
-adj_registered = { }
-
-# This class contains information about an adjustment that can change the
-# position of content.
-class Adjustment(renpy.object.Object):
- """
- :doc: ui
- :name: ui.adjustment class
-
- Adjustment objects represent a value that can be adjusted by a bar
- or viewport. They contain information about the value, the range
- of the value, and how to adjust the value in small steps and large
- pages.
-
-
- """
-
- def __init__(self, range=1, value=0, step=None, page=0, changed=None, adjustable=None, ranged=None): #@ReservedAssignment
- """
- The following parameters correspond to fields or properties on
- the adjustment object:
-
- `range`
- The range of the adjustment, a number.
-
- `value`
- The value of the adjustment, a number.
-
- `step`
- The step size of the adjustment, a number. If None, then
- defaults to 1/10th of a page, if set. Otherwise, defaults
- to the 1/20th of the range.
-
- This is used when scrolling a viewport with the mouse wheel.
-
- `page`
- The page size of the adjustment. If None, this is set
- automatically by a viewport. If never set, defaults to 1/10th
- of the range.
-
- It's can be used when clicking on a scrollbar.
-
- The following parameters control the behavior of the adjustment.
-
- `adjustable`
- If True, this adjustment can be changed by a bar. If False,
- it can't.
-
- It defaults to being adjustable if a `changed` function
- is given or if the adjustment is associated with a viewport,
- and not adjustable otherwise.
-
- `changed`
- This function is called with the new value when the value of
- the adjustment changes.
-
- `ranged`
- This function is called with the adjustment object when
- the range of the adjustment is set by a viewport.
-
- .. method:: change(value)
-
- Changes the value of the adjustment to `value`, updating
- any bars and viewports that use the adjustment.
- """
-
-
- super(Adjustment, self).__init__()
-
- if adjustable is None:
- if changed:
- adjustable = True
-
- self._value = value
- self._range = range
- self._page = page
- self._step = step
- self.changed = changed
- self.adjustable = adjustable
- self.ranged = ranged
-
- def get_value(self):
- if self._value > self._range:
- return self._range
-
- return self._value
-
- def set_value(self, v):
- self._value = v
-
- value = property(get_value, set_value)
-
- def get_range(self):
- return self._range
-
- def set_range(self, v):
- self._range = v
- if self.ranged:
- self.ranged(self)
-
- range = property(get_range, set_range) #@ReservedAssignment
-
- def get_page(self):
- if self._page is not None:
- return self._page
-
- return self._range / 10
-
- def set_page(self, v):
- self._page = v
-
- page = property(get_page, set_page)
-
- def get_step(self):
- if self._step is not None:
- return self._step
-
- if self._page is not None and self.page > 0:
- return self._page / 10
-
- if isinstance(self._range, float):
- return self._range / 10
- else:
- return 1
-
- def set_step(self, v):
- self._step = v
-
- step = property(get_step, set_step)
-
- # Register a displayable to be redrawn when this adjustment changes.
- def register(self, d):
- adj_registered.setdefault(self, [ ]).append(d)
-
- def change(self, value):
-
- if value < 0:
- value = 0
- if value > self._range:
- value = self._range
-
- if value != self._value:
- self._value = value
- for d in adj_registered.setdefault(self, [ ]):
- renpy.display.render.redraw(d, 0)
- if self.changed:
- return self.changed(value)
-
- return None
-
-class Bar(renpy.display.core.Displayable):
- """
- Implements a bar that can display an integer value, and respond
- to clicks on that value.
- """
-
- __version__ = 2
-
- def after_upgrade(self, version):
-
- if version < 1:
- self.adjustment = Adjustment(self.range, self.value, changed=self.changed) # E1101
- self.adjustment.register(self)
- del self.range # E1101
- del self.value # E1101
- del self.changed # E1101
-
- if version < 2:
- self.value = None
-
- def __init__(self,
- range=None, #@ReservedAssignment
- value=None,
- width=None,
- height=None,
- changed=None,
- adjustment=None,
- step=None,
- page=None,
- bar=None,
- style=None,
- vertical=False,
- replaces=None,
- hovered=None,
- unhovered=None,
- **properties):
-
- self.value = None
-
- if adjustment is None:
- if isinstance(value, renpy.ui.BarValue):
-
- if isinstance(replaces, Bar):
- value.replaces(replaces.value)
-
- self.value = value
- adjustment = value.get_adjustment()
- renpy.game.interface.timeout(0)
- else:
- adjustment = Adjustment(range, value, step=step, page=page, changed=changed)
-
- if style is None:
- if self.value is not None:
- if vertical:
- style = self.value.get_style()[1]
- else:
- style = self.value.get_style()[0]
- else:
- if vertical:
- style = 'vbar'
- else:
- style = 'bar'
-
- if width is not None:
- properties['xmaximum'] = width
-
- if height is not None:
- properties['ymaximum'] = height
-
- super(Bar, self).__init__(style=style, **properties)
-
- self.adjustment = adjustment
- self.focusable = True
-
- # These are set when we are first rendered.
- self.thumb_dim = 0
- self.height = 0
- self.width = 0
- self.hidden = False
-
- self.hovered = hovered
- self.unhovered = unhovered
-
- def per_interact(self):
- self.focusable = self.adjustment.adjustable
- self.adjustment.register(self)
-
- def predict_one(self):
- pd = renpy.display.predict.displayable
- style = self.style
-
- pd(style.insensitive_fore_bar)
- pd(style.idle_fore_bar)
- pd(style.hover_fore_bar)
- pd(style.selected_idle_fore_bar)
- pd(style.selected_hover_fore_bar)
-
- pd(style.insensitive_aft_bar)
- pd(style.idle_aft_bar)
- pd(style.hover_aft_bar)
- pd(style.selected_idle_aft_bar)
- pd(style.selected_hover_aft_bar)
-
- pd(style.insensitive_thumb)
- pd(style.idle_thumb)
- pd(style.hover_thumb)
- pd(style.selected_idle_thumb)
- pd(style.selected_hover_thumb)
-
- pd(style.insensitive_thumb_shadow)
- pd(style.idle_thumb_shadow)
- pd(style.hover_thumb_shadow)
- pd(style.selected_idle_thumb_shadow)
- pd(style.selected_hover_thumb_shadow)
-
- def render(self, width, height, st, at):
-
- # Handle redrawing.
- if self.value is not None:
- redraw = self.value.periodic(st)
-
- if redraw is not None:
- renpy.display.render.redraw(self, redraw)
-
- # Store the width and height for the event function to use.
- self.width = width
- self.height = height
- range = self.adjustment.range #@ReservedAssignment
- value = self.adjustment.value
- page = self.adjustment.page
-
- if range <= 0:
- if self.style.unscrollable == "hide":
- self.hidden = True
- return renpy.display.render.Render(width, height)
- elif self.style.unscrollable == "insensitive":
- self.set_style_prefix("insensitive_", True)
-
- self.hidden = False
-
- if self.style.bar_invert ^ self.style.bar_vertical:
- value = range - value
-
- bar_vertical = self.style.bar_vertical
-
- if bar_vertical:
- dimension = height
- else:
- dimension = width
-
- fore_gutter = self.style.fore_gutter
- aft_gutter = self.style.aft_gutter
-
- active = dimension - fore_gutter - aft_gutter
- if range:
- thumb_dim = active * page / (range + page)
- else:
- thumb_dim = active
-
- thumb_offset = abs(self.style.thumb_offset)
-
- if bar_vertical:
- thumb = render(self.style.thumb, width, thumb_dim, st, at)
- thumb_shadow = render(self.style.thumb_shadow, width, thumb_dim, st, at)
- thumb_dim = thumb.height
- else:
- thumb = render(self.style.thumb, thumb_dim, height, st, at)
- thumb_shadow = render(self.style.thumb_shadow, thumb_dim, height, st, at)
- thumb_dim = thumb.width
-
- # Remove the offset from the thumb.
- thumb_dim -= thumb_offset * 2
- self.thumb_dim = thumb_dim
-
- active -= thumb_dim
-
- if range:
- fore_size = active * value / range
- else:
- fore_size = active
-
- fore_size = int(fore_size)
-
- aft_size = active - fore_size
-
- fore_size += fore_gutter
- aft_size += aft_gutter
-
- rv = renpy.display.render.Render(width, height)
-
- if bar_vertical:
-
- if self.style.bar_resizing:
- foresurf = render(self.style.fore_bar, width, fore_size, st, at)
- aftsurf = render(self.style.aft_bar, width, aft_size, st, at)
- rv.blit(thumb_shadow, (0, fore_size - thumb_offset))
- rv.blit(foresurf, (0, 0), main=False)
- rv.blit(aftsurf, (0, height-aft_size), main=False)
- rv.blit(thumb, (0, fore_size - thumb_offset))
-
- else:
- foresurf = render(self.style.fore_bar, width, height, st, at)
- aftsurf = render(self.style.aft_bar, width, height, st, at)
-
- rv.blit(thumb_shadow, (0, fore_size - thumb_offset))
- rv.blit(foresurf.subsurface((0, 0, width, fore_size)), (0, 0), main=False)
- rv.blit(aftsurf.subsurface((0, height - aft_size, width, aft_size)), (0, height - aft_size), main=False)
- rv.blit(thumb, (0, fore_size - thumb_offset))
-
- else:
- if self.style.bar_resizing:
- foresurf = render(self.style.fore_bar, fore_size, height, st, at)
- aftsurf = render(self.style.aft_bar, aft_size, height, st, at)
- rv.blit(thumb_shadow, (fore_size - thumb_offset, 0))
- rv.blit(foresurf, (0, 0), main=False)
- rv.blit(aftsurf, (width-aft_size, 0), main=False)
- rv.blit(thumb, (fore_size - thumb_offset, 0))
-
- else:
- foresurf = render(self.style.fore_bar, width, height, st, at)
- aftsurf = render(self.style.aft_bar, width, height, st, at)
-
- rv.blit(thumb_shadow, (fore_size - thumb_offset, 0))
- rv.blit(foresurf.subsurface((0, 0, fore_size, height)), (0, 0), main=False)
- rv.blit(aftsurf.subsurface((width - aft_size, 0, aft_size, height)), (width-aft_size, 0), main=False)
- rv.blit(thumb, (fore_size - thumb_offset, 0))
-
- if self.focusable:
- rv.add_focus(self, None, 0, 0, width, height)
-
- return rv
-
-
- def focus(self, default=False):
- super(Bar, self).focus(default)
- self.set_transform_event("hover")
-
- if not default:
- run(self.hovered)
-
-
- def unfocus(self, default=False):
- super(Bar, self).unfocus()
- self.set_transform_event("idle")
-
- if not default:
- run_unhovered(self.hovered)
- run(self.unhovered)
-
- def event(self, ev, x, y, st):
-
- if not self.focusable:
- return None
-
- if not self.is_focused():
- return None
-
- if self.hidden:
- return None
-
- range = self.adjustment.range #@ReservedAssignment
- old_value = self.adjustment.value
- value = old_value
-
- vertical = self.style.bar_vertical
- invert = self.style.bar_invert ^ vertical
- if invert:
- value = range - value
-
- grabbed = (renpy.display.focus.get_grab() is self)
- just_grabbed = False
-
- if not grabbed and map_event(ev, "bar_activate"):
- renpy.display.focus.set_grab(self)
- just_grabbed = True
- grabbed = True
-
- if grabbed:
-
- if vertical:
- increase = "bar_down"
- decrease = "bar_up"
- else:
- increase = "bar_right"
- decrease = "bar_left"
-
- if map_event(ev, decrease):
- value -= self.adjustment.step
-
- if map_event(ev, increase):
- value += self.adjustment.step
-
- if ev.type in (pygame.MOUSEMOTION, pygame.MOUSEBUTTONUP, pygame.MOUSEBUTTONDOWN):
-
- if vertical:
-
- tgutter = self.style.fore_gutter
- bgutter = self.style.aft_gutter
- zone_height = self.height - tgutter - bgutter - self.thumb_dim
- if zone_height:
- value = (y - tgutter - self.thumb_dim / 2) * range / zone_height
- else:
- value = 0
-
- else:
- lgutter = self.style.fore_gutter
- rgutter = self.style.aft_gutter
- zone_width = self.width - lgutter - rgutter - self.thumb_dim
- if zone_width:
- value = (x - lgutter - self.thumb_dim / 2) * range / zone_width
- else:
- value = 0
-
- if isinstance(range, int):
- value = int(value)
-
- if value < 0:
- value = 0
-
- if value > range:
- value = range
-
- if invert:
- value = range - value
-
- if grabbed and not just_grabbed and map_event(ev, "bar_deactivate"):
- renpy.display.focus.set_grab(None)
-
- if value != old_value:
- return self.adjustment.change(value)
-
- return None
-
-
-class Conditional(renpy.display.layout.Container):
- """
- This class renders its child if and only if the condition is
- true. Otherwise, it renders nothing. (Well, a Null).
-
- Warning: the condition MUST NOT update the game state in any
- way, as that would break rollback.
- """
-
- def __init__(self, condition, *args, **properties):
- super(Conditional, self).__init__(*args, **properties)
-
- self.condition = condition
- self.null = renpy.display.layout.Null()
-
- self.state = eval(self.condition, vars(renpy.store))
-
- def render(self, width, height, st, at):
- if self.state:
- return render(self.child, width, height, st, at)
- else:
- return render(self.null, width, height, st, at)
-
- def event(self, ev, x, y, st):
-
- state = eval(self.condition, vars(renpy.store))
-
- if state != self.state:
- renpy.display.render.redraw(self, 0)
-
- self.state = state
-
- if state:
- return self.child.event(ev, x, y, st)
-
-
-class TimerState(renpy.python.RevertableObject):
- """
- Stores the state of the timer, which may need to be rolled back.
- """
-
- # Prevents us from having to worry about our initialization being
- # rolled back.
- started = False
- next_event = None
-
-class Timer(renpy.display.layout.Null):
-
- __version__ = 1
-
- started = False
-
- def after_upgrade(self, version):
- if version < 1:
- self.state = TimerState()
- self.state.started = self.started
- self.state.next_event = self.next_event
-
- def __init__(self, delay, action=None, repeat=False, args=(), kwargs={}, replaces=None, **properties):
- super(Timer, self).__init__(**properties)
-
- if action is None:
- raise Exception("A timer must have an action supplied.")
-
- if delay <= 0:
- raise Exception("A timer's delay must be > 0.")
-
- # The delay.
- self.delay = delay
-
- # Should we repeat the event?
- self.repeat = repeat
-
- # The time the next event should occur.
- self.next_event = None
-
- # The function and its arguments.
- self.function = action
- self.args = args
- self.kwargs = kwargs
-
- # Did we start the timer?
- self.started = False
-
- if replaces is not None:
- self.state = replaces.state
- else:
- self.state = TimerState()
-
-
- def event(self, ev, x, y, st):
-
- state = self.state
-
- if not state.started:
- state.started = True
- state.next_event = st + self.delay
-
- if state.next_event is None:
- return
-
- if st < state.next_event:
- renpy.game.interface.timeout(state.next_event - st)
- return
-
- if not self.repeat:
- state.next_event = None
- else:
- state.next_event = state.next_event + self.delay
- if state.next_event < st:
- state.next_event = st + self.delay
-
- renpy.game.interface.timeout(state.next_event - st)
-
- return run(self.function, *self.args, **self.kwargs)
-
-
-class MouseArea(renpy.display.core.Displayable):
-
- def __init__(self, hovered=None, unhovered=None, replaces=None, **properties):
- super(MouseArea, self).__init__(**properties)
-
- self.hovered = hovered
- self.unhovered = unhovered
-
- # Are we hovered right now?
- self.is_hovered = False
-
- if replaces is not None:
- self.is_hovered = replaces.is_hovered
-
- # Taken from the render.
- self.width = 0
- self.height = 0
-
-
- def render(self, width, height, st, at):
- self.width = width
- self.height = height
-
- return Render(width, height)
-
- def event(self, ev, x, y, st):
-
- if 0 <= x < self.width and 0 <= y < self.height:
- is_hovered = True
- else:
- is_hovered = False
-
- if is_hovered and not self.is_hovered:
- self.is_hovered = True
-
- return run(self.hovered)
-
- elif not is_hovered and self.is_hovered:
- self.is_hovered = False
-
- run_unhovered(self.hovered)
- run(self.unhovered)
-
-