Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/drawing.py
diff options
context:
space:
mode:
Diffstat (limited to 'drawing.py')
-rw-r--r--drawing.py181
1 files changed, 181 insertions, 0 deletions
diff --git a/drawing.py b/drawing.py
new file mode 100644
index 0000000..2850f4e
--- /dev/null
+++ b/drawing.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2012 Manuel QuiƱones
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+from gettext import gettext as _
+import logging
+
+import gtk
+from gtk import gdk
+import cairo
+
+
+# This prevents the expose callback to draw a large stroke each time:
+STROKE_MAX_POINTS = 80
+
+
+class Drawing(gtk.DrawingArea):
+ def __init__(self, parent):
+ super(Drawing, self).__init__()
+
+ # Communication with the activity, for sharing:
+ self._parent = parent
+
+ # This are temporal points stored while the stroke is being
+ # made. When the stroke is finished (release event) the
+ # stroke is applied to the canvas.
+ self._stroke_points = []
+
+ # Our drawing canvas:
+ self._drawing_canvas = None
+
+ # The settings of our brush:
+ self._settings = {
+ 'stroke color': (1.0, 0.0, 0.0, 0.3),
+ 'stroke width': 8,
+ }
+
+ # Sharing?
+ self.we_are_sharing = False
+
+ # The masks to capture the events we are interested in:
+ self.add_events(gdk.EXPOSURE_MASK | gdk.VISIBILITY_NOTIFY_MASK)
+ self.add_events(gtk.gdk.BUTTON_PRESS_MASK | \
+ gtk.gdk.BUTTON_RELEASE_MASK | \
+ gtk.gdk.BUTTON1_MOTION_MASK)
+
+ # Connect the callbacks:
+ self.connect("expose-event", self._expose_cb)
+ self.connect("button-press-event", self._press_cb)
+ self.connect("motion-notify-event", self._motion_cb)
+ self.connect("button-release-event", self._release_cb)
+
+ def setup(self, width, height):
+ """Setup a blank canvas of specified size."""
+ logging.debug("drawing set up")
+ self._drawing_canvas = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ context = cairo.Context(self._drawing_canvas)
+ context.rectangle(0, 0, width, height)
+ context.set_source_rgb(1.0, 1.0, 1.0)
+ context.fill()
+ self.queue_draw()
+
+ def set_sharing(self, share=True):
+ """Set sharing True or False."""
+ self.we_are_sharing = share
+
+ def get_size(self):
+ """Return the size of the current canvas."""
+ width = self._drawing_canvas.get_width()
+ height = self._drawing_canvas.get_height()
+ return width, height
+
+ def remote_stroke(self, stroke_points):
+ """Draw stroke from other player."""
+ context = cairo.Context(self._drawing_canvas)
+ self._set_stroke_context(context)
+ self._paint_stroke(context, stroke_points)
+ self.queue_draw()
+
+ def clear_drawing_canvas(self):
+ width, height = self.get_size()
+ self.setup(width, height)
+ if self.we_are_sharing:
+ self._parent.send_new_drawing()
+
+ def _set_stroke_context(self, context):
+ """Set the settings of our brush to the Cairo context."""
+ context.set_source_rgba(*self._settings['stroke color'])
+ context.set_line_width(self._settings['stroke width'])
+
+ def _paint_stroke(self, context, stroke_points):
+ """Draw lines from the list of points to the Cairo context"""
+ point_x, point_y = stroke_points[0]
+ context.move_to(point_x, point_y)
+
+ for point_x, point_y in stroke_points[1:]:
+ context.line_to(point_x, point_y)
+
+ context.stroke()
+
+ def _send_stroke_to_drawing_canvas(self, continue_stroke=False):
+ """Paint current stroke in the canvas, clean stroke points."""
+
+ # Return if there is no stroke to paint:
+ if self._stroke_points == []:
+ return
+
+ # Get context from canvas and paint:
+ context = cairo.Context(self._drawing_canvas)
+ self._set_stroke_context(context)
+ self._paint_stroke(context, self._stroke_points)
+
+ if self.we_are_sharing:
+ self._parent.send_stroke(self._stroke_points)
+
+ # Clean the list of points:
+ if continue_stroke:
+ self._stroke_points = self._stroke_points[-1:]
+ else:
+ self._stroke_points = []
+
+ def _press_cb(self, widget, event):
+ mouse_x, mouse_y, state = event.window.get_pointer()
+
+ # We paint pressing the BUTTON1, return otherwise:
+ if not state and gtk.gdk.BUTTON1_MASK:
+ return
+
+ self._stroke_points.append((mouse_x, mouse_y))
+
+ def _motion_cb(self, widget, event):
+ if event.is_hint:
+ mouse_x, mouse_y, state = event.window.get_pointer()
+ else:
+ mouse_x = event.x
+ mouse_y = event.y
+ state = event.state
+
+ # We paint pressing the BUTTON1, return otherwise:
+ if not state and gtk.gdk.BUTTON1_MASK:
+ return
+
+ # Paint stroke in canvas if it gets too big:
+ if len(self._stroke_points) > STROKE_MAX_POINTS:
+ self._send_stroke_to_drawing_canvas(continue_stroke=True)
+
+ self._stroke_points.append((mouse_x, mouse_y))
+ self.queue_draw()
+
+ def _release_cb(self, widget, event):
+ self._send_stroke_to_drawing_canvas()
+
+ def _expose_cb(self, widget, event):
+ context = self.window.cairo_create()
+
+ # Paint the canvas in the widget:
+ context.set_source_surface(self._drawing_canvas)
+ context.paint()
+
+ # Return if there is no stroke to paint:
+ if self._stroke_points == []:
+ return
+
+ # Get context from widget and paint:
+ self._set_stroke_context(context)
+ self._paint_stroke(context, self._stroke_points)