1616
1717from ._frontend import module_name , module_version
1818
19- from .utils import binary_image , populate_args , image_bytes_to_array
19+ from .utils import binary_image , populate_args , image_bytes_to_array , commands_to_buffer
2020
2121COMMANDS = {
2222 'fillRect' : 0 , 'strokeRect' : 1 , 'fillRects' : 2 , 'strokeRects' : 3 , 'clearRect' : 4 , 'fillArc' : 5 ,
@@ -259,14 +259,14 @@ def fill_rect(self, x, y, width, height=None):
259259 if height is None :
260260 height = width
261261
262- self ._send_canvas_command (COMMANDS ['fillRect' ], ( x , y , width , height ) )
262+ self ._send_canvas_command (COMMANDS ['fillRect' ], [ x , y , width , height ] )
263263
264264 def stroke_rect (self , x , y , width , height = None ):
265265 """Draw a rectangular outline of size ``(width, height)`` at the ``(x, y)`` position."""
266266 if height is None :
267267 height = width
268268
269- self ._send_canvas_command (COMMANDS ['strokeRect' ], ( x , y , width , height ) )
269+ self ._send_canvas_command (COMMANDS ['strokeRect' ], [ x , y , width , height ] )
270270
271271 def fill_rects (self , x , y , width , height = None ):
272272 """Draw filled rectangles of sizes ``(width, height)`` at the ``(x, y)`` positions.
@@ -313,24 +313,24 @@ def clear_rect(self, x, y, width, height=None):
313313 if height is None :
314314 height = width
315315
316- self ._send_canvas_command (COMMANDS ['clearRect' ], ( x , y , width , height ) )
316+ self ._send_canvas_command (COMMANDS ['clearRect' ], [ x , y , width , height ] )
317317
318318 # Arc methods
319319 def fill_arc (self , x , y , radius , start_angle , end_angle , anticlockwise = False ):
320320 """Draw a filled arc centered at ``(x, y)`` with a radius of ``radius`` from ``start_angle`` to ``end_angle``."""
321- self ._send_canvas_command (COMMANDS ['fillArc' ], ( x , y , radius , start_angle , end_angle , anticlockwise ) )
321+ self ._send_canvas_command (COMMANDS ['fillArc' ], [ x , y , radius , start_angle , end_angle , anticlockwise ] )
322322
323323 def fill_circle (self , x , y , radius ):
324324 """Draw a filled circle centered at ``(x, y)`` with a radius of ``radius``."""
325- self ._send_canvas_command (COMMANDS ['fillCircle' ], ( x , y , radius ) )
325+ self ._send_canvas_command (COMMANDS ['fillCircle' ], [ x , y , radius ] )
326326
327327 def stroke_arc (self , x , y , radius , start_angle , end_angle , anticlockwise = False ):
328328 """Draw an arc outline centered at ``(x, y)`` with a radius of ``radius``."""
329- self ._send_canvas_command (COMMANDS ['strokeArc' ], ( x , y , radius , start_angle , end_angle , anticlockwise ) )
329+ self ._send_canvas_command (COMMANDS ['strokeArc' ], [ x , y , radius , start_angle , end_angle , anticlockwise ] )
330330
331331 def stroke_circle (self , x , y , radius ):
332332 """Draw a circle centered at ``(x, y)`` with a radius of ``radius``."""
333- self ._send_canvas_command (COMMANDS ['strokeCircle' ], ( x , y , radius ) )
333+ self ._send_canvas_command (COMMANDS ['strokeCircle' ], [ x , y , radius ] )
334334
335335 def fill_arcs (self , x , y , radius , start_angle , end_angle , anticlockwise = False ):
336336 """Draw filled arcs centered at ``(x, y)`` with a radius of ``radius``.
@@ -397,7 +397,7 @@ def stroke_circles(self, x, y, radius):
397397 # Lines methods
398398 def stroke_line (self , x1 , y1 , x2 , y2 ):
399399 """Draw a line from ``(x1, y1)`` to ``(x2, y2)``."""
400- self ._send_canvas_command (COMMANDS ['strokeLine' ], ( x1 , y1 , x2 , y2 ) )
400+ self ._send_canvas_command (COMMANDS ['strokeLine' ], [ x1 , y1 , x2 , y2 ] )
401401
402402 # Paths methods
403403 def begin_path (self ):
@@ -422,48 +422,48 @@ def fill(self, rule_or_path='nonzero'):
422422 Possible rules are ``nonzero`` and ``evenodd``.
423423 """
424424 if isinstance (rule_or_path , Path2D ):
425- self ._send_canvas_command (COMMANDS ['fillPath' ], ( widget_serialization ['to_json' ](rule_or_path , None ), ) )
425+ self ._send_canvas_command (COMMANDS ['fillPath' ], [ widget_serialization ['to_json' ](rule_or_path , None )] )
426426 else :
427- self ._send_canvas_command (COMMANDS ['fill' ], ( rule_or_path , ) )
427+ self ._send_canvas_command (COMMANDS ['fill' ], [ rule_or_path ] )
428428
429429 def move_to (self , x , y ):
430430 """Move the "pen" to the given ``(x, y)`` coordinates."""
431- self ._send_canvas_command (COMMANDS ['moveTo' ], ( x , y ) )
431+ self ._send_canvas_command (COMMANDS ['moveTo' ], [ x , y ] )
432432
433433 def line_to (self , x , y ):
434434 """Add a straight line to the current path by connecting the path's last point to the specified ``(x, y)`` coordinates.
435435
436436 Like other methods that modify the current path, this method does not directly render anything. To
437437 draw the path onto the canvas, you can use the fill() or stroke() methods.
438438 """
439- self ._send_canvas_command (COMMANDS ['lineTo' ], ( x , y ) )
439+ self ._send_canvas_command (COMMANDS ['lineTo' ], [ x , y ] )
440440
441441 def rect (self , x , y , width , height ):
442442 """Add a rectangle of size ``(width, height)`` at the ``(x, y)`` position in the current path."""
443- self ._send_canvas_command (COMMANDS ['rect' ], ( x , y , width , height ) )
443+ self ._send_canvas_command (COMMANDS ['rect' ], [ x , y , width , height ] )
444444
445445 def arc (self , x , y , radius , start_angle , end_angle , anticlockwise = False ):
446446 """Add a circular arc centered at ``(x, y)`` with a radius of ``radius`` to the current path.
447447
448448 The path starts at ``start_angle`` and ends at ``end_angle``, and travels in the direction given by
449449 ``anticlockwise`` (defaulting to clockwise: ``False``).
450450 """
451- self ._send_canvas_command (COMMANDS ['arc' ], ( x , y , radius , start_angle , end_angle , anticlockwise ) )
451+ self ._send_canvas_command (COMMANDS ['arc' ], [ x , y , radius , start_angle , end_angle , anticlockwise ] )
452452
453453 def ellipse (self , x , y , radius_x , radius_y , rotation , start_angle , end_angle , anticlockwise = False ):
454454 """Add an ellipse centered at ``(x, y)`` with the radii ``radius_x`` and ``radius_y`` to the current path.
455455
456456 The path starts at ``start_angle`` and ends at ``end_angle``, and travels in the direction given by
457457 ``anticlockwise`` (defaulting to clockwise: ``False``).
458458 """
459- self ._send_canvas_command (COMMANDS ['ellipse' ], ( x , y , radius_x , radius_y , rotation , start_angle , end_angle , anticlockwise ) )
459+ self ._send_canvas_command (COMMANDS ['ellipse' ], [ x , y , radius_x , radius_y , rotation , start_angle , end_angle , anticlockwise ] )
460460
461461 def arc_to (self , x1 , y1 , x2 , y2 , radius ):
462462 """Add a circular arc to the current path.
463463
464464 Using the given control points ``(x1, y1)`` and ``(x2, y2)`` and the ``radius``.
465465 """
466- self ._send_canvas_command (COMMANDS ['arcTo' ], ( x1 , y1 , x2 , y2 , radius ) )
466+ self ._send_canvas_command (COMMANDS ['arcTo' ], [ x1 , y1 , x2 , y2 , radius ] )
467467
468468 def quadratic_curve_to (self , cp1x , cp1y , x , y ):
469469 """Add a quadratic Bezier curve to the current path.
@@ -472,7 +472,7 @@ def quadratic_curve_to(self, cp1x, cp1y, x, y):
472472 The starting point is the latest point in the current path, which can be changed using move_to()
473473 before creating the quadratic Bezier curve.
474474 """
475- self ._send_canvas_command (COMMANDS ['quadraticCurveTo' ], ( cp1x , cp1y , x , y ) )
475+ self ._send_canvas_command (COMMANDS ['quadraticCurveTo' ], [ cp1x , cp1y , x , y ] )
476476
477477 def bezier_curve_to (self , cp1x , cp1y , cp2x , cp2y , x , y ):
478478 """Add a cubic Bezier curve to the current path.
@@ -481,16 +481,16 @@ def bezier_curve_to(self, cp1x, cp1y, cp2x, cp2y, x, y):
481481 The starting point is the latest point in the current path, which can be changed using move_to()
482482 before creating the Bezier curve.
483483 """
484- self ._send_canvas_command (COMMANDS ['bezierCurveTo' ], ( cp1x , cp1y , cp2x , cp2y , x , y ) )
484+ self ._send_canvas_command (COMMANDS ['bezierCurveTo' ], [ cp1x , cp1y , cp2x , cp2y , x , y ] )
485485
486486 # Text methods
487487 def fill_text (self , text , x , y , max_width = None ):
488488 """Fill a given text at the given ``(x, y)`` position. Optionally with a maximum width to draw."""
489- self ._send_canvas_command (COMMANDS ['fillText' ], ( text , x , y , max_width ) )
489+ self ._send_canvas_command (COMMANDS ['fillText' ], [ text , x , y , max_width ] )
490490
491491 def stroke_text (self , text , x , y , max_width = None ):
492492 """Stroke a given text at the given ``(x, y)`` position. Optionally with a maximum width to draw."""
493- self ._send_canvas_command (COMMANDS ['strokeText' ], ( text , x , y , max_width ) )
493+ self ._send_canvas_command (COMMANDS ['strokeText' ], [ text , x , y , max_width ] )
494494
495495 # Line methods
496496 def get_line_dash (self ):
@@ -503,7 +503,7 @@ def set_line_dash(self, segments):
503503 self ._line_dash = segments + segments
504504 else :
505505 self ._line_dash = segments
506- self ._send_canvas_command (COMMANDS ['setLineDash' ], ( self ._line_dash , ) )
506+ self ._send_canvas_command (COMMANDS ['setLineDash' ], [ self ._line_dash ] )
507507
508508 # Image methods
509509 def draw_image (self , image , x = 0 , y = 0 , width = None , height = None ):
@@ -516,7 +516,7 @@ def draw_image(self, image, x=0, y=0, width=None, height=None):
516516
517517 serialized_image = widget_serialization ['to_json' ](image , None )
518518
519- self ._send_canvas_command (COMMANDS ['drawImage' ], ( serialized_image , x , y , width , height ) )
519+ self ._send_canvas_command (COMMANDS ['drawImage' ], [ serialized_image , x , y , width , height ] )
520520
521521 def put_image_data (self , image_data , x = 0 , y = 0 ):
522522 """Draw an image on the Canvas.
@@ -526,7 +526,7 @@ def put_image_data(self, image_data, x=0, y=0):
526526 matrix, and supports transparency.
527527 """
528528 image_metadata , image_buffer = binary_image (image_data )
529- self ._send_canvas_command (COMMANDS ['putImageData' ], ( image_metadata , x , y ), ( image_buffer , ) )
529+ self ._send_canvas_command (COMMANDS ['putImageData' ], [ image_metadata , x , y ], [ image_buffer ] )
530530
531531 def create_image_data (self , width , height ):
532532 """Create a NumPy array of shape (width, height, 4) representing a table of pixel colors."""
@@ -556,11 +556,11 @@ def translate(self, x, y):
556556 ``x`` indicates the horizontal distance to move,
557557 and ``y`` indicates how far to move the grid vertically.
558558 """
559- self ._send_canvas_command (COMMANDS ['translate' ], ( x , y ) )
559+ self ._send_canvas_command (COMMANDS ['translate' ], [ x , y ] )
560560
561561 def rotate (self , angle ):
562562 """Rotate the canvas clockwise around the current origin by the ``angle`` number of radians."""
563- self ._send_canvas_command (COMMANDS ['rotate' ], ( angle , ) )
563+ self ._send_canvas_command (COMMANDS ['rotate' ], [ angle ] )
564564
565565 def scale (self , x , y = None ):
566566 """Scale the canvas units by ``x`` horizontally and by ``y`` vertically. Both parameters are real numbers.
@@ -571,22 +571,22 @@ def scale(self, x, y=None):
571571 """
572572 if y is None :
573573 y = x
574- self ._send_canvas_command (COMMANDS ['scale' ], ( x , y ) )
574+ self ._send_canvas_command (COMMANDS ['scale' ], [ x , y ] )
575575
576576 def transform (self , a , b , c , d , e , f ):
577577 """Multiply the current transformation matrix with the matrix described by its arguments.
578578
579579 The transformation matrix is described by:
580580 ``[[a, c, e], [b, d, f], [0, 0, 1]]``.
581581 """
582- self ._send_canvas_command (COMMANDS ['transform' ], ( a , b , c , d , e , f ) )
582+ self ._send_canvas_command (COMMANDS ['transform' ], [ a , b , c , d , e , f ] )
583583
584584 def set_transform (self , a , b , c , d , e , f ):
585585 """Reset the current transform to the identity matrix, and then invokes the transform() method with the same arguments.
586586
587587 This basically undoes the current transformation, then sets the specified transform, all in one step.
588588 """
589- self ._send_canvas_command (COMMANDS ['setTransform' ], ( a , b , c , d , e , f ) )
589+ self ._send_canvas_command (COMMANDS ['setTransform' ], [ a , b , c , d , e , f ] )
590590
591591 def reset_transform (self ):
592592 """Reset the current transform to the identity matrix.
@@ -605,7 +605,7 @@ def flush(self):
605605 if not self .caching or not len (self ._commands_cache ):
606606 return
607607
608- self .send (self ._commands_cache , self ._buffers_cache )
608+ self ._send_custom (self ._commands_cache , self ._buffers_cache )
609609
610610 self ._commands_cache = []
611611 self ._buffers_cache = []
@@ -660,22 +660,20 @@ def __setattr__(self, name, value):
660660 self ._send_command ([COMMANDS ['set' ], [self .ATTRS [name ], value ]])
661661
662662 def _send_canvas_command (self , name , args = [], buffers = []):
663- command = [name ]
664-
665- if len (args ):
666- command .append ([arg for arg in args if arg is not None ])
667-
668- if len (buffers ):
669- command .append (len (buffers ))
670-
671- self ._send_command (command , buffers )
663+ while len (args ) and args [len (args ) - 1 ] is None :
664+ args .pop ()
665+ self ._send_command ([name , args , len (buffers )], buffers )
672666
673667 def _send_command (self , command , buffers = []):
674668 if self .caching :
675669 self ._commands_cache .append (command )
676670 self ._buffers_cache += buffers
677671 else :
678- self .send (command , buffers )
672+ self ._send_custom (command , buffers )
673+
674+ def _send_custom (self , command , buffers = []):
675+ metadata , command_buffer = commands_to_buffer (command )
676+ self .send (metadata , buffers = [command_buffer ] + buffers )
679677
680678 def _handle_frontend_event (self , _ , content , buffers ):
681679 if content .get ('event' , '' ) == 'client_ready' :
0 commit comments