@@ -221,22 +221,22 @@ def rotate(self, angle):
221221
222222color = Color
223223
224- def background (* args ):
224+ def background (* args , ** kwargs ):
225225 """ Sets the current background color.
226226 """
227227 global _background
228228 if args :
229- _background = Color (* args )
229+ _background = Color (* args , ** kwargs )
230230 xywh = (GLint * 4 )(); glGetIntegerv (GL_VIEWPORT , xywh ); x ,y ,w ,h = xywh
231231 rect (x , y , w , h , fill = _background , stroke = None )
232232 return _background
233233
234- def fill (* args ):
234+ def fill (* args , ** kwargs ):
235235 """ Sets the current fill color for drawing primitives and paths.
236236 """
237237 global _fill
238238 if args :
239- _fill = Color (* args )
239+ _fill = Color (* args , ** kwargs )
240240 return _fill
241241
242242fill (0 ) # The default fill is black.
@@ -246,7 +246,7 @@ def stroke(*args, **kwargs):
246246 """
247247 global _stroke
248248 if args :
249- _stroke = Color (* args )
249+ _stroke = Color (* args , ** kwargs )
250250 return _stroke
251251
252252def nofill ():
@@ -442,7 +442,7 @@ def analog(clr, angle=20, d=0.1):
442442 Analogous color schemes can often be found in nature.
443443 """
444444 h , s , b = rgb_to_hsb (* clr [:3 ])
445- h , s , b = rotate_ryb (h , s , b , angle = random (- 1.0 , 1.0 ))
445+ h , s , b = rotate_ryb (h , s , b , angle = random (- angle , angle ))
446446 s *= 1 - random (- d ,d )
447447 b *= 1 - random (- d ,d )
448448 return Color (h , s , b , len (clr )== 4 and clr [3 ] or 1 , colorspace = HSB )
@@ -518,25 +518,27 @@ def pop():
518518 """
519519 glPopMatrix ()
520520
521- def translate (x , y ):
521+ def translate (x , y , z = 0 ):
522522 """ By default, the origin of the layer or canvas is at the bottom left.
523523 This origin point will be moved by (x,y) pixels.
524524 """
525- glTranslatef (round (x ), round (y ), 0 )
525+ glTranslatef (round (x ), round (y ), round ( z ) )
526526
527- def rotate (degrees ):
527+ def rotate (degrees , axis = ( 0 , 0 , 1 ) ):
528528 """ Rotates the transformation state, i.e. all subsequent drawing primitives are rotated.
529529 Rotations work incrementally:
530530 calling rotate(60) and rotate(30) sets the current rotation to 90.
531531 """
532- glRotatef (degrees , 0 , 0 , 1 )
532+ glRotatef (degrees , * axis )
533533
534- def scale (x , y = None ):
534+ def scale (x , y = None , z = None ):
535535 """ Scales the transformation state.
536536 """
537537 if y is None :
538538 y = x
539- glScalef (x , y , 1 )
539+ if z is None :
540+ z = 1
541+ glScalef (x , y , z )
540542
541543def reset ():
542544 """ Resets the transform state of the layer or canvas.
@@ -1240,7 +1242,7 @@ def endpath(draw=True, **kwargs):
12401242def findpath (points , curvature = 1.0 ):
12411243 """ Returns a smooth BezierPath from the given list of (x,y)-tuples.
12421244 """
1243- return bezier .findpath (points , curvature )
1245+ return bezier .findpath (list ( points ) , curvature )
12441246
12451247Path = BezierPath
12461248
@@ -1462,6 +1464,9 @@ def texture(img, data=None):
14621464 # Pixels object, return pixel texture.
14631465 if isinstance (img , Pixels ):
14641466 return img .texture
1467+ # Pyglet image data.
1468+ if isinstance (img , pyglet .image .ImageData ):
1469+ return img .texture
14651470 # Image data as byte string, load it, return texture.
14661471 if isinstance (data , basestring ):
14671472 return pyglet .image .load ("" , file = StringIO (data )).get_texture ()
@@ -2550,9 +2555,9 @@ def on_mouse_drag(self, mouse):
25502555 def on_mouse_scroll (self , mouse ):
25512556 pass
25522557
2553- def on_key_press (self , key ):
2558+ def on_key_press (self , keys ):
25542559 pass
2555- def on_key_release (self , key ):
2560+ def on_key_release (self , keys ):
25562561 pass
25572562
25582563 # Instead of calling an event directly it could be queued,
@@ -3356,41 +3361,55 @@ def __repr__(self):
33563361RIGHT = "right"
33573362
33583363# Key modifiers:
3359- OPTION = \
3360- ALT = "option"
3361- CTRL = "ctrl"
3362- SHIFT = "shift"
3364+ OPTION = \
3365+ ALT = "option"
3366+ CTRL = "ctrl"
3367+ SHIFT = "shift"
3368+ COMMAND = "command"
3369+
3370+ MODIFIERS = (OPTION , CTRL , SHIFT , COMMAND )
33633371
3364- class Key ( object ):
3372+ class Keys ( list ):
33653373
33663374 def __init__ (self , canvas ):
3367- """ Keeps track of the key pressed and any modifiers (e.g. shift or control key).
3375+ """ Keeps track of the keys pressed and any modifiers (e.g. shift or control key).
33683376 """
33693377 self ._canvas = canvas
3370- self ._code = None
3371- self .char = ""
3372- self .modifiers = []
3378+ self .code = None # Last key pressed
3379+ self .char = "" # Last key character representation (i.e., SHIFT + "a" = "A").
3380+ self .modifiers = [] # Modifier keys pressed (OPTION, CTRL, SHIFT, COMMAND).
33733381 self .pressed = False
3374-
3375- def _get_code (self ):
3376- return self ._code
3377- def _set_code (self , v ):
3378- if isinstance (v , int ):
3379- s = pyglet .window .key .symbol_string (v ) # 65288 => "BACKSPACE"
3380- s = s .lower () # "BACKSPACE" => "backspace"
3381- s = s .lstrip ("_" ) # "_1" => "1"
3382- s = s .endswith ((OPTION , CTRL , SHIFT )) and s .lstrip ("lr" ) or s # "lshift" => "shift"
3383- s = s .replace ("return" , ENTER ) # "return" => "enter"
3384- s = s .replace ("num_" , "" ) # "num_space" => "space"
3382+
3383+
3384+ def append (self , code ):
3385+ code = self ._decode (code )
3386+ if code in MODIFIERS :
3387+ self .modifiers .append (code )
3388+ list .append (self , code )
3389+ self .code = self [- 1 ]
3390+
3391+ def remove (self , code ):
3392+ code = self ._decode (code )
3393+ if code in MODIFIERS :
3394+ self .modifiers .remove (code )
3395+ list .remove (self , self ._decode (code ))
3396+ self .code = len (self ) > 0 and self [- 1 ] or None
3397+
3398+ def _decode (self , code ):
3399+ if not isinstance (code , int ):
3400+ s = code
33853401 else :
3386- s = v
3387- self ._code = s
3388-
3389- code = property (_get_code , _set_code )
3390-
3402+ s = pyglet .window .key .symbol_string (code ) # 65288 => "BACKSPACE"
3403+ s = s .lower () # "BACKSPACE" => "backspace"
3404+ s = s .lstrip ("_" ) # "_1" => "1"
3405+ s = s .replace ("return" , ENTER ) # "return" => "enter"
3406+ s = s .replace ("num_" , "" ) # "num_space" => "space"
3407+ s = s .endswith (MODIFIERS ) and s .lstrip ("lr" ) or s # "lshift" => "shift"
3408+ return s
3409+
33913410 def __repr__ (self ):
3392- return "Key (char=%s, code=%s, modifiers=%s, pressed=%s)" % (
3393- repr (self .char ), repr (self . code ), repr (self .modifiers ), repr (self .pressed ))
3411+ return "Keys (char=%s, code=%s, modifiers=%s, pressed=%s)" % (
3412+ repr (self .char ), repr (iter ( self ) ), repr (self .modifiers ), repr (self .pressed ))
33943413
33953414#=====================================================================================================
33963415
@@ -3462,10 +3481,11 @@ def __init__(self, width=640, height=480, name="NodeBox for OpenGL", resizable=F
34623481 self ._window = pyglet .window .Window (** window )
34633482 self ._fps = None # Frames per second.
34643483 self ._frame = 0 # The current frame.
3484+ self ._elapsed = 0 # dt = time elapsed since last frame.
34653485 self ._active = False # Application is running?
34663486 self .paused = False # Pause animation?
34673487 self ._mouse = Mouse (self ) # The mouse cursor location.
3468- self ._key = Key (self ) # The key pressed on the keyboard.
3488+ self ._keys = Keys (self ) # The keys pressed on the keyboard.
34693489 self ._focus = None # The layer being focused by the mouse.
34703490 # Mouse and keyboard events:
34713491 self ._window .on_mouse_enter = self ._on_mouse_enter
@@ -3570,15 +3590,27 @@ def frame(self):
35703590 """
35713591 return self ._frame
35723592
3593+ @property
3594+ def elapsed (self ):
3595+ """ Yields the elapsed time since last frame.
3596+ """
3597+ return self ._elapsed
3598+
3599+ dt = elapsed
3600+
35733601 @property
35743602 def mouse (self ):
35753603 """ Yields a Point(x, y) with the mouse position on the canvas.
35763604 """
35773605 return self ._mouse
3578-
3606+
35793607 @property
3608+ def keys (self ):
3609+ return self ._keys
3610+
3611+ @property # Backwards compatibility.
35803612 def key (self ):
3581- return self ._key
3613+ return self ._keys
35823614
35833615 @property
35843616 def focus (self ):
@@ -3701,34 +3733,28 @@ def _on_mouse_scroll(self, x, y, scroll_x, scroll_y):
37013733 self ._focus .on_mouse_scroll (self ._mouse )
37023734
37033735 def _on_key_press (self , keycode , modifiers ):
3704- self ._key .pressed = True
3705- self ._key .code = keycode
3706- self ._key .modifiers = [a for (a ,b ) in (
3707- (CTRL , pyglet .window .key .MOD_CTRL ),
3708- (SHIFT , pyglet .window .key .MOD_SHIFT ),
3709- (OPTION , pyglet .window .key .MOD_OPTION )) if modifiers & b ]
3710- if self ._key .code == TAB :
3711- self ._key .char = "\t "
3736+ self ._keys .pressed = True
3737+ self ._keys .append (keycode )
3738+ if self ._keys .code == TAB :
3739+ self ._keys .char = "\t "
37123740 # The event is delegated in _update():
37133741 self ._window .on_key_pressed = True
37143742
37153743 def _on_key_release (self , keycode , modifiers ):
37163744 for layer in self :
37173745 layer .on_key_release (self .key )
37183746 self .on_key_release (self .key )
3719- self ._key .char = ""
3720- self ._key .code = None
3721- self ._key .modifiers = []
3722- self ._key .pressed = False
3747+ self ._keys .char = ""
3748+ self ._keys .remove (keycode )
3749+ self ._keys .pressed = False
37233750
37243751 def _on_text (self , text ):
3725- self ._key .char = text
3752+ self ._keys .char = text
37263753 # The event is delegated in _update():
37273754 self ._window .on_key_pressed = True
37283755
37293756 def _on_text_motion (self , keycode ):
3730- self ._key .char = ""
3731- self ._key .code = keycode
3757+ self ._keys .char = ""
37323758 # The event is delegated in _update():
37333759 self ._window .on_key_pressed = True
37343760
@@ -3781,6 +3807,11 @@ def _setup(self):
37813807 # Set the window color, this will be transparent in saved images.
37823808 glClearColor (VERY_LIGHT_GREY , VERY_LIGHT_GREY , VERY_LIGHT_GREY , 0 )
37833809 # Reset the transformation state.
3810+ # Most of this is already taken care of in Pyglet.
3811+ #glMatrixMode(GL_PROJECTION)
3812+ #glLoadIdentity()
3813+ #glOrtho(0, self.width, 0, self.height, -1, 1)
3814+ #glMatrixMode(GL_MODELVIEW)
37843815 glLoadIdentity ()
37853816 # Enable line anti-aliasing.
37863817 glEnable (GL_LINE_SMOOTH )
@@ -3819,6 +3850,7 @@ def _update(self, lapse=0):
38193850 """ Updates the canvas and its layers.
38203851 This method does not actually draw anything, it only updates the state.
38213852 """
3853+ self ._elapsed = lapse
38223854 if not self .paused :
38233855 # Advance the animation by updating all layers.
38243856 # This is only done when the canvas is not paused.
@@ -3831,9 +3863,9 @@ def _update(self, lapse=0):
38313863 # Fire on_key_press() event,
38323864 # which combines _on_key_press(), _on_text() and _on_text_motion().
38333865 self ._window .on_key_pressed = False
3834- self .on_key_press (self ._key )
3866+ self .on_key_press (self ._keys )
38353867 for layer in self :
3836- layer .on_key_press (self ._key )
3868+ layer .on_key_press (self ._keys )
38373869
38383870 def stop (self ):
38393871 # If you override this method, don't forget to call Canvas.stop() to exit the app.
0 commit comments