CampBuddy/Camp.Buddy v2.2.1/Camp_Buddy-2.2.1-pc/renpy/text/extras.py
2025-03-03 23:00:33 +01:00

250 lines
6.8 KiB
Python

# Copyright 2004-2019 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.
# Other text-related things.
from __future__ import print_function
import renpy.text
from renpy.text.textsupport import TAG, PARAGRAPH
import renpy.text.textsupport as textsupport
# A list of text tags, mapping from the text tag prefix to if it
# requires a closing tag.
text_tags = dict(
alpha=True,
art=True,
image=False,
p=False,
w=False,
fast=False,
b=True,
i=True,
u=True,
a=True,
plain=True,
font=True,
color=True,
outlinecolor=True,
size=True,
nw=False,
s=True,
rt=True,
rb=True,
k=True,
cps=True,
space=False,
vspace=False
)
text_tags[""] = True
# This checks the text tags in a string to be sure they are all matched, and
# properly nested. It returns an error message, or None if the line is okay.
def check_text_tags(s):
"""
:doc: lint
Checks the text tags in s for correctness. Returns an error string if there is
an error, or None if there is no error.
"""
all_tags = dict(text_tags)
custom_tags = renpy.config.custom_text_tags
if custom_tags:
all_tags.update(custom_tags)
self_closing_custom_tags = renpy.config.self_closing_custom_text_tags
if self_closing_custom_tags:
all_tags.update(dict.fromkeys(self_closing_custom_tags, False))
try:
tokens = textsupport.tokenize(unicode(s))
except Exception as e:
return e.args[0]
tag_stack = [ ]
for type, text in tokens: # @ReservedAssignment
if type != TAG:
continue
if text[0] == "#":
continue
# Strip off arguments for tags.
if text.find('=') != -1:
text = text[:text.find('=')]
# Closing tag.
if text and text[0] == '/':
if not tag_stack:
return "Close text tag '%s' does not match an open text tag." % text
if tag_stack[-1] != text[1:]:
return "Close text tag '%s' does not match open text tag '%s'." % (text, tag_stack[-1])
tag_stack.pop()
continue
if text not in all_tags:
return "Text tag '%s' is not known." % text
if all_tags[text]:
tag_stack.append(text)
if tag_stack:
return "One or more text tags were left open at the end of the string: " + ", ".join([ "'" + i + "'" for i in tag_stack])
return None
def filter_text_tags(s, allow=None, deny=None):
"""
:doc: text_utility
Returns a copy of `s` with the text tags filtered. Exactly one of the `allow` and `deny` keyword
arguments must be given.
`allow`
A set of tags that are allowed. If a tag is not in this list, it is removed.
`deny`
A set of tags that are denied. If a tag is not in this list, it is kept in the string.
"""
if (allow is None) and (deny is None):
raise Exception("Only one of the allow and deny keyword arguments should be given to filter_text_tags.")
if (allow is not None) and (deny is not None):
raise Exception("Only one of the allow and deny keyword arguments should be given to filter_text_tags.")
tokens = textsupport.tokenize(unicode(s))
rv = [ ]
for tokentype, text in tokens:
if tokentype == PARAGRAPH:
rv.append("\n")
elif tokentype == TAG:
kind = text.partition("=")[0]
if kind and (kind[0] == "/"):
kind = kind[1:]
if allow is not None:
if kind in allow:
rv.append("{" + text + "}")
else:
if kind not in deny:
rv.append("{" + text + "}")
else:
rv.append(text)
return "".join(rv)
class ParameterizedText(object):
"""
:name: ParameterizedText
:doc: text
This is a displayable that can be shown with an additional string
parameter, which then shows that string as if it was an image.
This is usually used as part of the pre-defined ``text`` image.
For example, one can do::
show text "Hello, World" at truecenter
with dissolve
pause 1
hide text
with dissolve
You can use ParameterizedText directly to define similar images with
different style properties. For example, one can write::
image top_text = ParameterizedText(xalign=0.5, yalign=0.0)
"""
def __init__(self, style='default', **properties):
self.style = style
self.properties = properties
_duplicatable = True
def _duplicate(self, args):
if len(args.args) == 0:
raise Exception("'%s' takes a single string parameter." % ' '.join(args.name))
param = "".join(args.args)
string = renpy.python.py_eval(param)
return renpy.text.text.Text(string, style=self.style, **self.properties)
def textwrap(s, width=78, asian=False):
"""
Wraps the unicode string `s`, and returns a list of strings.
`width`
The number of half-width characters that fit on a line.
`asian`
True if we should make ambiguous width characters full-width, as is
done in Asian encodings.
"""
import unicodedata
glyphs = [ ]
for c in unicode(s):
eaw = unicodedata.east_asian_width(c)
if (eaw == "F") or (eaw =="W"):
gwidth = 20
elif (eaw == "A"):
if asian:
gwidth = 20
else:
gwidth = 10
else:
gwidth = 10
g = textsupport.Glyph()
g.character = ord(c)
g.ascent = 10
g.line_spacing = 10
g.width = gwidth
g.advance = gwidth
glyphs.append(g)
textsupport.annotate_unicode(glyphs, False, 2)
renpy.text.texwrap.linebreak_tex(glyphs, width * 10, width * 10, False)
return textsupport.linebreak_list(glyphs)