Compare commits

...

27 Commits

Author SHA1 Message Date
Tom Rothamel 71ba444e62 6.11.0e. 2010-07-18 10:39:09 -04:00
Tom Rothamel 3e0baee463 Update documentation. 2010-07-17 22:44:53 -04:00
Tom Rothamel a0064f5511 Disable OpenGL in launcher. 2010-07-17 22:37:01 -04:00
Tom Rothamel e7ce23f377 Fix potential video race. 2010-07-17 22:35:11 -04:00
Tom Rothamel 9c6d93968c Stop defining default in terms of other transforms, to allow those
transforms to be re-defined.
2010-07-17 22:00:21 -04:00
Tom Rothamel e4b29d58f4 Include indentation in text size. 2010-07-17 17:38:44 -04:00
Tom Rothamel a48b87a0d6 Fixed a bug that could cause ATL transforms to over-compute changes,
this leading to problems when used in parallel
2010-07-17 16:17:26 -04:00
Tom Rothamel 763515a937 Add GL Performance test. 2010-07-17 14:02:00 -04:00
Tom Rothamel 46a8242e51 Make sure that lexer revert also reverts the line. 2010-07-17 12:59:18 -04:00
Tom Rothamel efa8d66d3d Make placement of developer menu more friendly. 2010-07-15 23:28:37 -04:00
Tom Rothamel b7c71bb3b8 Work better with broken fonts. 2010-07-15 22:36:05 -04:00
Tom Rothamel aca5438b5a Use shift to disable OpenGL. Add deinit to swdraw. 2010-07-15 17:15:54 -04:00
Tom Rothamel e7eb23ab5e Create layout.yesno_screen function.
Doc update.

Bump to 6.11.0d.
2010-07-14 21:47:46 -04:00
Tom Rothamel 05dd8bfcc7 Use "screen" as the screen type and mouse for screens. 2010-07-14 20:39:30 -04:00
Tom Rothamel 2c299ab079 Share code between fullscreen and displayable versions of video playback. 2010-07-14 19:00:33 -04:00
Tom Rothamel 62acff5c75 CTRL on startup aborts OpenGL mode. 2010-07-14 01:22:40 -04:00
Tom Rothamel 316d146893 Make imagedissolve use the correct texture units. 2010-07-13 22:28:41 -04:00
Tom Rothamel e69fee2108 Auto-vivification of styles.
New styles.
2010-07-13 01:09:14 -04:00
Tom Rothamel 8fe6e1cf20 Add group argument to ui functions. 2010-07-13 00:27:48 -04:00
Tom Rothamel 6fcf7dbbba Blacklist Mesa Indirect GLX renderer. 2010-07-12 21:13:32 -04:00
Tom Rothamel f55c5f0ce5 Make screen language automatically prefix unicode-containing strings with u"" - like we do for other strings. 2010-07-12 20:42:32 -04:00
Tom Rothamel aaf8369421 Deallocate textures on shutdown. 2010-07-12 20:40:41 -04:00
Tom Rothamel 8e26c7730c Finish has rename.
Fix bugs with screens.
2010-07-11 22:46:19 -04:00
Tom Rothamel 556ca0611a Add has statement. 2010-07-11 17:25:46 -04:00
Tom Rothamel e2e78c175b Tweak the parser so that it recognizes \$ as a word unto itself. 2010-07-11 15:14:44 -04:00
Tom Rothamel 7b8033e6b2 A reference loop was preventing the weakref-based way of dealing with
PyCode from working. So instead, manually control when PyCodes are
recorded.
2010-07-11 13:04:44 -04:00
Tom Rothamel d602645fee Use button_text rather than default as the default button text style. 2010-07-11 11:57:06 -04:00
42 changed files with 854 additions and 310 deletions
+2 -2
View File
@@ -35,8 +35,8 @@ init -1110:
xpos 1.0 xanchor 0.0 ypos 1.0 yanchor 1.0
transform default:
reset
center
alpha 1 rotate None zoom 1 xzoom 1 yzoom 1 align (0, 0) alignaround (0, 0) subpixel False size None crop None
xpos 0.5 xanchor 0.5 ypos 1.0 yanchor 1.0
python:
config.default_transform = default
+79
View File
@@ -0,0 +1,79 @@
# Copyright 2004-2010 PyTom <pytom@bishoujo.us>
# See LICENSE.txt for license details.
# This file contains code to perform the OpenGL test. This is always
# run - even in software mode - so that the user experience remains
# consistent. (But it terminates early in sw-mode.)
init -1024 python:
# The image that we fill the screen with in GL-test mode.
config.gl_test_image = "black"
class __GLTest(renpy.Displayable):
"""
This counts the number of times it's been rendered, and
the number of seconds it's been displayed, and uses them
to make the decisions as to if OpenGL is working or not.
"""
def __init__(self, frames, timeout):
super(__GLTest, self).__init__()
self.frames = frames
self.timeout = timeout
def render(self, width, height, st, at):
self.frames -= 1
if self.frames <= 0:
renpy.timeout(0)
renpy.redraw(self, 0)
rv = renpy.Render(width, height)
return rv
def event(self, ev, x, y, st):
st = st
if self.frames <= 0:
return True
if st > self.timeout:
return False
renpy.timeout(self.timeout - st)
label _gl_test:
# Show the test image.
show expression config.gl_test_image
python hide:
# If GL is able to render FRAMES in DELAY seconds, we consider it to
# be operational, and continue in GL mode. Otherwise, we rever to
# software rendering mode.
FRAMES = 4
DELAY = .25
import os
if (not "RENPY_RENDERER" in os.environ) and (renpy.get_renderer_info()["renderer"] == "gl"):
renpy.pause(0)
renpy.transition(Dissolve(DELAY))
ui.add(__GLTest(FRAMES, DELAY))
rv = ui.interact(suppress_overlay=True, suppress_underlay=False)
if not rv:
config.gl_enable = False
renpy.display_reset()
# Hide the test image.
scene
return
+44 -1
View File
@@ -386,5 +386,48 @@ init -1105 python hide:
layout.QUIT = u"Are you sure you want to quit?"
layout.MAIN_MENU = u"Are you sure you want to return to the main menu?\nThis will lose unsaved progress."
@layout
def yesno_screen(message, yes=None, no=None):
"""
:doc: other
This causes the a yes/no prompt screen with the given message
to be displayed. The screen will be hidden when the user hits
yes or no.
`message`
The message that will be displayed.
`yes`
An action that is run when the user chooses yes.
`no`
An action that is run when the user chooses no.
"""
if renpy.has_screen("yesno_prompt"):
yes_action = [ Hide("yesno_prompt") ]
no_action = [ Hide("yesno_prompt") ]
if yes is not None:
yes_action.append(yes)
if no is not None:
no_action.append(no)
renpy.display.show_screen(
"yesno_prompt",
message=message,
yes_action=yes_action,
no_action=no_action)
return
if renpy.invoke_in_new_context(layout.yesno_prompt, None, message):
if yes is not None:
yes()
else:
if no is not None:
no()
+7 -4
View File
@@ -562,7 +562,7 @@ label _enter_menu:
renpy.context()._menu = True
# This may be changed, if we are already in the main menu.
renpy.context().main_menu = False
renpy.context()._main_menu = False
renpy.context_dynamic("main_menu")
renpy.context_dynamic("_window_subtitle")
renpy.context_dynamic("_window")
@@ -651,7 +651,7 @@ label _noisy_return:
# Return to the game.
label _return:
if renpy.context().main_menu:
if renpy.context()._main_menu:
$ renpy.transition(config.game_main_transition)
jump _main_menu_screen
@@ -685,6 +685,7 @@ init -1180 python hide:
# after_load.
label _after_load:
$ renpy.context()._menu = False
$ renpy.context()._main_menu = False
if config.after_load_transition:
$ renpy.transition(config.after_load_transition, force=True)
@@ -705,7 +706,9 @@ label _start:
for i in config.start_callbacks:
i()
call _gl_test
call _load_reload_game from _call__load_reload_game_1
if not _restart and config.auto_load and renpy.can_load(config.auto_load):
@@ -777,7 +780,7 @@ label _main_menu(_main_menu_screen="_main_menu_screen"):
renpy.dynamic("_load_prompt")
_load_prompt = False
renpy.context().main_menu = True
renpy.context()._main_menu = True
store.main_menu = True
jump expression _main_menu_screen
+6 -30
View File
@@ -2,30 +2,6 @@
init -1140 python:
def __yesno_prompt(message, yes=None, no=None):
if renpy.has_screen("yesno_prompt"):
yes_action = [ Hide("yesno_prompt") ]
no_action = [ Hide("yesno_prompt") ]
if yes is not None:
yes_action.append(yes)
if no is not None:
no_action.append(no)
renpy.display.show_screen(
"yesno_prompt",
message=message,
yes_action=yes_action,
no_action=no_action)
if renpy.invoke_in_new_context(layout.yesno_prompt, None, message):
if yes is not None:
yes()
else:
if no is not None:
no()
class Return(Action):
"""
:doc: control_action
@@ -262,7 +238,7 @@ init -1140 python:
return
if self.confirm:
__yesno_prompt(layout.MAIN_MENU, MainMenu(False))
layout.yesno_screen(layout.MAIN_MENU, MainMenu(False))
else:
renpy.full_restart()
@@ -283,12 +259,12 @@ init -1140 python:
"""
def __init__(self, confirm=True):
self.confirm = True
self.confirm = confirm
def __call__(self):
if self.confirm:
__yesno_prompt(layout.QUIT, Quit(False))
layout.yesno_screen(layout.QUIT, Quit(False))
else:
renpy.quit()
@@ -914,7 +890,7 @@ init -1140 python:
if renpy.scan_saved_game(fn):
if self.confirm:
__yesno_prompt(layout.OVERWRITE_SAVE, FileSave(self.name, False, self.newest, self.page))
layout.yesno_screen(layout.OVERWRITE_SAVE, FileSave(self.name, False, self.newest, self.page))
return
renpy.save(fn, extra_info=save_name)
@@ -959,7 +935,7 @@ init -1140 python:
if not renpy.context()._main_menu:
if self.confirm:
__yesno_prompt(layout.LOADING, FileLoad(self.name, False, self.page))
layout.yesno_screen(layout.LOADING, FileLoad(self.name, False, self.page))
return
renpy.load(fn)
@@ -993,7 +969,7 @@ init -1140 python:
fn = __filename(self.name, self.page)
if self.confirm:
__yesno_prompt(layout.DELETE_SAVE, FileDelete(self.name, False, self.page))
layout.yesno_screen(layout.DELETE_SAVE, FileDelete(self.name, False, self.page))
return
renpy.unlink_save(fn)
+8 -3
View File
@@ -22,10 +22,14 @@ init -1200 python hide:
# Style Declarations #################################################
style.default = Style(None, help='root of style hierarchy')
style.text = Style(style.default, help='style of text')
style.fixed = Style(style.default, help='fixed layouts')
style.hbox = Style(style.default, help='horizontal boxes')
style.vbox = Style(style.default, help='vertical boxes')
style.grid = Style(style.default, help='grid layouts')
style.side = Style(style.default, help='side layouts')
style.window = Style(style.default, help='windows created with ui.window')
style.image_placement = Style(style.default, help='default placement of images on the screen')
@@ -50,7 +54,8 @@ init -1200 python hide:
style.menu_choice_chosen_button = Style(style.menu_choice_button, help='buttons containing chosen in-game menu choices')
style.menu_window = Style(style.window, help='a window containing a menu')
style.input_text = Style(style.default, help='text of an input box')
style.input = Style(style.default, help='style of an input control')
style.input_text = Style(style.input, help='text of an input box')
style.input_prompt = Style(style.default, help='prompt of an input box')
style.input_window = Style(style.window, help='window of an input box')
@@ -235,7 +240,7 @@ init -1090 python:
# Menus.
style.menu_choice.idle_color = "#0ff"
style.menu_choice.hover_color = "#ff0"
style.input_text.color = "#ff0"
style.input.color = "#ff0"
# Styles used by centered.
style.centered_window.xalign = 0.5
+2 -2
View File
@@ -8,7 +8,7 @@ label _developer_screen:
ui.window(style=style.gm_root)
ui.null()
ui.frame(xpos=10, ypos=10, style=style.menu_frame)
ui.frame(xalign=.025, yalign=.05, style=style.menu_frame)
ui.vbox(box_first_spacing=10)
layout.label(u"Developer Menu", None)
@@ -92,7 +92,7 @@ label _theme_test:
return ""
toggle_var = True
adj = ui.adjustment(100, 25, page=25)
adj = ui.adjustment(100, 25, page=25, adjustable=True)
while True:
+3
View File
@@ -100,6 +100,9 @@ init -1 python hide:
## Set this to False if the game does not have any sound effects.
config.sound = False
# Disable opengl.
config.gl_enable = False
python early:
config.save_directory = "launcher-2"
+1 -1
View File
@@ -27,7 +27,7 @@
# ***** ***** ***** ***** ***** ***** **** ***** ***** ***** *****
# Be sure to change script_version in launcher/script_version.rpy, too!
# Also check to see if we have to update renpy.py.
version = "Ren'Py 6.11.0c"
version = "Ren'Py 6.11.0e"
script_version = 5003000
savegame_suffix = "-LT1.save"
+6 -5
View File
@@ -29,7 +29,6 @@
import renpy
import re
import time
import weakref
# Called to set the state of a Node, when necessary.
def setstate(node, state):
@@ -103,7 +102,6 @@ class PyCode(object):
'location',
'mode',
'bytecode',
'__weakref__',
]
def __getstate__(self):
@@ -112,8 +110,10 @@ class PyCode(object):
def __setstate__(self, state):
(_, self.source, self.location, self.mode) = state
self.bytecode = None
renpy.game.script.all_pycode.append(weakref.ref(self))
if renpy.game.script.record_pycode:
renpy.game.script.all_pycode.append(self)
def __init__(self, source, loc=('<none>', 1), mode='exec'):
if isinstance(source, PyExpr):
@@ -130,7 +130,8 @@ class PyCode(object):
# This will be initialized later on, after we are serialized.
self.bytecode = None
renpy.game.script.all_pycode.append(weakref.ref(self))
if renpy.game.script.record_pycode:
renpy.game.script.all_pycode.append(self)
def chain_block(block, next):
"""
+7
View File
@@ -847,6 +847,12 @@ class Interpolation(Statement):
# between the new and old states.
linear = trans.state.diff(newts)
# Ensure that we set things, even if they don't actually
# change from the old state.
for k, v in self.properties:
if k not in linear:
setattr(trans.state, k, v)
revolution = None
splines = [ ]
@@ -906,6 +912,7 @@ class Interpolation(Statement):
# Linearly interpolate between the things in linear.
for k, (old, new) in linear.iteritems():
value = interpolate(complete, old, new, PROPERTIES[k])
setattr(trans.state, k, value)
# Handle the revolution.
+25 -12
View File
@@ -813,7 +813,24 @@ def rollback():
ALLOC_EVENT = pygame.USEREVENT
REFRESH_EVENT = pygame.USEREVENT + 1
# The last surface we allocated.
last_alloc_surface = None
def alloc_surface(force):
global last_alloc_surface
if renpy.display.video.fullscreen and renpy.display.draw.fullscreen_surface:
surf = renpy.display.draw.fullscreen_surface
else:
surf = renpy.display.video.surface
if (surf is not last_alloc_surface) or force:
last_alloc_surface = surf
pss.alloc_event(surf)
def event(ev):
"""
Handles an event generated by pss (really, the ffdecode
@@ -824,24 +841,20 @@ def event(ev):
if not pcm_ok:
return False
if renpy.display.video.fullscreen or not renpy.display.video.surface:
surf = renpy.display.draw.fullscreen_surface
else:
surf = renpy.display.video.surface
if ev.type == ALLOC_EVENT:
pss.alloc_event(surf)
alloc_surface(True)
return True
if ev.type == REFRESH_EVENT:
elif ev.type == REFRESH_EVENT:
alloc_surface(False)
if renpy.audio.music.get_playing("movie"):
pss.refresh_event()
renpy.display.draw.mutated_surface(surf)
if surf is renpy.display.draw.fullscreen_surface:
renpy.game.interface.force_redraw = True
renpy.game.interface.force_redraw = True
# Return False, as a Movie should get this to know when to
# redraw itself.
+58 -55
View File
@@ -239,69 +239,72 @@ def bootstrap(renpy_base):
keep_running = True
report_error = None
while keep_running:
try:
renpy.game.options = options
try:
while keep_running:
try:
renpy.game.options = options
renpy.config.renpy_base = renpy_base
renpy.config.basedir = basedir
renpy.config.gamedir = gamedir
renpy.config.args = options.args
renpy.main.main()
keep_running = False
renpy.config.renpy_base = renpy_base
renpy.config.basedir = basedir
renpy.config.gamedir = gamedir
renpy.config.args = options.args
except KeyboardInterrupt:
import traceback
traceback.print_exc()
break
except renpy.game.UtterRestartException:
if renpy.display.draw:
renpy.display.draw.deinit()
# Only works after a full restart.
report_error = renpy.display.error.ReportError()
# On an UtterRestart, reload Ren'Py.
renpy.reload_all()
continue
except renpy.game.ParseErrorException:
if report_error and report_error.report('a parse error'):
renpy.reload_all()
keep_running = True
else:
renpy.main.main()
keep_running = False
except KeyboardInterrupt:
import traceback
traceback.print_exc()
break
except renpy.game.UtterRestartException:
if renpy.display.draw:
renpy.display.draw.deinit()
# Only works after a full restart.
report_error = renpy.display.error.ReportError()
# On an UtterRestart, reload Ren'Py.
renpy.reload_all()
continue
except renpy.game.ParseErrorException:
if report_error and report_error.report('a parse error'):
renpy.reload_all()
keep_running = True
else:
keep_running = False
except Exception, e:
report_exception(e)
if report_error and report_error.report('an exception'):
renpy.reload_all()
keep_running = True
else:
keep_running = False
sys.exit(0)
finally:
except Exception, e:
report_exception(e)
if "RENPY_SHUTDOWN_TRACE" in os.environ:
enable_trace(int(os.environ["RENPY_SHUTDOWN_TRACE"]))
if report_error and report_error.report('an exception'):
renpy.reload_all()
keep_running = True
else:
keep_running = False
renpy.display.im.cache.quit()
if "RENPY_SHUTDOWN_TRACE" in os.environ:
enable_trace(int(os.environ["RENPY_SHUTDOWN_TRACE"]))
if options.leak:
memory_profile()
if renpy.display.draw:
renpy.display.draw.quit()
renpy.display.im.cache.quit()
if renpy.display.draw:
renpy.display.draw.quit()
# Prevent subprocess from throwing errors while trying to run it's
# __del__ method during shutdown.
import subprocess # W0403
subprocess.Popen.__del__ = popen_del # E1101
# Prevent subprocess from throwing errors while trying to run it's
# __del__ method during shutdown.
import subprocess # W0403
subprocess.Popen.__del__ = popen_del # E1101
sys.exit(0)
if options.leak:
memory_profile()
def report_tb(out, tb):
+3
View File
@@ -431,6 +431,9 @@ gamedir = None
basedir = None
renpy_base = None
# Should we enable OpenGL mode?
gl_enable = True
del renpy
def init():
+1 -1
View File
@@ -615,7 +615,7 @@ class Input(renpy.display.text.Text):
def __init__(self,
default="",
length=None,
style='input_text',
style='input',
allow=None,
exclude=None,
prefix="",
+7
View File
@@ -1221,6 +1221,11 @@ class Interface(object):
This sets the video mode. It also picks the draw object.
"""
if self.display_reset:
renpy.display.draw.deinit()
renpy.display.draw.quit()
renpy.display.draw = None
self.display_reset = False
# Ensure that we kill off the movie when changing screen res.
@@ -1272,6 +1277,8 @@ class Interface(object):
def draw_screen(self, root_widget, fullscreen_video):
surftree = renpy.display.render.render_screen(
root_widget,
renpy.config.screen_width,
+30 -14
View File
@@ -80,9 +80,6 @@ class GLDraw(object):
# This is used to cache the surface->texture operation.
self.texture_cache = weakref.WeakKeyDictionary()
# This is a fullscreen surface used for video playback.
self.fullscreen_surface = None
# The time of the last redraw.
self.last_redraw_time = 0
@@ -91,7 +88,9 @@ class GLDraw(object):
# Old value of fullscreen.
self.old_fullscreen = None
# We don't use a fullscreen surface.
self.fullscreen_surface = None
def log(self, msg, *args):
"""
@@ -114,6 +113,10 @@ class GLDraw(object):
# If GL can't be loaded, give up.
if not gl:
return False
if not renpy.config.gl_enable:
self.log("GL Disabled.")
return False
if self.did_init:
self.deinit()
@@ -201,9 +204,6 @@ class GLDraw(object):
self.environ.init()
self.rtt.init()
# Allocate a fullscreen surface for video playback.
self.fullscreen_surface = renpy.display.pgrender.surface(self.virtual_size, False)
# Prepare a mouse call.
self.mouse_old_visible = None
@@ -228,7 +228,11 @@ class GLDraw(object):
self.environ.deinit()
def quit(self):
self.log("Deallocating textures.")
gltexture.dealloc_textures()
self.log("Done deallocating textures.")
self.log("About to quit GL.")
pygame.display.quit()
self.log("Finished quit GL.")
@@ -241,12 +245,15 @@ class GLDraw(object):
# Init glew.
pysdlgl.init_glew()
renderer = pysdlgl.get_string(gl.RENDERER)
# Log the GL version.
self.log("Vendor: %r", pysdlgl.get_string(gl.VENDOR))
self.log("Renderer: %r", pysdlgl.get_string(gl.RENDERER))
self.log("Renderer: %r", renderer)
self.log("Version: %r", pysdlgl.get_string(gl.VERSION))
self.log("Video Info: %s", pygame.display.Info())
extensions = set(pysdlgl.get_string(gl.EXTENSIONS).split(" "))
self.log("Extensions:")
@@ -340,7 +347,14 @@ class GLDraw(object):
self.log("Using copy RTT.")
self.rtt = glenviron.CopyRtt()
self.info["rtt"] = "copy"
# Check for ctrl held down at startup - revert to software
# rendering if that's the case.
if pygame.key.get_mods() & pygame.KMOD_SHIFT:
self.log("Giving up on OpenGL, because SHIFT is held down.")
return False
# Do additional setup needed.
renpy.display.pgrender.set_bgra_masks()
@@ -351,7 +365,7 @@ class GLDraw(object):
def should_redraw(self, needs_redraw, first_pass):
"""
Redraw whenever the screen needs it, but at least once every
1/20 seconds. We rely on VSYNC to slow down our maximum
.2 seconds. We rely on VSYNC to slow down our maximum
draw speed.
"""
@@ -449,7 +463,9 @@ class GLDraw(object):
self.undefine_clip()
if renpy.audio.music.get_playing("movie") and renpy.display.video.fullscreen:
tex = self.load_texture(self.fullscreen_surface, transient=True)
tex = renpy.display.video.get_movie_texture(self.virtual_size)
# self.load_texture(self.fullscreen_surface, transient=True)
self.draw_transformed(tex, clip, 0, 0, 1.0, forward, reverse)
else:
self.draw_transformed(surftree, clip, 0, 0, 1.0, forward, reverse)
+3 -6
View File
@@ -393,12 +393,9 @@ class ShaderEnviron(object):
if self.last != IMAGEBLEND:
gl.UseProgramObjectARB(self.imageblend_program)
# Permute the texture units so they match the way the
# fixed-function system uses them.
gl.Uniform1iARB(self.imageblend_tex0_uniform, 1)
gl.Uniform1iARB(self.imageblend_tex1_uniform, 2)
gl.Uniform1iARB(self.imageblend_tex2_uniform, 0)
gl.Uniform1iARB(self.imageblend_tex0_uniform, 0)
gl.Uniform1iARB(self.imageblend_tex1_uniform, 1)
gl.Uniform1iARB(self.imageblend_tex2_uniform, 2)
self.last = IMAGEBLEND
+2 -2
View File
@@ -80,9 +80,9 @@ void main()
vec4 color1 = texture2D(tex1, gl_TexCoord[1].st);
vec4 color2 = texture2D(tex2, gl_TexCoord[2].st);
float a = clamp((color2.a + offset) * multiplier, 0.0, 1.0);
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
gl_FragColor = mix(color0, color1, a) * gl_Color;
gl_FragColor = mix(color1, color2, a) * gl_Color;
}
"""
+148 -4
View File
@@ -751,11 +751,11 @@ def imageblend(tg0, tg1, tg2, sx, sy, transform, alpha, fraction, ramp, environ)
x = 0
for (t0x, t0w, t0ci), (t1x, t1w, t1ci), (t2x, t2w, t2ci) in zip(cols0, cols1, cols2):
t0 = tg0.tiles[t0ri][t0ci]
t1 = tg1.tiles[t1ri][t1ci]
t2 = tg2.tiles[t2ri][t2ci]
pysdlgl.draw_rectangle(
sx, sy,
x, y,
@@ -764,9 +764,153 @@ def imageblend(tg0, tg1, tg2, sx, sy, transform, alpha, fraction, ramp, environ)
t0, t0x, t0y,
t1, t1x, t1y,
t2, t2x, t2y)
x += t0w
y += t0h
def draw_rectangle(
sx,
sy,
x,
y,
w,
h,
transform,
tex0, tex0x, tex0y,
tex1, tex1x, tex1y,
tex2, tex2x, tex2y):
"""
This draws a rectangle (textured with up to four textures) to the
screen.
"""
# Pull apart the transform.
xdx = transform.xdx
xdy = transform.xdy
ydx = transform.ydx
ydy = transform.ydy
# Transform the vertex coordinates to screen-space.
x0 = (x + 0) * xdx + (y + 0) * xdy + sx
y0 = (x + 0) * ydx + (y + 0) * ydy + sy
x1 = (x + w) * xdx + (y + 0) * xdy + sx
y1 = (x + w) * ydx + (y + 0) * ydy + sy
x2 = (x + 0) * xdx + (y + h) * xdy + sx
y2 = (x + 0) * ydx + (y + h) * ydy + sy
x3 = (x + w) * xdx + (y + h) * xdy + sx
y3 = (x + w) * ydx + (y + h) * ydy + sy
# Compute the texture coordinates, and set up the textures.
if tex0 is not None:
has_tex0 = 1
gl.ActiveTextureARB(gl.TEXTURE0_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex0.number)
xadd = tex0.xadd
yadd = tex0.yadd
xmul = tex0.xmul
ymul = tex0.ymul
t0u0 = xadd + xmul * (tex0x + 0)
t0u1 = xadd + xmul * (tex0x + w)
t0v0 = yadd + ymul * (tex0y + 0)
t0v1 = yadd + ymul * (tex0y + h)
else:
has_tex0 = 0
if tex1 is not None:
has_tex1 = 1
gl.ActiveTextureARB(gl.TEXTURE1_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex1.number)
xadd = tex1.xadd
yadd = tex1.yadd
xmul = tex1.xmul
ymul = tex1.ymul
t1u0 = xadd + xmul * (tex1x + 0)
t1u1 = xadd + xmul * (tex1x + w)
t1v0 = yadd + ymul * (tex1y + 0)
t1v1 = yadd + ymul * (tex1y + h)
else:
has_tex1 = 0
if tex2 is not None:
has_tex2 = 1
gl.ActiveTextureARB(gl.TEXTURE2_ARB)
gl.BindTexture(gl.TEXTURE_2D, tex2.number)
xadd = tex2.xadd
yadd = tex2.yadd
xmul = tex2.xmul
ymul = tex2.ymul
t2u0 = xadd + xmul * (tex2x + 0)
t2u1 = xadd + xmul * (tex2x + w)
t2v0 = yadd + ymul * (tex2y + 0)
t2v1 = yadd + ymul * (tex2y + h)
else:
has_tex2 = 0
# Now, actually draw the textured rectangle.
gl.Begin(gl.TRIANGLE_STRIP)
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u0, t0v0)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u0, t1v0)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u0, t2v0)
gl.Vertex2f(x0, y0)
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u1, t0v0)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u1, t1v0)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u1, t2v0)
gl.Vertex2f(x1, y1)
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u0, t0v1)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u0, t1v1)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u0, t2v1)
gl.Vertex2f(x2, y2)
if has_tex0:
gl.MultiTexCoord2fARB(gl.TEXTURE0_ARB, t0u1, t0v1)
if has_tex1:
gl.MultiTexCoord2fARB(gl.TEXTURE1_ARB, t1u1, t1v1)
if has_tex2:
gl.MultiTexCoord2fARB(gl.TEXTURE2_ARB, t2u1, t2v1)
gl.Vertex2f(x3, y3)
gl.End()
C_DRAW=True
if C_DRAW:
if pysdlgl:
draw_rectangle = pysdlgl.draw_rectangle
else:
print "Warning: Draw not using C code."
+2 -2
View File
@@ -307,7 +307,7 @@ class Grid(Container):
def __init__(self, cols, rows, padding=None,
transpose=False,
style='default', **properties):
style='grid', **properties):
"""
@param cols: The number of columns in this widget.
@@ -1138,7 +1138,7 @@ class Side(Container):
def after_setstate(self):
self.sized = False
def __init__(self, positions, style='default', **properties):
def __init__(self, positions, style='side', **properties):
super(Side, self).__init__(style=style, **properties)
+4 -1
View File
@@ -176,7 +176,7 @@ class TransformState(renpy.object.Object):
else:
old_value = old
if new_value != new or new_value != old_value:
if new_value != old_value:
rv[prop] = (old_value, new_value)
diff2("alpha", newts.alpha, self.alpha)
@@ -199,6 +199,7 @@ class TransformState(renpy.object.Object):
diff2("size", newts.size, self.size)
diff4("xpos", newts.xpos, newts.default_xpos, self.xpos, self.default_xpos)
diff4("xanchor", newts.xanchor, newts.default_xanchor, self.xanchor, self.default_xanchor)
diff2("xoffset", newts.xoffset, self.xoffset)
@@ -382,6 +383,8 @@ class Transform(Container):
xoffset = Proxy("xoffset")
yoffset = Proxy("yoffset")
offset = Proxy("offset")
subpixel = Proxy("subpixel")
def after_upgrade(self, version):
+5 -1
View File
@@ -137,8 +137,12 @@ def render(d, width, height, st, at):
rv = render_cache[d].get(wh, None)
if rv is not None:
return rv
rv = d.render(width, height, st, at)
if rv is None:
print d.style.parent, d.style, d.style.box_layout, d.style.name
rv.render_of.append(d)
if style.clipping:
+7 -4
View File
@@ -225,7 +225,6 @@ class Clipper(object):
updates.append((ix0, iy0, ix1 - ix0, iy1 - iy0))
return (x0, y0, x1 - x0, y1 - y0), updates
clippers = [ Clipper() ]
@@ -918,10 +917,8 @@ class SWDraw(object):
return True
return False
def mutated_surface(self, surf):
"""
Called to indicate that the given surface has changed.
@@ -964,6 +961,12 @@ class SWDraw(object):
rle_cache.clear()
def deinit(self):
"""
Called when we're restarted.
"""
return
def quit(self):
"""
+3 -3
View File
@@ -139,8 +139,8 @@ class TextStyle(object):
return rv
def sizes(self, text):
return self.get_width(text), self.f.get_ascent() - self.f.get_descent()
height = max(self.f.get_ascent() - self.f.get_descent(), self.f.get_height())
return self.get_width(text), height
def render(self, text, antialias, color, black_color, use_colors, time, at, expand, use_cache):
@@ -1316,7 +1316,7 @@ class Text(renpy.display.core.Displayable):
length = sys.maxint
self.call_slow_done(st)
final_width = self.laidout_width - mindsx + maxdsx
final_width = self.laidout_width - mindsx + maxdsx + max(self.style.first_indent, self.style.rest_indent)
final_height = self.laidout_height - mindsy + maxdsy
rv = renpy.display.render.Render(final_width, final_height)
+1 -1
View File
@@ -413,7 +413,7 @@ class ImageDissolve(Transition):
image = render(self.image, width, height, st, at)
bottom = render(self.old_widget, width, height, st, at)
top = render(self.new_widget, width, height, st, at)
width = min(bottom.width, top.width, image.width)
height = min(bottom.height, top.height, image.height)
+30 -19
View File
@@ -34,7 +34,6 @@ surface_file = None
# The surface to display the movie on, if not fullscreen.
surface = None
def movie_stop(clear=True, only_fullscreen=False):
"""
Stops the currently playing movie.
@@ -68,7 +67,7 @@ def movie_start(filename, size=None, loops=0):
filename = filename * (loops + 1)
renpy.audio.music.play(filename, channel='movie', loop=loop)
movie_start_fullscreen = movie_start
movie_start_displayable = movie_start
@@ -81,7 +80,6 @@ def early_interact():
global fullscreen
fullscreen = True
def interact():
"""
This is called each time the screen is redrawn. It helps us decide if
@@ -93,44 +91,57 @@ def interact():
else:
return False
def get_movie_texture(size):
"""
Gets a movie texture we can draw to the screen.
"""
global surface
global surface_file
playing = renpy.audio.music.get_playing("movie")
if (surface is None) or (surface.get_size() != size) or (surface_file != playing):
surface = renpy.display.pgrender.surface(size, False)
surface_file = playing
surface.fill((0, 0, 0, 255))
tex = None
if playing is not None:
renpy.display.render.mutated_surface(surface)
tex = renpy.display.draw.load_texture(surface)
return tex
class Movie(renpy.display.core.Displayable):
"""
This is a displayable that shows the current movie.
"""
fullscreen = False
def __init__(self, fps=24, size=None, **properties):
"""
@param fps: The framerate that the movie should be shown at.
"""
super(Movie, self).__init__(**properties)
self.size = size
def render(self, width, height, st, at):
global surface
global surface_file
size = self.size
if size is None:
size = default_size
playing = renpy.audio.music.get_playing("movie")
if (surface is None) or (surface.get_size() != size) or (surface_file != playing):
surface = renpy.display.pgrender.surface(size, False)
surface_file = playing
surface.fill((0, 0, 0, 255))
width, height = size
rv = renpy.display.render.Render(width, height)
if playing is not None:
renpy.display.render.mutated_surface(surface)
tex = renpy.display.draw.load_texture(surface)
rv = renpy.display.render.Render(width, height, opaque=True)
tex = get_movie_texture(size)
if tex is not None:
rv.blit(tex, (0, 0))
return rv
+8 -1
View File
@@ -1365,7 +1365,7 @@ def call_screen(_screen_name, **kwargs):
rv = None
try:
rv = renpy.ui.interact(roll_forward=roll_forward)
rv = renpy.ui.interact(mouse="screen", type="screen", roll_forward=roll_forward)
return rv
finally:
@@ -1417,3 +1417,10 @@ def get_renderer_info():
return renpy.display.draw.info
def display_reset():
"""
Used internally. Causes the display to be restarted at the start of
the next interaction.
"""
renpy.display.interface.display_reset = True
+4 -4
View File
@@ -610,7 +610,7 @@ class Lexer(object):
return self.word_cache
self.word_cache_pos = self.pos
rv = self.match(ur'[a-zA-Z_\u00a0-\ufffd\$][0-9a-zA-Z_\u00a0-\ufffd\$]*')
rv = self.match(ur'[a-zA-Z_\u00a0-\ufffd][0-9a-zA-Z_\u00a0-\ufffd]*')
self.word_cache = rv
self.word_cache_newpos = self.pos
@@ -829,7 +829,7 @@ class Lexer(object):
passed to revert to back the lexer up.
"""
return self.filename, self.number, self.text, self.subblock, self.pos
return self.line, self.filename, self.number, self.text, self.subblock, self.pos
def revert(self, state):
"""
@@ -837,7 +837,7 @@ class Lexer(object):
by a previous checkpoint operation on this lexer.
"""
self.filename, self.number, self.text, self.subblock, self.pos = state
self.line, self.filename, self.number, self.text, self.subblock, self.pos = state
self.word_cache_pos = -1
def get_location(self):
@@ -1321,7 +1321,7 @@ class ParseTrie(object):
def parse(self, l):
old_pos = l.pos
word = l.word()
word = l.word() or l.match(r'\$')
if not word in self.words:
l.pos = old_pos
+10 -6
View File
@@ -164,7 +164,7 @@ def set_filename(filename, offset, tree):
worklist.extend(node.getChildNodes())
def make_unicode(m):
def unicode_sub(m):
"""
If the string s contains a unicode character, make it into a
unicode string.
@@ -188,6 +188,13 @@ def make_unicode(m):
string_re = re.compile(r'([uU]?[rR]?)("""|"|\'\'\'|\')((\\.|.)*?)\2')
def escape_unicode(s):
s = s.encode("raw_unicode_escape")
if "\\u" in s:
s = string_re.sub(unicode_sub, s)
return s
def py_compile(source, mode, filename='<none>', lineno=1):
"""
@@ -195,7 +202,7 @@ def py_compile(source, mode, filename='<none>', lineno=1):
Lists, List Comprehensions, and Dictionaries are wrapped when
appropriate.
@param source: The sourccode, as a string.
@param source: The source code, as a string.
@param mode: 'exec' or 'eval'.
@@ -212,10 +219,7 @@ def py_compile(source, mode, filename='<none>', lineno=1):
lineno = source.linenumber
source = source.replace("\r", "")
source = source.encode('raw_unicode_escape')
if "\\u" in source:
source = string_re.sub(make_unicode, source)
source = escape_unicode(source)
try:
line_offset = lineno - 1
+81 -21
View File
@@ -152,15 +152,22 @@ class Parser(object):
elif isinstance(i, Parser):
self.children[i.name] = i
def parse_statement(self, l, name):
word = l.word()
def parse_statement(self, l, name, layout_mode=False):
word = l.word() or l.match(r'\$')
if word and word in self.children:
c = self.children[word].parse(l, name)
if layout_mode:
c = self.children[word].parse_layout(l, name)
else:
c = self.children[word].parse(l, name)
return c
else:
return None
def parse_layout(self, l, name):
l.error("The %s statement cannot be used as a container for the has statement." % self.name)
def parse_children(self, stmt, l, name):
l.expect_block(stmt)
@@ -195,6 +202,9 @@ class Parser(object):
and expr instances, and adjusts the line number.
"""
if isinstance(expr, unicode):
expr = renpy.python.escape_unicode(expr)
try:
rv = ast.parse(expr, 'eval').body[0].value
except SyntaxError, e:
@@ -215,12 +225,13 @@ class Parser(object):
adjusts the line number. Returns a list of statements.
"""
if isinstance(code, unicode):
code = renpy.python.escape_unicode(code)
try:
rv = ast.parse(code, 'exec')
except SyntaxError, e:
print repr(e)
raise renpy.parser.ParseError(
filename,
lineno + e[1][1] - 1,
@@ -281,8 +292,11 @@ class FunctionStatementParser(Parser):
if nchildren != 0:
childbearing_statements.append(self)
def parse_layout(self, l, name):
return self.parse(l, name, True)
def parse(self, l, name):
def parse(self, l, name, layout_mode=False):
# The list of nodes this function returns.
rv = [ ]
@@ -290,6 +304,9 @@ class FunctionStatementParser(Parser):
# The line number of the current node.
lineno = l.number
if layout_mode and self.nchildren is not many:
l.error("The %s statement cannot be used as a layout." % self.name)
func = self.parse_eval(self.function, lineno)
call_node = ast.Call(
@@ -303,14 +320,14 @@ class FunctionStatementParser(Parser):
)
seen_keywords = set()
# Parses a keyword argument from the lexer.
def parse_keyword(l):
name = l.word()
if name is None:
l.error('expected a keyword argument, colon, or end of line.')
if name not in self.keyword:
l.error('%r is not a keyword argument or valid child for the %s statement.' % (name, self.name))
@@ -351,22 +368,49 @@ class FunctionStatementParser(Parser):
if self.nchildren == 1:
rv.extend(self.parse_exec('ui.child_or_fixed()'))
needs_close = (self.nchildren != 0)
# The index of the child we're adding to this statement.
child_index = 0
# The variable we store the child's name in.
with new_variable() as child_name:
old_l = l
# If we have a block, then parse each line.
if block:
l = l.subblock_lexer()
while l.advance():
state = l.checkpoint()
if l.keyword(r'has'):
if self.nchildren != 1:
l.error("The %s statement does not take a layout." % self.name)
if child_index != 0:
l.error("The has statement may not be given after a child has been supplied.")
c = self.parse_statement(l, child_name, layout_mode=True)
if c is None:
l.error('Has expects a child statement.')
# Remove the call to child_or_fixed.
rv.pop()
rv.extend(self.parse_exec("%s = (%s, %d)" % (child_name, name, child_index)))
rv.extend(c)
needs_close = False
continue
c = self.parse_statement(l, child_name)
if c is not None:
rv.extend(self.parse_exec("%s = (%s, %d)" % (child_name, name, child_index)))
@@ -381,7 +425,24 @@ class FunctionStatementParser(Parser):
while not l.eol():
parse_keyword(l)
if self.nchildren != 0:
l = old_l
if layout_mode:
while l.advance():
c = self.parse_statement(l, child_name)
if c is not None:
rv.extend(self.parse_exec("%s = (%s, %d)" % (child_name, name, child_index)))
rv.extend(c)
child_index += 1
else:
l.error("Expected a screen language statement.")
if needs_close:
rv.extend(self.parse_exec("ui.close()"))
if "id" not in seen_keywords:
@@ -416,6 +477,8 @@ position_properties = [ Style(i) for i in [
"ymaximum",
"area",
"clipping",
"xfill",
"yfill",
] ]
text_properties = [ Style(i) for i in [
@@ -447,8 +510,6 @@ text_properties = [ Style(i) for i in [
"ymaximum",
"xminimum",
"yminimum",
"xfill",
"yfill",
] ]
window_properties = [ Style(i) for i in [
@@ -469,8 +530,6 @@ window_properties = [ Style(i) for i in [
"size_group",
"xminimum",
"yminimum",
"xfill",
"yfill",
] ]
button_properties = [ Style(i) for i in [
@@ -501,14 +560,13 @@ box_properties = [ Style(i) for i in [
"box_layout",
"spacing",
"first_spacing",
"xfill",
"yfill",
] ]
ui_properties = [
Keyword("at"),
Keyword("id"),
Keyword("style"),
Keyword("group"),
]
@@ -795,13 +853,13 @@ class IfParser(Parser):
count += 1
while l.advance():
state = l.checkpoint()
while l.advance():
old_orelse = orelse
lineno = l.number
state = l.checkpoint()
if l.keyword("elif"):
condition = self.parse_eval(l.require(l.python_expression), lineno)
@@ -813,6 +871,8 @@ class IfParser(Parser):
count += 1
state = l.checkpoint()
elif l.keyword("else"):
old_orelse.extend(self.parse_exec("%s = (%s, %d)" % (child_name, name, count)))
@@ -823,7 +883,7 @@ class IfParser(Parser):
else:
l.revert(state)
break
return [ rv ]
IfParser("if")
+7 -9
View File
@@ -110,7 +110,8 @@ class Script(object):
self.namemap = { }
self.all_stmts = [ ]
self.all_pycode = [ ]
self.record_pycode = True
# Bytecode caches.
self.bytecode_oldcache = { }
self.bytecode_newcache = { }
@@ -246,11 +247,15 @@ class Script(object):
# See if we have a corresponding .rpyc file. If so, then
# we want to try to upgrade our .rpy file with it.
try:
self.record_pycode = False
old_data, old_stmts = self.load_file_core(dir, fn + "c")
self.merge_names(old_stmts, stmts)
del old_data
del old_stmts
except:
pass
finally:
self.record_pycode = True
self.assign_names(stmts, fullfn)
@@ -286,12 +291,9 @@ class Script(object):
return None, None
return data, stmts
def load_file(self, dir, fn, initcode):
# Actually do the loading.
data, stmts = self.load_file_core(dir, fn)
if data is None:
@@ -415,10 +417,6 @@ class Script(object):
# bytecode.
for i in self.all_pycode:
i = i()
if i is None:
continue
codes = self.bytecode_oldcache.get(i.location, { })
if magic in codes:
+18 -4
View File
@@ -384,14 +384,28 @@ def reset():
class StyleManager(object):
"""
This is the singleton object that is exported into the store
as style
as style.
"""
def __getattr__(self, name):
try:
return style_map[name]
except:
raise Exception('The style %s does not exist.' % name)
pass
# Automatically create styles, maybe.
if not styles_built:
if "_" in name:
first, rest = name.split("_", 1)
if rest in style_map:
s = Style(rest)
self.__setattr__(name, s)
return s
else:
raise Exception("The style %s does not exist, and couldn't be auto-created because %s doesn't exist, either." % (name, rest))
raise Exception('The style %s does not exist.' % name)
def __setattr__(self, name, value):
@@ -477,7 +491,7 @@ def expand_properties(properties):
# This builds the style.
def build_style(style):
if style.cache is not None:
return
@@ -592,7 +606,7 @@ def build_styles():
global styles_pending
global styles_built
for s in styles_pending:
build_style(s)
+93 -45
View File
@@ -29,7 +29,6 @@
import sys
import renpy
##############################################################################
# Special classes that can be subclassed from the outside.
@@ -76,6 +75,9 @@ class BarValue(renpy.object.Object):
# closed.
class Addable(object):
# A group associates with this addable.
group = None
def get_layer(self):
return Exception("Operation can only be performed on a layer.")
@@ -101,9 +103,10 @@ class Many(Addable):
A widget that takes many children.
"""
def __init__(self, displayable, imagemap):
def __init__(self, displayable, imagemap, group):
self.displayable = displayable
self.imagemap = False
self.group = group
def add(self, d, key):
self.displayable.add(d)
@@ -122,9 +125,10 @@ class One(Addable):
A widget that expects exactly one child.
"""
def __init__(self, displayable):
def __init__(self, displayable, group):
self.displayable = displayable
self.group = group
def add(self, d, key):
self.displayable.add(d)
stack.pop()
@@ -150,9 +154,10 @@ class ChildOrFixed(Addable):
the widgets are added to that.
"""
def __init__(self):
def __init__(self, group):
self.queue = [ ]
self.group = group
def add(self, d, key):
self.queue.append(d)
@@ -225,7 +230,7 @@ def child_or_fixed():
a fixed will be created, and the children will be added to that.
"""
stack.append(ChildOrFixed())
stack.append(ChildOrFixed(stack[-1].group))
def remove(d):
layer = stack[-1].get_layer()
@@ -301,7 +306,27 @@ def context_enter(w):
def context_exit(w):
close(w)
NoGroupGiven = object()
def group_style(s, group):
"""
Given a style name s, combine it with the group to create a new
style. If the style doesn't exist, create a new lightweight style.
"""
if group is NoGroupGiven:
group = stack[-1].group
if group is None:
return s
new_style = group + "_" + s
if new_style not in renpy.style.style_map:
renpy.style.style_map[new_style] = renpy.style.Style(s, heavy=False, name=new_style)
return new_style
# The screen we're using as we add widgets. None if there isn't a
# screen.
screen = None
@@ -311,7 +336,7 @@ class Wrapper(renpy.object.Object):
def __reduce__(self):
return self.name
def __init__(self, function, one=False, many=False, imagemap=False, replaces=False, **kwargs):
def __init__(self, function, one=False, many=False, imagemap=False, replaces=False, style=None, **kwargs):
# The name assigned to this wrapper. This is used to serialize us correctly.
self.name = None
@@ -331,18 +356,30 @@ class Wrapper(renpy.object.Object):
# Default keyword arguments to the function.
self.kwargs = kwargs
# Default style (suffix).
self.style = style
def __call__(self, *args, **kwargs):
global add_tag
# Pull out the special kwargs, id and at.
if not stack:
raise Exception("Can't add displayable during init phase.")
# Pull out the special kwargs, id, at, and group.
id = kwargs.pop("id", None)
at_list = kwargs.pop("at", [ ])
if not isinstance(at_list, list):
at_list = [ at_list ]
group = kwargs.pop("group", NoGroupGiven)
# Figure out our group.
if group is NoGroupGiven:
group = stack[-1].group
# Figure out the keyword arguments, based on the parameters.
if self.kwargs:
@@ -358,16 +395,16 @@ class Wrapper(renpy.object.Object):
if self.replaces:
keyword["replaces"] = screen.old_widgets.get(id, None)
if self.style and "style" not in keyword:
keyword["style"] = group_style(self.style, group)
try:
w = self.function(*args, **keyword)
# We want to rewrite the type error so that it mentions our name,
# so the user gcan figure out WTF is going on.
except TypeError:
except TypeError, e:
etype, e, tb = sys.exc_info(); etype
if tb.tb_next is None:
e.args = (e.args[0].replace("__init__", "ui." + self.name), )
e.args = (e.args[0].replace("__call__", "ui." + self.name), )
del tb # Important! Prevents memory leaks via our frame.
raise
@@ -385,17 +422,13 @@ class Wrapper(renpy.object.Object):
atw = atf(atw)
# Add to the displayable at the bottom of the stack.
if stack:
stack[-1].add(atw, add_tag)
else:
raise Exception("Can't add displayable during init phase.")
stack[-1].add(atw, add_tag)
# Update the stack, as necessary.
if self.one:
stack.append(One(w))
stack.append(One(w, group))
elif self.many:
stack.append(Many(w, self.imagemap))
stack.append(Many(w, self.imagemap, group))
# If we have an id, record the displayable, the transform,
# and maybe take the state from a previous transform.
@@ -466,19 +499,19 @@ def _image(im, **properties):
image = Wrapper(_image)
null = Wrapper(renpy.display.layout.Null)
text = Wrapper(renpy.display.text.Text, replaces=True)
text = Wrapper(renpy.display.text.Text, style="text", replaces=True)
hbox = Wrapper(renpy.display.layout.MultiBox, layout="horizontal", style="hbox", many=True)
vbox = Wrapper(renpy.display.layout.MultiBox, layout="vertical", style="vbox", many=True)
fixed = Wrapper(renpy.display.layout.MultiBox, layout="fixed", many=True)
grid = Wrapper(renpy.display.layout.Grid, many=True)
side = Wrapper(renpy.display.layout.Side, many=True)
fixed = Wrapper(renpy.display.layout.MultiBox, layout="fixed", style="fixed", many=True)
grid = Wrapper(renpy.display.layout.Grid, style="grid", many=True)
side = Wrapper(renpy.display.layout.Side, style="side", many=True)
def _sizer(maxwidth=None, maxheight=None, **properties):
return renpy.display.layout.Container(xmaximum=maxwidth, ymaximum=maxheight, **properties)
sizer = Wrapper(_sizer, one=True)
window = Wrapper(renpy.display.layout.Window, one=True, child=None)
frame = Wrapper(renpy.display.layout.Window, style='frame', one=True, child=None)
window = Wrapper(renpy.display.layout.Window, style="window", one=True, child=None)
frame = Wrapper(renpy.display.layout.Window, style="frame", one=True, child=None)
keymap = Wrapper(renpy.display.behavior.Keymap)
saybehavior = Wrapper(renpy.display.behavior.SayBehavior)
@@ -553,7 +586,7 @@ def menu(menuitems,
close()
input = Wrapper(renpy.display.behavior.Input, exclude='{}', replaces=True)
input = Wrapper(renpy.display.behavior.Input, exclude='{}', style="input", replaces=True)
def imagemap_compat(ground,
selected,
@@ -591,7 +624,7 @@ def imagemap_compat(ground,
close()
button = Wrapper(renpy.display.behavior.Button, one=True)
button = Wrapper(renpy.display.behavior.Button, style='button', one=True)
def _imagebutton(idle_image = None,
hover_image = None,
@@ -607,7 +640,6 @@ def _imagebutton(idle_image = None,
selected_idle=None,
selected_hover=None,
selected_insensitive=None,
style='image_button',
image_style=None,
auto=None,
**properties):
@@ -638,17 +670,15 @@ def _imagebutton(idle_image = None,
selected_hover_image = selected_hover,
selected_insensitive_image = selected_insensitive,
selected_activate_image = selected_activate_image,
style=style,
**properties)
imagebutton = Wrapper(_imagebutton)
imagebutton = Wrapper(_imagebutton, style="image_button")
def get_text_style(style, default):
if isinstance(style, basestring):
base = style
rest = ()
else:
print style
base = style.name[0]
rest = style.name[1:]
@@ -657,26 +687,32 @@ def get_text_style(style, default):
rv = renpy.style.style_map.get(base, None)
if rv is None:
rv = renpy.style.style_map['default']
rv = renpy.style.style_map[default]
for i in rest:
rv = rv[i]
return rv
def textbutton(label, clicked=None, style='button', text_style=None, **kwargs):
def textbutton(label, clicked=None, style=None, text_style=None, **kwargs):
if style is None:
style = group_style('button', NoGroupGiven)
if text_style is None:
text_style = get_text_style(style, 'button_text')
text_style = get_text_style(style, group_style('button_text', NoGroupGiven))
button(style=style, clicked=clicked, **kwargs)
text(label, style=text_style)
def label(label, style='label', text_style=None, **kwargs):
def label(label, style=None, text_style=None, **kwargs):
if style is None:
style = group_style('label', NoGroupGiven)
if text_style is None:
text_style = get_text_style(style, 'label_text')
text_style = get_text_style(style, group_style('label_text', NoGroupGiven))
window(style=style, **kwargs)
text(label, style=text_style)
@@ -708,10 +744,22 @@ def _bar(*args, **properties):
if "value" in properties:
value = properties.pop("value")
if "style" not in properties:
if isinstance(value, BarValue):
if properties["vertical"]:
style = value.get_style()[1]
else:
style = value.get_style()[0]
if isinstance(style, basestring):
style = group_style(style, NoGroupGiven)
properties["style"] = style
return renpy.display.behavior.Bar(range, value, width, height, **properties)
bar = Wrapper(_bar, style=None, vertical=False, replaces=True)
vbar = Wrapper(_bar, style=None, vertical=True, replaces=True)
bar = Wrapper(_bar, vertical=False, replaces=True)
vbar = Wrapper(_bar, vertical=True, replaces=True)
slider = Wrapper(_bar, style='slider', replaces=True)
vslider = Wrapper(_bar, style='vslider', replaces=True)
scrollbar = Wrapper(_bar, style='scrollbar', replaces=True)
@@ -735,8 +783,8 @@ def _autobar(range, start, end, time, **properties):
return renpy.display.layout.DynamicDisplayable(autobar_interpolate(range, start, end, time, **properties))
autobar = Wrapper(_autobar)
transform = Wrapper(renpy.display.motion.Transform, one=True)
viewport = Wrapper(renpy.display.layout.Viewport, one=True, replaces=True)
transform = Wrapper(renpy.display.motion.Transform, one=True, style='transform')
viewport = Wrapper(renpy.display.layout.Viewport, one=True, replaces=True, style='viewport')
conditional = Wrapper(renpy.display.behavior.Conditional, one=True)
timer = Wrapper(renpy.display.behavior.Timer, replaces=True)
+2
View File
@@ -1,3 +1,4 @@
import inspect
import re
import collections
@@ -80,6 +81,7 @@ hotbar
transform
add
use
has
"""
+7
View File
@@ -146,6 +146,13 @@ Other Changes
* When there are transparent areas on the screen, and
:var:`config.developer` is true, the transparent areas are filled
with a checkerboard pattern.
* The new ``input``, ``side``, ``grid``, and ``fixed`` styles were created,
and the corresponding displayables use them by default.
* When a style is accessed at init-time, and doesn't exist, we divide it
into two parts at the first underscore. If the second part corresponds
to an existing style, we create a new style instead of causing an error.
* The python compiler has been rewritten to use the python ast module.
This should both improve performance, and improve error handling for
+14 -1
View File
@@ -304,6 +304,12 @@ Occasionally Used
If not None, a music file to play when at the game menu.
.. var:: config.gl_test_image = "black"
The name of the image that is used when running the OpenGL
performance test. This image will be shown for 5 frames or .25
seconds, on startup. It will then be automatically hidden.
.. var:: config.has_autosave = True
If true, the game will autosave. If false, no autosaving will
@@ -604,13 +610,20 @@ Rarely or Internally Used
mechanisms. Your file-like object must implement at least the
read, seek, tell, and close methods.
.. var:: config.focus_crossrange_penalty = 1024
This is the amount of penalty to apply to moves perpendicular to
the selected direction of motion, when moving focus with the
keyboard.
.. var:: config.gl_enable = True
Set this to False to disable OpenGL acceleration. OpenGL acceleration
will automatically be disabled if it's determined that the system
cannot support it, so it usually isn't necessary to set this.
OpenGL can also be disabled by holding down shift at startup.
.. var:: config.hard_rollback_limit = 100
This is the number of steps that Ren'Py will let the user
+4
View File
@@ -72,6 +72,9 @@ becomes: ::
There are three groups of UI functions, corresponding to the number
of children they take.
.. When updating this list, be sure to update the documentation for
the layout statement in screens.rst as well.
The following UI functions do not take any children.
* ui.add
@@ -103,6 +106,7 @@ taking children until :func:`ui.close` is called.
* ui.grid
* ui.hbox
* ui.side
* ui.vbox
* ui.imagemap
There are a few UI functions that do not correspond to screen language
+90 -28
View File
@@ -150,14 +150,29 @@ All user interface statements take the following common properties:
given identifier. Some screens will require that a displayable
with a given identifier is created.
By default, the
By default, the id is automatically-generated.
`style`
The name of the style applied to this displayable. This may be a
string name, or a style object. The style gives default
values for style properties.
`group`
Group is used to provide a prefix to the style of a displayable,
for this displayable and all of its children (unless they have a
more specific group set).
For example, if a vbox has a group of ``"pref"``, then the vbox will
have the style ``"pref_vbox"``, unless a more specific style is
supplied to it. A button inside that vbox would default to the
style ``"pref_button"``.
Styles accessed in this way are automatically created, if they do
not exist. This prevents an error from being signalled.
Setting a group of ``None`` disables this behavior for a
displayable and all of its children.
Many user interface statements take classes of style properties, or
transform properties. These properties can have a style prefix
associated with them, that determines when they apply. For example, if
@@ -215,12 +230,13 @@ This does not take children.
::
screen volume_controls:
frame:
vbox:
bar value Preference("sound volume")
bar value Preference("music volume")
bar value Preference("voice volume")
frame:
has vbox
bar value Preference("sound volume")
bar value Preference("music volume")
bar value Preference("voice volume")
Button
------
@@ -471,10 +487,10 @@ This does not take any children.
screen input_screen:
window:
vbox:
spacing 10
text "Enter your name."
input default "Joseph P. Blow, ESQ."
has vbox
text "Enter your name."
input default "Joseph P. Blow, ESQ."
Key
---
@@ -528,10 +544,11 @@ It does not take children.
screen display_preference:
frame:
vbox:
label "Display"
textbutton "Fullscreen" action Preference("display", "fullscreen")
textbutton "Window" action Preference("display", "window")
has vbox
label "Display"
textbutton "Fullscreen" action Preference("display", "fullscreen")
textbutton "Window" action Preference("display", "window")
Null
----
@@ -699,10 +716,11 @@ as `bar`.
screen volume_controls:
frame:
hbox:
vbar value Preference("sound volume")
vbar value Preference("music volume")
vbar value Preference("voice volume")
has hbox
vbar value Preference("sound volume")
vbar value Preference("music volume")
vbar value Preference("voice volume")
Vbox
@@ -934,6 +952,48 @@ function takes:
This does not take children.
Has Statement
=============
The has statment allows you to specify a container to use, instead of
fixed, for statements that take only one child. The has statement
may only be used inside a statement that takes one child. The keyword
``has`` is followed (on the same line) by another statement, which
must be a statement that creates a container displayable, one that
takes more than one child.
The has statement changes the way in which the block that contains
it is parsed. Child displayables created in that block are added to
the container, rather than the parent displayable. Keyword arguments
to the parent displayable are not allowed after the has statement.
The has statement can be supplied as a child of the following
statements:
* button
* frame
* window
The has statement can be given the following statements as a
container.
* fixed
* grid
* hbox
* side
* vbox
::
screen volume_controls:
frame:
has vbox
bar value Preference("sound volume")
bar value Preference("music volume")
bar value Preference("voice volume")
Control Statements
==================
@@ -991,10 +1051,11 @@ occurs.
screen preferences:
frame:
hbox:
text "Display"
textbutton "Fullscreen" action Preferences("display", "fullscreen")
textbutton "Window" action Preferences("display", "window")
has hbox
text "Display"
textbutton "Fullscreen" action Preferences("display", "fullscreen")
textbutton "Window" action Preferences("display", "window")
on "show" action Show("navigation")
on "hide" action Hide("navigation")
@@ -1017,11 +1078,12 @@ values.
button:
action FileAction(slot)
hbox:
add FileScreenshot(slot)
vbox:
text FileTime(slot, empty="Empty Slot.")
text FileSaveName(slot)
has hbox
add FileScreenshot(slot)
vbox:
text FileTime(slot, empty="Empty Slot.")
text FileSaveName(slot)
screen save:
+16 -12
View File
@@ -254,6 +254,22 @@ layout.
Specifies the maximum vertical size of the displayable in pixels.
.. style-property:: xfill boolean
If true, the displayable will expand to fill all available
horizontal space. If not true, it will only be large enough to
contain its children.
This only works for displayables that can change size.
.. style-property:: yfill boolean
If true, the displayable will expand to fill all available
horizontal space. If not true, it will only be large enough to
contain its children.
This only works for displayables that can change size.
.. style-property:: area tuple of (int, int, int, int)
The tuple is interpreted as (`xpos`, `ypos`, `width`,
@@ -502,18 +518,6 @@ buttons.
Sets the minimum height of the window, in pixels.
.. style-property:: xfill boolean
If true, the window will expand to fill all available horizontal
space. If not true, it will only be large enough to contain its
child.
.. style-property:: yfill boolean
If true, the window will expand to fill all available horizontal
space. If not true, it will only be large enough to contain its
child.
.. _button-style-properties:
+4 -4
View File
@@ -1,9 +1,9 @@
executable_name = 'the_question'
documentation_extensions = 'txt html'
description = "A simple and complete Ren'Py game."
build_mac = False
build_mac = True
build_all = True
build_windows = True
distribution_base = 'the_question-1.0'
ignore_extensions = '~ .bak'
build_linux = False
build_all = False
build_linux = True
executable_name = 'the_question'
File diff suppressed because one or more lines are too long