973 lines
28 KiB
Plaintext
973 lines
28 KiB
Plaintext
# Copyright 2004-2025 Tom Rothamel <pytom@bishoujo.us>
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person
|
|
# obtaining a copy of this software and associated documentation files
|
|
# (the "Software"), to deal in the Software without restriction,
|
|
# including without limitation the rights to use, copy, modify, merge,
|
|
# publish, distribute, sublicense, and/or sell copies of the Software,
|
|
# and to permit persons to whom the Software is furnished to do so,
|
|
# subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be
|
|
# included in all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
init -1500 python:
|
|
|
|
@renpy.pure
|
|
class InvertSelected(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
This inverts the selection state of the provided action, while
|
|
proxying over all of the other methods.
|
|
"""
|
|
|
|
def __init__(self, action):
|
|
self.action = action
|
|
|
|
try:
|
|
self.alt = action.alt
|
|
except Exception:
|
|
pass
|
|
|
|
def __call__(self):
|
|
return self.action.__call__()
|
|
|
|
def get_selected(self):
|
|
return not self.action.get_selected()
|
|
|
|
def get_sensitive(self):
|
|
return self.action.get_sensitive()
|
|
|
|
def periodic(self, st):
|
|
return self.action.periodic(st)
|
|
|
|
def predict(self):
|
|
self.action.predict()
|
|
|
|
@renpy.pure
|
|
def If(expression, true=None, false=None):
|
|
"""
|
|
:doc: other_action
|
|
|
|
This returns `true` if `expression` is true, and `false`
|
|
otherwise. Use this to select an action based on an expression.
|
|
Note that the default, None, can be used as an action that causes
|
|
a button to be disabled.
|
|
"""
|
|
|
|
if expression:
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
@renpy.pure
|
|
class SelectedIf(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
:args: (action, /)
|
|
|
|
This indicates that one action in a list of actions should be used
|
|
to determine if a button is selected. This only makes sense
|
|
when the button has a list of actions. For example::
|
|
|
|
# The button is selected only if mars_flag is True
|
|
textbutton "Marsopolis":
|
|
action [ SelectedIf(SetVariable("mars_flag", True)), SetVariable("on_mars", True) ]
|
|
|
|
The action inside SelectedIf is run normally when the button is clicked.
|
|
"""
|
|
|
|
# Note: This had been documented to take a boolean.
|
|
|
|
def __init__(self, expression):
|
|
self.expression = expression
|
|
|
|
if isinstance(expression, Action):
|
|
for i in ("get_selected", "get_sensitive", "get_tooltip", "periodic", "unhovered"):
|
|
setattr(self, i, getattr(expression, i, None))
|
|
|
|
def __call__(self):
|
|
if isinstance(self.expression, Action):
|
|
return self.expression()
|
|
return None
|
|
|
|
def get_selected(self):
|
|
return self.expression
|
|
|
|
@renpy.pure
|
|
class SensitiveIf(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
:args: (action, /)
|
|
|
|
This indicates that one action in a list of actions should be used
|
|
to determine if a button is sensitive. This only makes sense
|
|
when the button has a list of actions. For example::
|
|
|
|
# The button is sensitive only if mars_flag is True
|
|
textbutton "Marsopolis":
|
|
action [ SensitiveIf(SetVariable("mars_flag", True)), SetVariable("on_mars", True) ]
|
|
|
|
The action inside SensitiveIf is run normally when the button is clicked.
|
|
"""
|
|
|
|
# Note: This had been documented to take a boolean.
|
|
|
|
def __init__(self, expression):
|
|
self.expression = expression
|
|
|
|
if isinstance(expression, Action):
|
|
for i in ("get_selected", "get_sensitive", "get_tooltip", "periodic", "unhovered"):
|
|
setattr(self, i, getattr(expression, i, None))
|
|
|
|
def __call__(self):
|
|
if isinstance(self.expression, Action):
|
|
return self.expression()
|
|
return None
|
|
|
|
def get_sensitive(self):
|
|
return self.expression
|
|
|
|
@renpy.pure
|
|
class Screenshot(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Takes a screenshot.
|
|
"""
|
|
|
|
def __call__(self):
|
|
_screenshot()
|
|
|
|
@renpy.pure
|
|
class HideInterface(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Causes the interface to be hidden until the user clicks.
|
|
This is typically what happens when hitting the H key in a Ren'Py game.
|
|
"""
|
|
|
|
def __call__(self):
|
|
renpy.call_in_new_context("_hide_windows")
|
|
|
|
|
|
@renpy.pure
|
|
class OpenURL(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Causes `url` to be opened in a web browser.
|
|
"""
|
|
|
|
def __init__(self, url):
|
|
self.url = url
|
|
|
|
def __call__(self):
|
|
renpy.open_url(self.url)
|
|
|
|
class With(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Causes `transition` to occur.
|
|
"""
|
|
|
|
def __init__(self, transition):
|
|
self.transition = transition
|
|
|
|
def __call__(self):
|
|
renpy.transition(self.transition)
|
|
renpy.restart_interaction()
|
|
|
|
@renpy.pure
|
|
class Notify(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Displays `message` using :func:`renpy.notify`.
|
|
"""
|
|
|
|
def __init__(self, message):
|
|
self.message = message
|
|
|
|
def predict(self):
|
|
renpy.predict_screen("notify")
|
|
|
|
def __call__(self):
|
|
renpy.notify(self.message)
|
|
|
|
@renpy.pure
|
|
class Rollback(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
:args: (*args, force="menu", **kwargs)
|
|
|
|
This action causes a rollback to occur, when a rollback is possible.
|
|
Otherwise, nothing happens.
|
|
|
|
The arguments are given to :func:`renpy.rollback`. This includes the
|
|
`force` argument which here defaults to "menu".
|
|
"""
|
|
|
|
args = tuple()
|
|
kwargs = { "force" : "menu" }
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.args = args
|
|
kwargs.setdefault("force", "menu")
|
|
self.kwargs = kwargs
|
|
|
|
def __call__(self):
|
|
renpy.rollback(*self.args, **self.kwargs)
|
|
|
|
def get_sensitive(self):
|
|
return renpy.can_rollback()
|
|
|
|
class RollbackToIdentifier(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
This causes a rollback to an identifier to occur. Rollback
|
|
identifiers are returned as part of HistoryEntry objects.
|
|
"""
|
|
|
|
def __init__(self, identifier):
|
|
self.identifier = identifier
|
|
|
|
def __call__(self):
|
|
checkpoints = renpy.get_identifier_checkpoints(self.identifier)
|
|
|
|
if checkpoints is not None:
|
|
renpy.rollback(checkpoints=checkpoints, force="menu")
|
|
|
|
def get_sensitive(self):
|
|
return (renpy.get_identifier_checkpoints(self.identifier) is not None)
|
|
|
|
@renpy.pure
|
|
class RestartStatement(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
This action causes Ren'Py to rollback to before the current
|
|
statement, and then re-run the current statement. This may be used
|
|
when changing a persistent variable that affects how the statement
|
|
is displayed.
|
|
|
|
If run in a menu context, this waits until the player exits to a
|
|
top-level context before performing the rollback.
|
|
"""
|
|
|
|
def __call__(self):
|
|
renpy.rollback(force=True, checkpoints=0, defer=True)
|
|
|
|
@renpy.pure
|
|
class RollForward(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
This action causes a rollforward to occur, if a roll forward is
|
|
possible. Otherwise, it is insensitive.
|
|
"""
|
|
|
|
def __call__(self):
|
|
return renpy.exports.roll_forward_core()
|
|
|
|
def get_sensitive(self):
|
|
return renpy.roll_forward_info() is not None
|
|
|
|
|
|
#########################################################################
|
|
|
|
def GetTooltip(screen=None, last=False):
|
|
"""
|
|
:doc: get_tooltip
|
|
|
|
Returns the tooltip of the currently focused displayable, or None
|
|
if no displayable is focused.
|
|
|
|
`screen`
|
|
If not None, this should be the name or tag of a screen. If
|
|
given, this function only returns the tooltip if the focused
|
|
displayable is part of the screen.
|
|
|
|
`last`
|
|
If true, returns the last non-None value this function would
|
|
have returned.
|
|
"""
|
|
|
|
return renpy.display.focus.get_tooltip(screen, last)
|
|
|
|
|
|
class __TooltipAction(Action, FieldEquality):
|
|
|
|
identity_fields = [ "tooltip", "value" ]
|
|
|
|
def __init__(self, tooltip, value):
|
|
self.tooltip = tooltip
|
|
self.value = value
|
|
|
|
def __call__(self):
|
|
if self.tooltip.value != self.value:
|
|
self.tooltip.value = self.value
|
|
renpy.restart_interaction()
|
|
|
|
def unhovered(self):
|
|
if self.tooltip.value != self.tooltip.default:
|
|
self.tooltip.value = self.tooltip.default
|
|
renpy.restart_interaction()
|
|
|
|
_m1_00screen__TooltipAction = __TooltipAction
|
|
|
|
|
|
class Tooltip(object):
|
|
"""
|
|
:doc: tooltips class
|
|
|
|
A tooltip object can be used to define a portion of a screen that is
|
|
updated when the mouse hovers an area.
|
|
|
|
A tooltip object has a ``value`` field, which is set to the `default`
|
|
value passed to the constructor when the tooltip is created. When
|
|
a button using an action created by the tooltip is hovered, the
|
|
value field changes to the value associated with the action.
|
|
"""
|
|
|
|
def __init__(self, default):
|
|
self.value = default
|
|
self.default = default
|
|
|
|
def Action(self, value):
|
|
"""
|
|
:doc: tooltips method
|
|
:name: Action
|
|
|
|
Returns an action that is generally used as the hovered property
|
|
of a button. When the button is hovered, the value field of this
|
|
tooltip is set to `value`. When the button loses focus, the
|
|
value field of this tooltip reverts to the default.
|
|
"""
|
|
|
|
return __TooltipAction(self, value)
|
|
|
|
action = Action
|
|
|
|
|
|
#########################################################################
|
|
|
|
@renpy.pure
|
|
class Language(Action, DictEquality):
|
|
"""
|
|
:doc: language_action
|
|
|
|
Changes the language of the game to `language`.
|
|
|
|
`language`
|
|
A string giving the language to translate to, or None to use
|
|
the default language of the game script.
|
|
"""
|
|
|
|
alt = _("Language [text]")
|
|
|
|
def __init__(self, language):
|
|
self.language = language
|
|
|
|
def __call__(self):
|
|
renpy.change_language(self.language)
|
|
|
|
def get_selected(self):
|
|
return _preferences.language == self.language
|
|
|
|
def get_sensitive(self):
|
|
if self.language is None:
|
|
return True
|
|
|
|
return self.language in renpy.known_languages()
|
|
|
|
|
|
#########################################################################
|
|
|
|
# Transitions used when entering and leaving replays.
|
|
config.enter_replay_transition = None
|
|
config.exit_replay_transition = None
|
|
|
|
@renpy.pure
|
|
class Replay(Action, DictEquality):
|
|
"""
|
|
:doc: replay
|
|
|
|
An action that starts `label` as a replay.
|
|
|
|
`scope`
|
|
A dictionary mapping variable name to value. These variables are set
|
|
when entering the replay.
|
|
|
|
`locked`
|
|
If true, this action is insensitive and will not do anything when triggered.
|
|
If false, it will behave normally. If None, it will be locked if the label
|
|
has not been seen in any playthrough.
|
|
"""
|
|
|
|
def __init__(self, label, scope={}, locked=None):
|
|
self.label = label
|
|
self.scope = scope
|
|
self.locked = locked
|
|
|
|
def __call__(self):
|
|
|
|
if not self.get_sensitive():
|
|
return
|
|
|
|
if config.enter_replay_transition:
|
|
renpy.transition(config.enter_replay_transition)
|
|
|
|
renpy.call_replay(self.label, self.scope)
|
|
|
|
if config.exit_replay_transition:
|
|
renpy.transition(config.exit_replay_transition)
|
|
|
|
def get_sensitive(self):
|
|
if self.locked is not None:
|
|
return not self.locked
|
|
|
|
return renpy.seen_label(self.label)
|
|
|
|
@renpy.pure
|
|
class EndReplay(Action, DictEquality):
|
|
"""
|
|
:doc: replay
|
|
|
|
Ends the current replay.
|
|
|
|
`confirm`
|
|
If true, prompts the user for confirmation before ending the
|
|
replay.
|
|
"""
|
|
def __init__(self, confirm=True):
|
|
self.confirm = confirm
|
|
|
|
def __call__(self):
|
|
|
|
if not self.get_sensitive():
|
|
return
|
|
|
|
if self.confirm:
|
|
layout.yesno_screen(layout.END_REPLAY, EndReplay(False))
|
|
else:
|
|
renpy.end_replay()
|
|
|
|
def get_sensitive(self):
|
|
return _in_replay
|
|
|
|
@renpy.pure
|
|
class MouseMove(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Move the mouse pointer to `x`, `y`. If the device does not have a mouse
|
|
pointer, if it is not possible for Ren'Py to move that pointer,
|
|
or if the :var:`"automatic move" preference <preferences.mouse_move>`
|
|
is False, this does nothing.
|
|
|
|
`duration`
|
|
The time it will take to perform the move, in seconds. During
|
|
this time, the mouse may be unresponsive.
|
|
"""
|
|
def __init__(self, x, y, duration=0):
|
|
self.x = x
|
|
self.y = y
|
|
self.duration = duration
|
|
|
|
def __call__(self):
|
|
if _preferences.mouse_move:
|
|
renpy.set_mouse_pos(self.x, self.y, self.duration)
|
|
|
|
|
|
@renpy.pure
|
|
class QueueEvent(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Queues the given event using :func:`renpy.queue_event`.
|
|
"""
|
|
|
|
def __init__(self, event, up=False):
|
|
self.event = event
|
|
self.up = up
|
|
|
|
def __call__(self):
|
|
renpy.queue_event(self.event, up=self.up)
|
|
|
|
@renpy.pure
|
|
class Function(Action):
|
|
"""
|
|
:doc: other_action
|
|
:args: (callable, *args, _update_screens=True, **kwargs)
|
|
|
|
This Action calls ``callable(*args, **kwargs)``.
|
|
|
|
`callable`
|
|
Callable object. This assumes that if two callables compare
|
|
equal, calling either one will be equivalent.
|
|
|
|
`args`
|
|
positional arguments to be passed to `callable`.
|
|
|
|
`kwargs`
|
|
keyword arguments to be passed to `callable`.
|
|
|
|
`_update_screens`
|
|
When true, the interaction restarts and the screens are updated
|
|
after the function returns.
|
|
|
|
If the function returns a non-None value, the interaction stops and
|
|
returns that value. (When called using the call screen statement, the
|
|
result is placed in the `_return` variable.)
|
|
|
|
Instead of using a Function action, you can define your own subclass
|
|
of the :class:`Action` class. This lets you name the action, and
|
|
determine when it should be selected and sensitive.
|
|
"""
|
|
|
|
update_screens = True
|
|
|
|
def __eq__(self, other):
|
|
if type(self) is not type(other):
|
|
return False
|
|
|
|
if PY2:
|
|
if self.callable is not other.callable:
|
|
return False
|
|
else:
|
|
if self.callable != other.callable:
|
|
return False
|
|
|
|
if self.args != other.args:
|
|
return False
|
|
|
|
if self.kwargs != other.kwargs:
|
|
return False
|
|
|
|
for a, b in zip(self.args, other.args):
|
|
if a is not b:
|
|
return False
|
|
|
|
for k in self.kwargs:
|
|
if self.kwargs[k] is not other.kwargs[k]:
|
|
return False
|
|
|
|
if self.update_screens != other.update_screens:
|
|
return False
|
|
|
|
return True
|
|
|
|
def __init__(self, callable, *args, **kwargs):
|
|
self.callable = callable
|
|
self.args = args
|
|
|
|
self.update_screens = kwargs.pop("_update_screens", True)
|
|
|
|
self.kwargs = kwargs
|
|
|
|
def __call__(self):
|
|
rv = self.callable(*self.args, **self.kwargs)
|
|
|
|
if self.update_screens:
|
|
renpy.restart_interaction()
|
|
|
|
return rv
|
|
|
|
@renpy.pure
|
|
class Confirm(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Prompts the user for confirmation of an action. If the user
|
|
clicks yes, the yes action is performed. Otherwise, the `no`
|
|
action is performed.
|
|
|
|
`prompt`
|
|
The prompt to display to the user.
|
|
|
|
`confirm_selected`
|
|
If true, the prompt will be displayed even if the `yes` action
|
|
is already selected. If false (the default), the prompt
|
|
will not be displayed if the `yes` action is selected.
|
|
|
|
The sensitivity and selectedness of this action match those
|
|
of the `yes` action.
|
|
|
|
See :func:`renpy.confirm` for a function version of this action.
|
|
"""
|
|
|
|
|
|
def __init__(self, prompt, yes, no=None, confirm_selected=False):
|
|
self.prompt = prompt
|
|
self.yes = yes
|
|
self.no = no
|
|
self.confirm_selected = confirm_selected
|
|
|
|
def __call__(self):
|
|
if self.get_selected() and not self.confirm_selected:
|
|
return renpy.run(self.yes)
|
|
|
|
return layout.yesno_screen(self.prompt, self.yes, self.no)
|
|
|
|
def get_sensitive(self):
|
|
if self.yes is None:
|
|
return False
|
|
|
|
return renpy.is_sensitive(self.yes)
|
|
|
|
def get_selected(self):
|
|
return renpy.is_selected(self.yes)
|
|
|
|
def get_tooltip(self):
|
|
return renpy.display.behavior.get_tooltip(self.yes)
|
|
|
|
@renpy.pure
|
|
class Scroll(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Causes a Bar, Viewport, or Vpgrid to scroll.
|
|
|
|
`id`
|
|
The id of a bar, viewport, or vpgrid in the current screen.
|
|
|
|
`direction`
|
|
For a vbar, one of "increase" or "decrease". For a viewport
|
|
or vpgrid, one of "horizontal increase", "vertical increase",
|
|
"horizontal decrease", or "vertical decrease".
|
|
|
|
`amount`
|
|
The amount to scroll by. This can be a number of pixels, or
|
|
else "step" or "page".
|
|
|
|
`delay`
|
|
If non-zero, the scroll will be animated for this many seconds.
|
|
"""
|
|
|
|
delay = 0.0
|
|
|
|
def __init__(self, id, direction, amount="step", delay=0.0):
|
|
self.id = id
|
|
self.direction = direction
|
|
self.amount = amount
|
|
self.delay = delay
|
|
|
|
|
|
def get_adjustment_and_delta(self):
|
|
|
|
d = renpy.get_widget(None, self.id)
|
|
if d is None:
|
|
return None, +1
|
|
|
|
if self.direction == "increase":
|
|
delta = +1
|
|
adjustment = d.adjustment
|
|
elif self.direction == "decrease":
|
|
delta = -1
|
|
adjustment = d.adjustment
|
|
elif self.direction == "horizontal increase":
|
|
delta = +1
|
|
adjustment = d.xadjustment
|
|
elif self.direction == "horizontal decrease":
|
|
delta = -1
|
|
adjustment = d.xadjustment
|
|
elif self.direction == "vertical increase":
|
|
delta = +1
|
|
adjustment = d.yadjustment
|
|
elif self.direction == "vertical decrease":
|
|
delta = -1
|
|
adjustment = d.yadjustment
|
|
else:
|
|
raise Exception("Unknown scroll direction: {}".format(self.direction))
|
|
|
|
return adjustment, delta
|
|
|
|
def get_sensitive(self):
|
|
|
|
adjustment, delta = self.get_adjustment_and_delta()
|
|
|
|
|
|
if adjustment is None:
|
|
return False
|
|
|
|
adjustment.restart_interaction_at_limit = True
|
|
adjustment.restart_interaction_at_range = True
|
|
|
|
if delta > 0:
|
|
return adjustment.value < adjustment.range
|
|
else:
|
|
return adjustment.value > 0
|
|
|
|
def __call__(self):
|
|
|
|
adjustment, delta = self.get_adjustment_and_delta()
|
|
|
|
if adjustment is None:
|
|
raise Exception("There is no displayable with the id {}.".format(self.id))
|
|
|
|
if self.amount == "step":
|
|
amount = delta * adjustment.step
|
|
elif self.amount == "page":
|
|
amount = delta * adjustment.page
|
|
else:
|
|
amount = absolute.compute_raw(delta*self.amount, adjustment.range)
|
|
|
|
if self.delay == 0.0:
|
|
adjustment.change(adjustment.value + amount)
|
|
else:
|
|
adjustment.animate(amount, self.delay, _warper.ease)
|
|
|
|
|
|
@renpy.pure
|
|
class OpenDirectory(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
:args: (directory)
|
|
|
|
Opens `directory` in a file browser. `directory` is relative to
|
|
:var:`config.basedir`.
|
|
"""
|
|
|
|
alt = _("Open [text] directory.")
|
|
|
|
def __init__(self, directory, absolute=False):
|
|
import os
|
|
|
|
if absolute:
|
|
self.directory = directory
|
|
else:
|
|
self.directory = os.path.join(config.basedir, directory)
|
|
|
|
def get_sensitive(self):
|
|
import os
|
|
|
|
return os.path.exists(self.directory)
|
|
|
|
def __call__(self):
|
|
import os
|
|
import subprocess
|
|
|
|
try:
|
|
directory = renpy.fsencode(self.directory)
|
|
|
|
if renpy.windows:
|
|
os.startfile(directory)
|
|
elif renpy.macintosh:
|
|
subprocess.Popen([ "open", directory ])
|
|
else:
|
|
subprocess.Popen([ "xdg-open", directory ])
|
|
|
|
except Exception:
|
|
pass
|
|
|
|
@renpy.pure
|
|
class CaptureFocus(Action, DictEquality):
|
|
"""
|
|
:doc: focus_action
|
|
|
|
If a displayable is focused when this action is run, the rectangle
|
|
containing that displayable is stored with the name `name`. This
|
|
rectangle can then be retrieved with the :func:`GetFocusRect` action,
|
|
or the `focus` property of the :ref:`sl-nearrect` displayable.
|
|
|
|
If no displayable is focused, the previous capture with that name
|
|
is removed.
|
|
|
|
`name`
|
|
The name of the focus rectangle to store. This should be a string.
|
|
The name "tooltip" is special, as it is automatically captured
|
|
when the tooltip is changed.
|
|
"""
|
|
|
|
def __init__(self, name="default"):
|
|
self.name = name
|
|
|
|
def __call__(self):
|
|
renpy.capture_focus(self.name)
|
|
renpy.restart_interaction()
|
|
|
|
@renpy.pure
|
|
class ToggleFocus(Action, DictEquality):
|
|
"""
|
|
:doc: focus_action
|
|
|
|
If the focus rectangle exists, clears it, otherwise captures it.
|
|
|
|
`name`
|
|
The name of the focus rectangle to store. This should be a string.
|
|
The name "tooltip" is special, as it is automatically captured
|
|
when the tooltip is changed.
|
|
"""
|
|
|
|
def __init__(self, name="default"):
|
|
self.name = name
|
|
|
|
def __call__(self):
|
|
name = self.name
|
|
|
|
if renpy.get_focus_rect(name) is not None:
|
|
renpy.clear_capture_focus(name)
|
|
|
|
else:
|
|
renpy.capture_focus(name)
|
|
|
|
renpy.restart_interaction()
|
|
|
|
@renpy.pure
|
|
class ClearFocus(Action, DictEquality):
|
|
"""
|
|
:doc: focus_action
|
|
|
|
Clears a stored focus rectangle captured with :func:`CaptureFocus`.
|
|
If `name` is None, all focus rectangles are cleared.
|
|
"""
|
|
|
|
def __init__(self, name="default"):
|
|
self.name = name
|
|
|
|
def __call__(self):
|
|
renpy.clear_capture_focus(self.name)
|
|
renpy.restart_interaction()
|
|
|
|
def GetFocusRect(name="default"):
|
|
"""
|
|
:doc: focus_action
|
|
|
|
If a focus rectangle with the given name has been stored (either with
|
|
:func:`CaptureFocus`, or automatically by a tooltip, returns the
|
|
a (x, y, h, w) rectangle. Otherwise, returns None.
|
|
|
|
`name`
|
|
The name of the focus rectangle to retrieve. The name "tooltip"
|
|
is special, as it is automatically captured when the tooltip is
|
|
changed.
|
|
"""
|
|
|
|
return renpy.get_focus_rect(name)
|
|
|
|
@renpy.pure
|
|
class ExecJS(Action, DictEquality):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Executes the given JavaScript source code. This is only supported on
|
|
the web, and will raise an exception on other platforms. The script
|
|
is executed asynchronously in the window context, and the return value
|
|
is not available.
|
|
|
|
`code`
|
|
The JavaScript code to execute.
|
|
"""
|
|
|
|
def __init__(self, code):
|
|
self.code = code
|
|
|
|
def __call__(self):
|
|
if not renpy.emscripten:
|
|
raise Exception("ExecJS is only supported on the web.")
|
|
|
|
import emscripten
|
|
emscripten.run_script(self.code)
|
|
|
|
def CurrentScreenName():
|
|
"""
|
|
:doc: other_screen_function
|
|
|
|
Returns the name of the current screen, or None if there is no
|
|
current screen. In the case of a screen including by the use
|
|
screen, this returns the name of the screen that is doing the
|
|
including, not the name of the screen being included.
|
|
"""
|
|
|
|
current = renpy.current_screen()
|
|
if current is None:
|
|
return None
|
|
|
|
return current.screen_name[0]
|
|
|
|
@renpy.pure
|
|
class CopyToClipboard(Action):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Copies the string `s` to the system clipboard, if possible. This
|
|
should work on desktop and mobile platforms, but will not work
|
|
on the web.
|
|
"""
|
|
|
|
def __init__(self, s):
|
|
self.s = s
|
|
|
|
def __call__(self):
|
|
import pygame.scrap
|
|
pygame.scrap.put(pygame.SCRAP_TEXT, self.s.encode("utf-8"))
|
|
|
|
@renpy.pure
|
|
class EditFile(Action):
|
|
"""
|
|
:doc: other_action
|
|
|
|
Requests Ren'Py to open the given file in a text editor, if possible.
|
|
This will work on some platforms but not others.
|
|
|
|
`filename`
|
|
If given, the filename to open. If None, the current filename
|
|
and line number are used, with `line` being ignored.
|
|
|
|
`line`
|
|
The line number to open the file at.
|
|
"""
|
|
|
|
def __init__(self, filename=None, line=1):
|
|
self.filename = filename
|
|
self.line = line
|
|
|
|
def __call__(self):
|
|
|
|
filename = self.filename
|
|
line = self.line
|
|
|
|
if filename is None:
|
|
filename, line = renpy.get_filename_line()
|
|
|
|
try:
|
|
renpy.launch_editor([ filename ], line)
|
|
except Exception:
|
|
pass
|
|
|
|
init -1500:
|
|
|
|
transform _notify_transform:
|
|
# These control the position.
|
|
xalign .02 yalign .015
|
|
|
|
# These control the actions on show and hide.
|
|
on show:
|
|
alpha 0
|
|
linear .25 alpha 1.0
|
|
on hide:
|
|
linear .5 alpha 0.0
|
|
|
|
screen notify:
|
|
layer config.interface_layer
|
|
zorder 100
|
|
|
|
text "[message!tq]" at _notify_transform
|
|
|
|
# This controls how long it takes between when the screen is
|
|
# first shown, and when it begins hiding.
|
|
timer 3.25 action Hide('notify')
|