diff options
Diffstat (limited to 'unrpyc/renpy/display/behavior.py')
-rw-r--r-- | unrpyc/renpy/display/behavior.py | 1531 |
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) - - |