Skip to content

Commit c199171

Browse files
author
Tom De Smedt
committed
Canvas.key changed to Canvas.keys
- ! Canvas.keys instead of Canvas.key - analog() bug fix - Canvas.elapsed (dt)
1 parent 45b6de3 commit c199171

File tree

2 files changed

+113
-81
lines changed

2 files changed

+113
-81
lines changed

nodebox/graphics/context.py

Lines changed: 94 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -221,22 +221,22 @@ def rotate(self, angle):
221221

222222
color = 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

242242
fill(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

252252
def 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

541543
def reset():
542544
""" Resets the transform state of the layer or canvas.
@@ -1240,7 +1242,7 @@ def endpath(draw=True, **kwargs):
12401242
def 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

12451247
Path = 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):
33563361
RIGHT = "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

Comments
 (0)