Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGonzalo Odiard <godiard@gmail.com>2012-06-28 14:39:08 (GMT)
committer Gonzalo Odiard <godiard@gmail.com>2012-08-10 13:49:29 (GMT)
commit16c5b2406cac683eb7009ae84f0c6a4db36cf7c7 (patch)
tree5ec963b75f2d865e9a9a33fcffee5b475898bef5
parent6d884b54e61a4b9eaa0429fac0695bfee7d3b811 (diff)
First stage of port of Paint to cairo
Brushes and shapes are working. NOTES: * The pixmaps used as canvas has been replaced by ImageSurface and cairo context. * All the gc with tool properties were removed. * The variables needed by the freeform and rainbow were moved from Area to Desenha * The freeform code was simplified. * The heart is draw using cairo curves and is a little different than before. * I am using cairo_stroke_color and cairo_fill_color values in the tool dict to enable compatibility while the port is done, later will be unified. I am setting this color with a fixed alpha of 0.3 to display artifacts if we want enable alpha in the future. It's only for test at this stage. * The code used to display the polygons (triangle, trapezoid, arrow, paralellogram, star, polygon_regular) was simplified calling a method _draw_polygon witha array of points. PENDING: * All the clipboard operations. * All the efects. * Text * Bucket * Stamps
-rw-r--r--Area.py362
-rw-r--r--Desenho.py592
-rw-r--r--OficinaActivity.py20
-rw-r--r--toolbox.py12
4 files changed, 416 insertions, 570 deletions
diff --git a/Area.py b/Area.py
index a81cda3..f5b9511 100644
--- a/Area.py
+++ b/Area.py
@@ -69,6 +69,7 @@ import os
import tempfile
import math
import pango
+import cairo
from Desenho import Desenho
from urlparse import urlparse
@@ -130,7 +131,7 @@ class Area(gtk.DrawingArea):
gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
self.connect('drag_data_received', self.drag_data_received)
- self.set_flags(gtk.CAN_FOCUS)
+ self.set_can_focus(True)
self.grab_focus()
self.set_extension_events(gtk.gdk.EXTENSION_EVENTS_CURSOR)
@@ -147,13 +148,15 @@ class Area(gtk.DrawingArea):
## - 'vertices' : a integer
## All values migth be None, execept in 'name' key.
self.tool = {
- 'name': 'pencil',
+ 'name': 'brush',
'line size': 4,
'stamp size': self._get_stamp_size(),
'fill color': None,
'stroke color': None,
'line shape': 'circle',
'fill': True,
+ 'cairo_stroke_color': (0.0, 0.0, 0.0, 0.3),
+ 'cairo_fill_color': (0.0, 0.0, 0.0, 0.3),
'vertices': 6.0}
self.desenha = False
@@ -161,24 +164,12 @@ class Area(gtk.DrawingArea):
self.sel_get_out = False
self.oldx = 0
self.oldy = 0
- self.polygon_start = True
- self.points = []
- self.gc = None
- self.gc_rainbow = None
- self.gc_line = None
- self.gc_eraser = None
- self.gc_brush = None
- self.gc_selection = None
- self.pixmap = None
- self.pixmap_temp = None
- self.pixmap_sel = None
- self.desenho = []
+ self.drawing_canvas = None
self.textos = []
self.text_in_progress = False
self.activity = activity
self.d = Desenho(self)
self.last = []
- self.rainbow_counter = 0
self.keep_aspect_ratio = False
self.keep_shape_ratio = False
@@ -186,7 +177,7 @@ class Area(gtk.DrawingArea):
self.font_description.set_family('Sans')
self.font_description.set_size(12)
- self._set_selection_bounds(0, 0, 0, 0)
+ self.set_selection_bounds(0, 0, 0, 0)
# List of pixmaps for the Undo function:
self._undo_list = []
@@ -201,57 +192,32 @@ class Area(gtk.DrawingArea):
"""Set the stamp initial size, based on the display DPI."""
return zoom(44)
+ def load_from_file(self, file_path):
+ self.drawing_canvas = cairo.ImageSurface.create_from_png(file_path)
+
def setup(self, width, height):
"""Configure the Area object."""
- if self.pixmap:
- # Already set up
- return
-
logging.debug('Area.setup: w=%s h=%s' % (width, height))
win = self.window
self.set_size_request(width, height)
- ##It is the main pixmap, who is display most of the time.
- self.pixmap = gtk.gdk.Pixmap(win, width, height, -1)
- self.pixmap.draw_rectangle(self.get_style().white_gc, True,
- 0, 0, width, height)
- ##This pixmap is showed when we need show something and not draw it.
- self.pixmap_temp = gtk.gdk.Pixmap(win, width, height, -1)
- self.pixmap_temp.draw_rectangle(self.get_style().white_gc, True,
- 0, 0, width, height)
-
- ##When something is selected this pixmap draw and rectangular box
- # out of the selection
- #self.pixmap_sel = gtk.gdk.Pixmap(win, width, height, -1)
- #self.pixmap_sel.draw_rectangle(self.get_style().white_gc, True,
- # 0, 0, width, height)
-
- self.gc = win.new_gc()
- self.gc_eraser = win.new_gc()
- colormap = self.get_colormap()
- self.white = colormap.alloc_color('#ffffff', True, True) # white
- self.black = colormap.alloc_color('#000000', True, True) # black
-
- self.gc_eraser.set_foreground(self.white)
- self.gc_rainbow = win.new_gc()
-
- self.gc_brush = win.new_gc()
- self.gc_brush.set_foreground(self.black)
-
- self.gc_line = win.new_gc()
-
- self.gc_selection = win.new_gc()
- self.gc_selection.set_line_attributes(1, gtk.gdk.LINE_ON_OFF_DASH,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
- self.gc_selection.set_foreground(self.black)
-
- #this make another white line out of the black line
- self.gc_selection1 = win.new_gc()
- self.gc_selection1.set_line_attributes(1, gtk.gdk.LINE_ON_OFF_DASH,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
- self.gc_selection1.set_foreground(self.white)
+ ##It is the main canvas, who is display most of the time
+ # if is not None was read from a file
+ if self.drawing_canvas is None:
+ self.drawing_canvas = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ self.drawing_ctx = cairo.Context(self.drawing_canvas)
+ # paint background white
+ self.drawing_ctx.rectangle(0, 0, width, height)
+ self.drawing_ctx.set_source_rgb(1.0, 1.0, 1.0)
+ self.drawing_ctx.fill()
+ else:
+ self.drawing_ctx = cairo.Context(self.drawing_canvas)
+
+ ##This canvas is showed when we need show something and not draw it.
+ self._init_temp_canvas(width, height)
self.enableUndo(self, size=(width, height))
@@ -260,6 +226,31 @@ class Area(gtk.DrawingArea):
return True
+ def _init_temp_canvas(self, width, height):
+ self.temp_canvas = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ self.temp_ctx = cairo.Context(self.temp_canvas)
+ self.temp_ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
+ self.temp_ctx.rectangle(0, 0, width, height)
+ self.temp_ctx.fill()
+ self.temp_ctx.set_source_surface(self.drawing_canvas)
+ self.temp_ctx.paint()
+
+ def display_selection_border(self, ctx):
+ x, y, x2, y2 = self.get_selection_bounds()
+ if (x, y, x2, y2) == (0, 0, 0, 0):
+ return
+
+ ctx.save()
+ ctx.set_line_width(1)
+ ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+ ctx.set_line_join(cairo.LINE_JOIN_ROUND)
+ ctx.set_dash([5, 5], 0)
+ ctx.set_source_rgba(0., 0., 0., 1.)
+ ctx.rectangle(x, y, x2, y2)
+ ctx.stroke()
+ ctx.restore()
+
def configure_line(self, size):
"""Configure the new line's size.
@@ -267,11 +258,12 @@ class Area(gtk.DrawingArea):
@param size -- the size of the new line
"""
- self.gc_line.set_line_attributes(size, gtk.gdk.LINE_SOLID,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
+ self.drawing_ctx.set_line_width(size)
+ self.drawing_ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+ self.drawing_ctx.set_line_join(cairo.LINE_JOIN_ROUND)
def expose(self, widget, event):
- """ This function define which pixmap will be showed to the user.
+ """ This function define which canvas will be showed to the user.
Show up the Area object (GtkDrawingArea).
@param self -- the Area object (GtkDrawingArea)
@@ -280,41 +272,58 @@ class Area(gtk.DrawingArea):
"""
area = event.area
+ #logging.error('expose area %s', area)
+ width, height = self.window.get_size()
+
+ context = self.window.cairo_create()
+
if self.desenha or self.selmove:
- widget.window.draw_drawable(self.gc, self.pixmap_temp,
- area[0], area[1], area[0], area[1], area[2], area[3])
+ # Paint the canvas in the widget:
+ # TODO: clipping
+ context.set_source_surface(self.temp_canvas)
+ context.paint()
else:
- widget.window.draw_drawable(self.gc, self.pixmap,
- area[0], area[1], area[0], area[1], area[2], area[3])
- self.show_tool_shape(widget)
- return False
-
- def show_tool_shape(self, widget):
+ # TODO: clipping
+ context.set_source_surface(self.drawing_canvas)
+ context.paint()
+ self.show_tool_shape(context)
+ self._init_temp_canvas(width, height)
+ self.display_selection_border(context)
+
+ def show_tool_shape(self, context):
"""
Show the shape of the tool selected for pencil, brush,
rainbow and eraser
"""
if self.tool['name'] in ['pencil', 'eraser', 'brush', 'rainbow',
'stamp']:
+ context.set_source_rgba(*self.tool['cairo_stroke_color'])
+ context.set_line_width(1)
if not self.drawing:
# draw stamp border in widget.window
if self.tool['name'] == 'stamp':
wr, hr = self.stamp_dimentions
- widget.window.draw_rectangle(self.gc_brush, False,
- self.x_cursor - wr / 2, self.y_cursor - hr / 2,
- wr, hr)
+ context.rectangle(self.x_cursor - wr / 2,
+ self.y_cursor - hr / 2, wr, hr)
+ # TODO: stroke style
+ context.stroke()
# draw shape of the brush, square or circle
elif self.tool['line shape'] == 'circle':
size = self.tool['line size']
- widget.window.draw_arc(self.gc_brush, False,
- self.x_cursor - size / 2, self.y_cursor - size / 2,
- size, size, 0, 360 * 64)
+ context.move_to(self.x_cursor,
+ self.y_cursor)
+ context.arc(self.x_cursor,
+ self.y_cursor, size / 2, 0.,
+ 2 * math.pi)
+ context.stroke()
else:
size = self.tool['line size']
- widget.window.draw_rectangle(self.gc_brush, False,
- self.x_cursor - size / 2, self.y_cursor - size / 2,
- size, size)
+ context.move_to(self.x_cursor - size / 2,
+ self.y_cursor - size / 2)
+ context.rectangle(self.x_cursor - size / 2,
+ self.y_cursor - size / 2, size, size)
+ context.stroke()
def mousedown(self, widget, event):
"""Make the Area object (GtkDrawingArea) recognize
@@ -350,9 +359,6 @@ class Area(gtk.DrawingArea):
self.oldx, self.oldy = coords
- if self.polygon_start is False and self.tool['name'] is not 'freeform':
- self.d.polygon(widget, coords, False, self.tool['fill'], "bug")
-
x, y, state = event.window.get_pointer()
if self.tool['name'] == 'picker':
@@ -366,33 +372,29 @@ class Area(gtk.DrawingArea):
#Handle with the left button click event.
if self.tool['name'] == 'eraser':
self.last = []
- self.d.eraser(widget, coords, self.last,
- self.tool['line size'], self.tool['line shape'])
+ self.d.eraser(widget, coords, self.last)
self.last = coords
self.drawing = True
elif self.tool['name'] == 'brush':
self.last = []
- self.d.brush(widget, coords, self.last, self.tool['line size'],
- self.tool['line shape'])
+ self.d.brush(widget, coords, self.last)
self.last = coords
self.drawing = True
elif self.tool['name'] == 'stamp':
self.last = []
- self.d.stamp(widget, coords, self.last,
- self.tool['stamp size'])
+ self.d.stamp(widget, coords, self.last)
self.last = coords
self.drawing = True
elif self.tool['name'] == 'rainbow':
self.last = []
- self.d.rainbow(widget, coords, self.last,
- self.rainbow_counter, self.tool['line size'],
- self.tool['line shape'])
+ self.d.rainbow(widget, coords, self.last)
self.last = coords
self.drawing = True
elif self.tool['name'] == 'freeform':
+ logging.error('mousedown')
self.configure_line(self.tool['line size'])
- if self.polygon_start == False:
- self.desenha = True
+ self.d.freeform(widget, coords, True,
+ self.tool['fill'], "motion")
if self.selmove:
#get out of the func selection
if self.tool['name'] != 'marquee-rectangular':
@@ -408,8 +410,10 @@ class Area(gtk.DrawingArea):
(coords[1] < yi) or (coords[1] > yf):
self.sel_get_out = True
else:
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap,
- 0, 0, 0, 0, width, height)
+ self.temp_ctx.set_source_surface(self.drawing_canvas, 0, 0)
+ self.temp_ctx.rectangle(0, 0, width, height)
+ self.temp_ctx.paint()
+
self.desenha = True
widget.queue_draw()
@@ -436,20 +440,13 @@ class Area(gtk.DrawingArea):
elif self.tool['name'] == 'line':
coords = self._keep_line_ratio(coords)
- if state & gtk.gdk.BUTTON1_MASK and self.pixmap != None:
- if self.tool['name'] == 'pencil':
- self.d.brush(widget, coords, self.last,
- self.tool['line size'], self.tool['line shape'])
- self.last = coords
-
- elif self.tool['name'] == 'eraser':
- self.d.eraser(widget, coords, self.last,
- self.tool['line size'], self.tool['line shape'])
+ if state & gtk.gdk.BUTTON1_MASK:
+ if self.tool['name'] == 'eraser':
+ self.d.eraser(widget, coords, self.last)
self.last = coords
elif self.tool['name'] == 'brush':
- self.d.brush(widget, coords, self.last,
- self.tool['line size'], self.tool['line shape'])
+ self.d.brush(widget, coords, self.last)
self.last = coords
elif self.tool['name'] == 'stamp':
@@ -458,25 +455,17 @@ class Area(gtk.DrawingArea):
self.last = coords
elif self.tool['name'] == 'rainbow':
- self.d.rainbow(widget, coords, self.last,
- self.rainbow_counter, self.tool['line size'],
- self.tool['line shape'])
- self.rainbow_counter += 1
- if self.rainbow_counter > 11:
- self.rainbow_counter = 0
+ self.d.rainbow(widget, coords, self.last)
self.last = coords
if self.desenha:
if self.tool['name'] == 'line':
- self.configure_line(self.tool['line size'])
- self.d.line(widget, coords)
+ self.d.line(widget, coords, True)
elif self.tool['name'] == 'ellipse':
- self.configure_line(self.tool['line size'])
self.d.circle(widget, coords, True, self.tool['fill'])
elif self.tool['name'] == 'rectangle':
- self.configure_line(self.tool['line size'])
self.d.square(widget, event, coords, True,
self.tool['fill'])
@@ -493,52 +482,44 @@ class Area(gtk.DrawingArea):
self.d.moveSelection(widget, coords)
elif self.tool['name'] == 'freeform':
+ logging.error('mousemove')
self.configure_line(self.tool['line size'])
- self.d.polygon(widget, coords, True,
+ self.d.freeform(widget, coords, True,
self.tool['fill'], "motion")
elif self.tool['name'] == 'triangle':
- self.configure_line(self.tool['line size'])
self.d.triangle(widget, coords, True, self.tool['fill'])
elif self.tool['name'] == 'trapezoid':
- self.configure_line(self.tool['line size'])
self.d.trapezoid(widget, coords, True, self.tool['fill'])
elif self.tool['name'] == 'arrow':
- self.configure_line(self.tool['line size'])
self.d.arrow(widget, coords, True, self.tool['fill'])
elif self.tool['name'] == 'parallelogram':
- self.configure_line(self.tool['line size'])
self.d.parallelogram(widget, coords, True,
self.tool['fill'])
elif self.tool['name'] == 'star':
- self.configure_line(self.tool['line size'])
self.d.star(widget, coords, self.tool['vertices'],
True, self.tool['fill'])
elif self.tool['name'] == 'polygon_regular':
- self.configure_line(self.tool['line size'])
self.d.polygon_regular(widget, coords,
self.tool['vertices'], True, self.tool['fill'])
elif self.tool['name'] == 'heart':
- self.configure_line(self.tool['line size'])
self.d.heart(widget, coords, True, self.tool['fill'])
else:
if self.tool['name'] in ['brush', 'eraser', 'rainbow', 'pencil',
'stamp']:
widget.queue_draw()
if self.tool['name'] == 'marquee-rectangular' and self.selmove:
- size = self.pixmap_sel.get_size()
- xi = self.orig_x
- yi = self.orig_y
- xf = xi + size[0]
- yf = yi + size[1]
- if (coords[0] < xi) or (coords[0] > xf) or \
- (coords[1] < yi) or (coords[1] > yf):
+ sel_x, sel_y, sel_width, sel_height = \
+ self.get_selection_bounds()
+
+ if (coords[0] < sel_x) or (coords[0] > sel_x + sel_width) or \
+ (coords[1] < sel_y) or (coords[1] > sel_y + sel_height):
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
else:
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
@@ -546,7 +527,7 @@ class Area(gtk.DrawingArea):
elif self.tool['name'] == 'freeform' and not self.selmove:
self.desenha = True
self.configure_line(self.tool['line size'])
- self.d.polygon(widget, coords, True,
+ self.d.freeform(widget, coords, True,
self.tool['fill'], "moving")
gtk.gdk.event_request_motions(event)
@@ -573,9 +554,7 @@ class Area(gtk.DrawingArea):
private_undo = False
if self.desenha or self.sel_get_out:
if self.tool['name'] == 'line':
- self.pixmap.draw_line(self.gc_line, self.oldx, self.oldy,
- coords[0], coords[1])
- widget.queue_draw()
+ self.d.line(widget, coords, False)
elif self.tool['name'] == 'ellipse':
self.d.circle(widget, coords, False, self.tool['fill'])
@@ -588,7 +567,7 @@ class Area(gtk.DrawingArea):
if (event.state & gtk.gdk.CONTROL_MASK) or \
self.keep_aspect_ratio:
coords = self._keep_selection_ratio(coords)
- self.d.selection(widget, coords, False)
+ self.d.selection(widget, coords)
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
self.selmove = True
self.sel_get_out = False
@@ -609,7 +588,7 @@ class Area(gtk.DrawingArea):
private_undo = True
elif self.tool['name'] == 'freeform':
- self.d.polygon(widget, coords, False,
+ self.d.freeform(widget, coords, False,
self.tool['fill'], 'release')
private_undo = True
@@ -819,10 +798,6 @@ class Area(gtk.DrawingArea):
self.pixmap.draw_drawable(self.gc, undo_pix, 0, 0, 0, 0, -1, -1)
self.queue_draw()
- #special case for func polygon
- if self.tool['name'] == 'freeform':
- self.polygon_start = True # start the polygon again
-
self.emit('undo')
def redo(self):
@@ -852,6 +827,9 @@ class Area(gtk.DrawingArea):
@param widget -- the Area object (GtkDrawingArea)
"""
+ #TODO
+ return
+
#logging.debug('Area.enableUndo(self,widget)')
width, height = self.window.get_size()
@@ -980,10 +958,8 @@ class Area(gtk.DrawingArea):
width, height)
self.pixmap_temp.draw_drawable(self.gc, self.pixmap_sel,
0, 0, 0, 0, size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection, False, 0, 0,
- size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection1, False, -1, -1,
- size[0] + 2, size[1] + 2)
+
+ self.set_selection_bounds(0, 0, size[0], size[1])
self.tool['name'] = 'marquee-rectangular'
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
@@ -1007,7 +983,9 @@ class Area(gtk.DrawingArea):
@param color -- a gdk.Color object
"""
- self.gc.set_foreground(color)
+ logging.error("TODO: Area.set_stroke_color %s", color)
+ self.tool['cairo_fill_color'] = (color.red_float,
+ color.green_float, color.blue_float, 0.3)
def set_stroke_color(self, color):
"""Set stroke color.
@@ -1016,10 +994,10 @@ class Area(gtk.DrawingArea):
@param color -- a gdk.Color object
"""
- self.gc_line.set_foreground(color)
- self.gc_line.set_line_attributes(1, gtk.gdk.LINE_ON_OFF_DASH,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
- self.gc_brush.set_foreground(color)
+ logging.error("TODO: Area.set_stroke_color %s", color)
+ self.tool['cairo_stroke_color'] = (color.red_float,
+ color.green_float, color.blue_float, 0.3)
+ return
self.activity.textview.modify_text(gtk.STATE_NORMAL, color)
def grayscale(self, widget):
@@ -1126,10 +1104,13 @@ class Area(gtk.DrawingArea):
width, height)
self.pixmap_temp.draw_drawable(self.gc, self.pixmap_sel,
0, 0, self.orig_x, self.orig_y, size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection, False,
- self.orig_x, self.orig_y, size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
- self.orig_x - 1, self.orig_y - 1, size[0] + 2, size[1] + 2)
+ self.set_selection_bounds(self.orig_x, self.orig_y, size[0],
+ size[1])
+
+# self.pixmap_temp.draw_rectangle(self.gc_selection, False,
+# self.orig_x, self.orig_y, size[0], size[1])
+# self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
+# self.orig_x - 1, self.orig_y - 1, size[0] + 2, size[1] + 2)
else:
self.pixmap.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
@@ -1147,37 +1128,6 @@ class Area(gtk.DrawingArea):
while gtk.events_pending():
gtk.mainiteration(block)
- def _pixbuf2Image(self, pb):
- """change a pixbuf to RGB image
-
- @param self -- the Area object (GtkDrawingArea)
- @param pb -- the pixbuf object (gtk.gdk.Pixbuf)
-
- @return RGB Image
-
- """
- width, height = pb.get_width(), pb.get_height()
- return Image.fromstring("RGB", (width, height), pb.get_pixels())
-
- def _image2pixbuf(self, im):
- """change a RGB image to a pixbuf
-
- @param self -- the Area object (GtkDrawingArea)
- @param im -- a RGB image
-
- @return pixbuf
-
- """
- file1 = StringIO.StringIO()
- im.save(file1, "ppm")
- contents = file1.getvalue()
- file1.close()
- loader = gtk.gdk.PixbufLoader("pnm")
- loader.write(contents, len(contents))
- pixbuf = loader.get_pixbuf()
- loader.close()
- return pixbuf
-
def rotate_left(self, widget):
"""Rotate the image.
@@ -1241,10 +1191,14 @@ class Area(gtk.DrawingArea):
width, height)
self.pixmap_temp.draw_drawable(self.gc, self.pixmap_sel,
0, 0, self.orig_x, self.orig_y, size[1], size[0])
- self.pixmap_temp.draw_rectangle(self.gc_selection, False,
- self.orig_x, self.orig_y, size[1], size[0])
- self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
- self.orig_x - 1, self.orig_y - 1, size[1] + 2, size[0] + 2)
+
+ self.set_selection_bounds(self.orig_x, self.orig_y, size[0],
+ size[1])
+
+# self.pixmap_temp.draw_rectangle(self.gc_selection, False,
+# self.orig_x, self.orig_y, size[1], size[0])
+# self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
+# self.orig_x - 1, self.orig_y - 1, size[1] + 2, size[0] + 2)
else:
win = self.window
@@ -1292,14 +1246,14 @@ class Area(gtk.DrawingArea):
else:
return False
- def _set_selection_bounds(self, x1, y1, x2, y2):
+ def set_selection_bounds(self, x1, y1, width, height):
"""
Set selection bounds
@param self -- the Area object (GtkDrawingArea)
@param x1,y1,x2,y2 -- the coords of limit points
"""
- self._selection_corners = (x1, y1, x2, y2)
+ self._selection_corners = (x1, y1, width, height)
def get_selection_bounds(self):
"""
@@ -1313,15 +1267,6 @@ class Area(gtk.DrawingArea):
return self._selection_corners[0], self._selection_corners[1], \
self._selection_corners[2], self._selection_corners[3]
- def loadImageFromJournal(self, pixbuf):
- width, height = pixbuf.get_width(), pixbuf.get_height()
-
- self.pixmap.draw_pixbuf(self.gc, pixbuf, 0, 0, 0, 0,
- width, height, dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
- self.enableUndo(self, size=(width, height))
- self.queue_draw()
-
def loadImage(self, name, widget=None):
"""Load an image.
@@ -1353,10 +1298,13 @@ class Area(gtk.DrawingArea):
width, height)
self.pixmap_temp.draw_drawable(self.gc, self.pixmap_sel, 0, 0, 0, 0,
size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection, False,
- 0, 0, size[0], size[1])
- self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
- -1, -1, size[0] + 2, size[1] + 2)
+
+ self.set_selection_bounds(0, 0, size[0], size[1])
+
+# self.pixmap_temp.draw_rectangle(self.gc_selection, False,
+# 0, 0, size[0], size[1])
+# self.pixmap_temp.draw_rectangle(self.gc_selection1, False,
+# -1, -1, size[0] + 2, size[1] + 2)
self.tool['name'] = 'marquee-rectangular'
self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
@@ -1498,8 +1446,10 @@ class Area(gtk.DrawingArea):
width, height)
self.orig_x = 0
self.orig_y = 0
- self.pixmap_temp.draw_rectangle(self.gc_selection, False,
- 0, 0, width - 1, height - 1)
+
+ self.set_selection_bounds(0, 0, width - 1, height - 1)
+# self.pixmap_temp.draw_rectangle(self.gc_selection, False,
+# 0, 0, width - 1, height - 1)
self.selmove = True
self.sel_get_out = False
self.emit('select')
diff --git a/Desenho.py b/Desenho.py
index d4572c9..da5196a 100644
--- a/Desenho.py
+++ b/Desenho.py
@@ -69,6 +69,7 @@ import logging
import math
import gc
import gobject
+import cairo
RESIZE_DELAY = 500 # The time to wait for the resize operation to be
# executed, after the resize controls are pressed.
@@ -85,9 +86,23 @@ class Desenho:
"""
self._resize_timer = None
- #self.d = widget
-
- def line(self, widget, coords):
+ self._rainbow_color_list = ['#ff0000', # red
+ '#ff8000', # orange
+ '#ffff00', # yellow
+ '#80ff00', # lime
+ '#00ff00', # green
+ '#00ff80', # green water
+ '#00ffff', # light blue
+ '#007fff', # almost blue
+ '#0000ff', # blue
+ '#8000ff', # indigo
+ '#ff00ff', # pink violet
+ '#ff0080'] # violet
+ self._rainbow_counter = 0
+
+ self.points = []
+
+ def line(self, widget, coords, temp):
"""Draw line.
@param self -- Desenho.Desenho instance
@@ -96,15 +111,21 @@ class Desenho:
"""
width, height = widget.window.get_size()
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- widget.pixmap_temp.draw_line(widget.gc_line, widget.oldx, widget.oldy,
- coords[0], coords[1])
- #widget.newx = coords[0]
- #widget.newy = coords[1]
+
+ if temp == True:
+ ctx = widget.temp_ctx
+ else:
+ ctx = widget.drawing_ctx
+
+ ctx.set_line_width(widget.tool['line size'])
+ ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.move_to(widget.oldx, widget.oldy)
+ ctx.line_to(coords[0], coords[1])
+ ctx.stroke()
widget.queue_draw()
- def eraser(self, widget, coords, last, size=30, shape='circle'):
+ def eraser(self, widget, coords, last):
"""Erase part of the drawing.
@param self -- Desenho.Desenho instance
@@ -115,11 +136,10 @@ class Desenho:
@param shape -- string (default 'circle')
"""
- widget.desenha = False
- self._trace(widget, widget.gc_eraser, coords, last, size, shape)
- #widget.queue_draw()
+ widget.drawing_ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
+ self._trace(widget, coords, last)
- def brush(self, widget, coords, last, size=5, shape='circle'):
+ def brush(self, widget, coords, last):
"""Paint with brush.
@param self -- Desenho.Desenho instance
@@ -130,8 +150,9 @@ class Desenho:
@param shape -- string (default 'circle')
"""
- widget.desenha = False
- self._trace(widget, widget.gc_brush, coords, last, size, shape)
+ widget.drawing_ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ logging.error('brush')
+ self._trace(widget, coords, last)
def stamp(self, widget, coords, last, stamp_size=20):
"""Paint with stamp.
@@ -155,7 +176,7 @@ class Desenho:
widget.queue_draw()
- def rainbow(self, widget, coords, last, color, size=5, shape='circle'):
+ def rainbow(self, widget, coords, last):
"""Paint with rainbow.
@param self -- Desenho.Desenho instance
@@ -167,52 +188,61 @@ class Desenho:
@param shape -- string (default 'circle')
"""
- colormap = widget.get_colormap()
- rainbow_colors = [
- colormap.alloc_color('#ff0000', True, True), # vermelho
- colormap.alloc_color('#ff8000', True, True), # laranja
- colormap.alloc_color('#ffff00', True, True), # amarelo
- colormap.alloc_color('#80ff00', True, True), # verde lima
- colormap.alloc_color('#00ff00', True, True), # verde
- colormap.alloc_color('#00ff80', True, True), # verde agua
- colormap.alloc_color('#00ffff', True, True), # azul claro
- colormap.alloc_color('#007fff', True, True), # quase azul
- colormap.alloc_color('#0000ff', True, True), # azul
- colormap.alloc_color('#8000ff', True, True), # anil
- colormap.alloc_color('#ff00ff', True, True), # rosa violeta
- colormap.alloc_color('#ff0080', True, True), # violeta
- ]
-
- widget.gc_rainbow.set_foreground(rainbow_colors[color])
- widget.desenha = False
- self._trace(widget, widget.gc_rainbow, coords, last, size, shape)
+ _color_str = self._rainbow_color_list[self._rainbow_counter]
+ _color = gtk.gdk.color_parse(_color_str)
+ self._rainbow_counter += 1
+ if self._rainbow_counter > 11:
+ self._rainbow_counter = 0
- def _trace(self, widget, gc, coords, last, size, shape):
+ widget.drawing_ctx.set_source_rgba(_color.red, _color.green,
+ _color.blue, 0.3)
+ self._trace(widget, coords, last)
+
+ def _trace(self, widget, coords, last):
+ widget.desenha = False
+ size = widget.tool['line size']
+ shape = widget.tool['line shape']
if shape == 'circle':
- widget.pixmap.draw_arc(gc, True,
- coords[0] - size / 2, coords[1] - size / 2,
- size, size, 0, 360 * 64)
+ logging.error('trace circle')
if last:
- gc.set_line_attributes(size, gtk.gdk.LINE_SOLID,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
- widget.pixmap.draw_line(gc,
- last[0], last[1], coords[0], coords[1])
- gc.set_line_attributes(0, gtk.gdk.LINE_SOLID,
- gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)
+ logging.error('trace circle last')
+ widget.drawing_ctx.set_line_width(size)
+
+ widget.drawing_ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+ widget.drawing_ctx.set_line_join(cairo.LINE_JOIN_ROUND)
+ widget.drawing_ctx.move_to(last[0], last[1])
+ widget.drawing_ctx.line_to(coords[0], coords[1])
+ widget.drawing_ctx.stroke()
+ else:
+ widget.drawing_ctx.move_to(coords[0],
+ coords[1])
+ widget.drawing_ctx.arc(coords[0], coords[1],
+ size / 2, 0., 2 * math.pi)
+ widget.drawing_ctx.fill()
+
elif shape == 'square':
- widget.pixmap.draw_rectangle(gc, True,
- coords[0] - size / 2, coords[1] - size / 2, size, size)
if last:
points = [(last[0] - size / 2, last[1] - size / 2),
(coords[0] - size / 2, coords[1] - size / 2),
(coords[0] + size / 2, coords[1] + size / 2),
(last[0] + size / 2, last[1] + size / 2)]
- widget.pixmap.draw_polygon(gc, True, points)
+ for point in points:
+ widget.drawing_ctx.line_to(*point)
+ widget.drawing_ctx.fill()
points = [(last[0] + size / 2, last[1] - size / 2),
(coords[0] + size / 2, coords[1] - size / 2),
(coords[0] - size / 2, coords[1] + size / 2),
(last[0] - size / 2, last[1] + size / 2)]
- widget.pixmap.draw_polygon(gc, True, points)
+ for point in points:
+ widget.drawing_ctx.line_to(*point)
+ widget.drawing_ctx.fill()
+ else:
+ widget.drawing_ctx.move_to(coords[0] - size / 2,
+ coords[1] - size / 2)
+ widget.drawing_ctx.rectangle(coords[0] - size / 2,
+ coords[1] - size / 2, size, size)
+ widget.drawing_ctx.fill()
+
if last:
x = min(coords[0], last[0])
width = max(coords[0], last[0]) - x
@@ -230,94 +260,86 @@ class Desenho:
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between drawing context and temp context
@param fill -- Fill object
"""
if temp == True:
- pixmap = widget.pixmap_temp
+ ctx = widget.temp_ctx
else:
- pixmap = widget.pixmap
+ ctx = widget.drawing_ctx
width, height = widget.window.get_size()
x, y, dx, dy, = self.adjust(widget, coords)
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
+ ctx.rectangle(x, y, dx, dy)
if fill == True:
- pixmap.draw_rectangle(widget.gc, True, x, y, dx, dy)
- pixmap.draw_rectangle(widget.gc_line, False, x, y, dx, dy)
+ ctx.set_source_rgba(*widget.tool['cairo_fill_color'])
+ ctx.fill_preserve()
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.stroke()
+ widget.queue_draw_area(x, y, dx, dy)
+
+ def _draw_polygon(self, widget, temp, fill, points, closed=True):
+ if not points:
+ return
+ if temp == True:
+ ctx = widget.temp_ctx
+ else:
+ ctx = widget.drawing_ctx
+ width, height = widget.window.get_size()
+
+ ctx.save()
+ ctx.move_to(*points[0])
+ for point in points:
+ ctx.line_to(*point)
+ if closed:
+ ctx.close_path()
+ ctx.set_line_join(cairo.LINE_JOIN_MITER)
+ ctx.set_line_width(widget.tool['line size'])
+ if fill:
+ ctx.set_source_rgba(*widget.tool['cairo_fill_color'])
+ ctx.fill_preserve()
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.stroke()
+ ctx.restore()
widget.queue_draw()
def triangle(self, widget, coords, temp, fill):
"""Draw a triangle.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between drawing context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
points = [(widget.oldx, widget.oldy),
(widget.oldx + int((coords[0] - widget.oldx) / 2), coords[1]),
(coords[0], widget.oldy)]
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, points)
- pixmap.draw_polygon(widget.gc_line, False, points)
- widget.queue_draw()
+ self._draw_polygon(widget, temp, fill, points)
def trapezoid(self, widget, coords, temp, fill):
"""Draw a trapezoid.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
dif = int((coords[0] - widget.oldx) / 4)
points = [(widget.oldx, widget.oldy), (widget.oldx + dif, coords[1]),
(coords[0] - dif, coords[1]), (coords[0], widget.oldy)]
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, points)
- pixmap.draw_polygon(widget.gc_line, False, points)
- widget.queue_draw()
+ self._draw_polygon(widget, temp, fill, points)
def arrow(self, widget, coords, temp, fill):
"""Draw a arrow.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
x = coords[0] - widget.oldx
y = coords[1] - widget.oldy
A = math.atan2(y, x)
@@ -339,56 +361,31 @@ class Desenho:
widget.oldy + int(0.74 * r * math.sin(A + dA / 6 + dA / 6))))
p.append((widget.oldx + int(r * math.cos(A + dA / 2)),\
widget.oldy + int(r * math.sin(A + dA / 2))))
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- tp = tuple(p)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, tp)
- pixmap.draw_polygon(widget.gc_line, False, tp)
- widget.queue_draw()
+
+ self._draw_polygon(widget, temp, fill, p)
def parallelogram(self, widget, coords, temp, fill):
"""Draw a parallelogram.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
x = int((coords[0] - widget.oldx) / 4)
points = [(widget.oldx, widget.oldy), (coords[0] - x, widget.oldy),
(coords[0], coords[1]), (widget.oldx + x, coords[1])]
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, points)
- pixmap.draw_polygon(widget.gc_line, False, points)
- widget.queue_draw()
+ self._draw_polygon(widget, temp, fill, points)
def star(self, widget, coords, n, temp, fill):
"""Draw polygon with n sides.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
@param n -- number of sides
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
x = coords[0] - widget.oldx
y = coords[1] - widget.oldy
A = math.atan2(y, x)
@@ -404,32 +401,17 @@ class Desenho:
widget.oldy + int(r * math.sin(A))))
p.append((widget.oldx + int(0.4 * r * math.cos(A + dA / 2)), \
widget.oldy + int(0.4 * r * math.sin(A + dA / 2))))
- tp = tuple(p)
-
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, tp)
- pixmap.draw_polygon(widget.gc_line, False, tp)
- widget.queue_draw()
+ self._draw_polygon(widget, temp, fill, p)
def polygon_regular(self, widget, coords, n, temp, fill):
"""Draw polygon with n sides.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
@param n -- number of sides
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
- width, height = widget.window.get_size()
-
x = coords[0] - widget.oldx
y = coords[1] - widget.oldy
A = math.atan2(y, x)
@@ -441,29 +423,21 @@ class Desenho:
A = A + dA
p.append((widget.oldx + int(r * math.cos(A)), \
widget.oldy + int(r * math.sin(A))))
- tp = tuple(p)
-
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, tp)
- pixmap.draw_polygon(widget.gc_line, False, tp)
- widget.queue_draw()
+ self._draw_polygon(widget, temp, fill, p)
def heart(self, widget, coords, temp, fill):
"""Draw polygon with n sides.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
if temp == True:
- pixmap = widget.pixmap_temp
+ ctx = widget.temp_ctx
else:
- pixmap = widget.pixmap
+ ctx = widget.drawing_ctx
+
width, height = widget.window.get_size()
if coords[0] < widget.oldx:
@@ -477,118 +451,95 @@ class Desenho:
dx = math.fabs(coords[0] - widget.oldx)
dy = math.fabs(coords[1] - widget.oldy)
-
- w = int(4 * dx)
- e = int(4 * dx / math.sqrt(3))
-
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_arc(widget.gc, True,
- int(widget.oldx - dx),
- int(widget.oldy - e / 2), w, e, 180 * 64, 60 * 64)
- pixmap.draw_arc(widget.gc, True,
- int(widget.oldx - 3 * dx),
- int(widget.oldy - e / 2), w, e, 300 * 64, 60 * 64)
- pixmap.draw_arc(widget.gc, True,
- int(widget.oldx - dx * 0.2),
- int(widget.oldy - 0.6 * dx + 2),
- int(1.2 * dx), int(1.2 * dx), 0, 180 * 64)
- pixmap.draw_arc(widget.gc, True,
- int(widget.oldx - dx),
- int(widget.oldy - 0.6 * dx + 2),
- int(1.2 * dx), int(1.2 * dx), 0, 180 * 64)
- pixmap.draw_arc(widget.gc_line, False,
- int(widget.oldx - dx),
- int(widget.oldy - e / 2), w, e, 180 * 64, 60 * 64)
- pixmap.draw_arc(widget.gc_line, False,
- int(widget.oldx - dx - w / 2),
- int(widget.oldy - e / 2), w, e, 300 * 64, 60 * 64)
- pixmap.draw_arc(widget.gc_line, False,
- int(widget.oldx - dx * 0.2),
- int(widget.oldy - 0.6 * dx + 2),
- int(1.2 * dx), int(1.2 * dx), 0, 132 * 64)
- pixmap.draw_arc(widget.gc_line, False,
- int(widget.oldx - dx),
- int(widget.oldy - 0.6 * dx + 2),
- int(1.2 * dx), int(1.2 * dx), 48 * 64, 132 * 64)
+ r = math.hypot(dy, dy)
+ w = r / 10.0
+
+ if w == 0:
+ # non invertible cairo matrix
+ return
+
+ ctx.set_line_width(widget.tool['line size'])
+ line_width = ctx.get_line_width()
+
+ ctx.save()
+ ctx.translate(widget.oldx, widget.oldy)
+ ctx.scale(w, w)
+ ctx.move_to(0, 0)
+ ctx.curve_to(0, -30, -50, -30, -50, 0)
+ ctx.curve_to(-50, 30, 0, 35, 0, 60)
+ ctx.curve_to (0, 35, 50, 30, 50, 0)
+ ctx.curve_to (50, -30, 0, -30, 0, 0)
+
+ ctx.set_line_width(line_width / w)
+ if fill:
+ ctx.set_source_rgba(*widget.tool['cairo_fill_color'])
+ ctx.fill_preserve()
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.stroke()
+ ctx.restore()
widget.queue_draw()
def circle(self, widget, coords, temp, fill):
"""Draw a circle.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between context and temp context
@param fill -- Fill object
-
"""
-
if temp == True:
- pixmap = widget.pixmap_temp
+ ctx = widget.temp_ctx
else:
- pixmap = widget.pixmap
+ ctx = widget.drawing_ctx
width, height = widget.window.get_size()
x, y, dx, dy = self.adjust(widget, coords)
-
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_arc(widget.gc, True, x, y, dx, dy, 0, 360 * 64)
- pixmap.draw_arc(widget.gc_line, False, x, y, dx, dy, 0, 360 * 64)
+ if dx == 0 or dy == 0:
+ # scale by 0 gives error
+ return
+ ctx.set_line_width(widget.tool['line size'])
+ line_width = ctx.get_line_width()
+ ctx.save()
+ ctx.translate(x, y)
+ ctx.scale(dx, dy)
+ ctx.arc(0., 0., 1., 0., 2 * math.pi)
+ ctx.set_line_width(line_width / float(min(dx, dy)))
+ if fill:
+ ctx.set_source_rgba(*widget.tool['cairo_fill_color'])
+ ctx.fill_preserve()
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.stroke()
+ ctx.restore()
widget.queue_draw()
def clear(self, widget):
"""Clear the drawing.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
"""
logging.debug('Desenho.clear')
+ widget.desenha = False
- widget.desenho = []
widget.textos = []
-
+ x, y = 0, 0
+ width, height = widget.window.get_size()
# try to clear a selected area first
if widget.is_selected():
- try:
- width, height = widget.pixmap_sel.get_size()
-
- # Clear the selected area
- widget.pixmap_sel.draw_rectangle(widget.get_style().white_gc,
- True, 0, 0, width, height)
- # Draw the selected area in the displayed pixmap
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap_sel,
- 0, 0, widget.orig_x, widget.orig_y, width, height)
- # Draw the selection rectangle
- widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
- widget.orig_x, widget.orig_y, width, height)
- widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
- widget.orig_x - 1, widget.orig_y - 1,
- width + 2, height + 2)
-
- except NameError, message:
- logging.debug(message)
- except Exception, message:
- logging.debug('Unexpected error: %s', message)
- else:
- width, height = widget.window.get_size()
- widget.pixmap.draw_rectangle(widget.get_style().white_gc, True,
- 0, 0, width, height)
- widget.pixmap_temp.draw_rectangle(widget.get_style().white_gc,
- True, 0, 0, width, height)
+ x, y, width, height = widget.get_selection_bounds()
+ logging.error('clear %s', (x, y, width, height))
+
+ widget.drawing_ctx.rectangle(x, y, width, height)
+ widget.drawing_ctx.set_source_rgb(1.0, 1.0, 1.0)
+ widget.drawing_ctx.fill()
+
widget.queue_draw()
def text(self, widget, event):
"""Display and draw text in the drawing area.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param event -- GdkEvent
-
"""
if not widget.text_in_progress:
@@ -628,47 +579,18 @@ class Desenho:
widget.queue_draw()
- def selection(self, widget, coords, temp=True):
+ def selection(self, widget, coords):
"""Make a selection.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
@param fill -- Fill object
-
- @return (x0,y0,x1,y1) -- coords of corners
"""
width, height = widget.window.get_size()
x, y, dx, dy = self.adjust(widget, coords, True)
-
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap,
- 0, 0, 0, 0, width, height)
- if temp:
- widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
- x, y, dx, dy)
- widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
- x - 1, y - 1, dx + 2, dy + 2)
- else:
- try:
- del (widget.pixmap_sel)
- except:
- pass
-
- widget.pixmap_sel = gtk.gdk.Pixmap(widget.window, dx, dy, -1)
- widget.pixmap_sel.draw_drawable(widget.gc, widget.pixmap,
- x, y, 0, 0, dx, dy)
- widget.pixmap.draw_rectangle(widget.get_style().white_gc, True,
- x, y, dx, dy)
- widget.orig_x = x
- widget.orig_y = y
- widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
- x, y, dx, dy)
- widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
- x - 1, y - 1, dx + 2, dy + 2)
-
+ widget.set_selection_bounds(x, y, dx, dy)
widget.queue_draw()
def moveSelection(self, widget, coords):
@@ -695,11 +617,14 @@ class Desenho:
widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap_sel,
0, 0, widget.orig_x + dx, widget.orig_y + dy, size[0], size[1])
- widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
- widget.orig_x + dx, widget.orig_y + dy, size[0], size[1])
- widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
- widget.orig_x + dx - 1, widget.orig_y + dy - 1,
- size[0] + 2, size[1] + 2)
+ widget.set_selection_bounds(widget.orig_x + dx, widget.orig_y + dy,
+ size[0], size[1])
+
+# widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
+# widget.orig_x + dx, widget.orig_y + dy, size[0], size[1])
+# widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
+# widget.orig_x + dx - 1, widget.orig_y + dy - 1,
+# size[0] + 2, size[1] + 2)
widget.queue_draw()
@@ -772,108 +697,69 @@ class Desenho:
else:
widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap_sel,
0, 0, widget.orig_x, widget.orig_y, wr, hr)
- widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
- widget.orig_x, widget.orig_y, wr, hr)
- widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
- widget.orig_x - 1, widget.orig_y - 1, wr + 2, hr + 2)
+
+ widget.set_selection_bounds(widget.orig_x, widget.orig_y, wr, hr)
+# widget.pixmap_temp.draw_rectangle(widget.gc_selection, False,
+# widget.orig_x, widget.orig_y, wr, hr)
+# widget.pixmap_temp.draw_rectangle(widget.gc_selection1, False,
+# widget.orig_x - 1, widget.orig_y - 1, wr + 2, hr + 2)
widget.queue_draw()
gc.collect()
- def polygon(self, widget, coords, temp, fill, param=None):
+ def freeform(self, widget, coords, temp, fill, param=None):
"""Draw polygon.
-
@param self -- Desenho.Desenho instance
@param widget -- Area object (GtkDrawingArea)
@param coords -- Two value tuple
- @param temp -- switch between pixmap and pixmap_temp
+ @param temp -- switch between drawing context and temp context
@param fill -- Fill object
-
"""
- if temp == True:
- pixmap = widget.pixmap_temp
- else:
- pixmap = widget.pixmap
width, height = widget.window.get_size()
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
-
+ logging.error('freeform param %s', param)
if param == "moving":
# mouse not pressed moving
- if not widget.polygon_start:
- pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- elif widget.polygon_start == True: # Starting a new polygon ?
- if param == "motion":
- # first press
- try:
- pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- widget.pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- widget.points.append(coords)
- except:
- pixmap.draw_line(widget.gc_line, widget.oldx, widget.oldy,
- coords[0], coords[1])
- widget.pixmap.draw_line(widget.gc_line,
- widget.oldx, widget.oldy, coords[0], coords[1])
- widget.first = widget.oldx, widget.oldy
- widget.points = [widget.first, coords]
- widget.enableUndo(widget, overrite=True)
- widget.last = coords
- else: # param == "release"
- # first release
- try:
- widget.first
- widget.points.append(coords)
- widget.pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- except:
- widget.first = widget.oldx, widget.oldy
- widget.points = [widget.first, coords]
- widget.pixmap.draw_line(widget.gc_line,
- widget.oldx, widget.oldy, coords[0], coords[1])
- widget.enableUndo(widget, overrite=True)
- widget.last = coords
- widget.polygon_start = False
- else:
- if param == "motion":
- # print "press"
- pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- widget.pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
- widget.enableUndo(widget, overrite=True)
- widget.last = coords
- widget.points.append(coords)
- elif param == "release":
- # print "release"
- x = coords[0] - widget.first[0]
- y = coords[1] - widget.first[1]
- d = math.hypot(x, y)
- if d > 20: # close the polygon ?
- pixmap.draw_line(widget.gc_line,
- widget.last[0], widget.last[1], coords[0], coords[1])
+ if self.points:
+ if widget.last:
+ self.points.append((coords[0], coords[1]))
+ widget.last = []
+ else:
+ self.points[-1] = (coords[0], coords[1])
+ elif param == "motion":
+ # when mousepress or mousemove
+ if widget.last:
+ self.points.append((widget.last[0], widget.last[1]))
+ self.points.append((coords[0], coords[1]))
+ else:
+ self.points.append((widget.oldx, widget.oldy))
+ self.points.append((coords[0], coords[1]))
+ widget.enableUndo(widget, overrite=True)
+ widget.last = coords
+ elif param == "release":
+ if len(self.points) > 2:
+ first = self.points[0]
+ dx = coords[0] - first[0]
+ dy = coords[1] - first[1]
+ d = math.hypot(dx, dy)
+ if d > 20:
widget.last = coords
- widget.points.append(coords)
+ self.points.append(coords)
else:
- tp = tuple(widget.points)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, tp)
- pixmap.draw_polygon(widget.gc_line, False, tp)
+ # close the polygon
+ logging.error('freeform ending')
+ self._draw_polygon(widget, False, fill, self.points)
widget.last = []
- widget.polygon_start = True
+ self.points = []
widget.enableUndo(widget, overrite=True)
- elif param == "bug":
- tp = tuple(widget.points)
- if fill == True:
- pixmap.draw_polygon(widget.gc, True, tp)
- pixmap.draw_polygon(widget.gc_line, False, tp)
- widget.last = []
- widget.polygon_start = True
- widget.enableUndo(widget, overrite=True)
+ widget.queue_draw()
+ return
+
+ logging.error('freeform points (2) %s', self.points)
+ widget.desenha = True
+ # Display the polygon open in the temp canvas
+ self._draw_polygon(widget, True, False, self.points, closed=False)
widget.queue_draw()
def adjust(self, widget, coords, locked=False):
diff --git a/OficinaActivity.py b/OficinaActivity.py
index 64dace4..16484b6 100644
--- a/OficinaActivity.py
+++ b/OficinaActivity.py
@@ -140,21 +140,23 @@ class OficinaActivity(activity.Activity):
logging.debug('reading file %s, mimetype: %s, title: %s',
file_path, self.metadata['mime_type'], self.metadata['title'])
- pixbuf = gtk.gdk.pixbuf_new_from_file(file_path)
+ self.area.load_from_file(file_path)
def size_allocate_cb(widget, allocation):
+ logging.error('read file size allocate')
self.fixed.disconnect(self._setup_handle)
- self.area.setup(pixbuf.get_width(), pixbuf.get_height())
+ width = self.area.drawing_canvas.get_width()
+ height = self.area.drawing_canvas.get_height()
+ self.area.setup(width, height)
# The scrolled window is confused with a image of the same size
# of the canvas when the toolbars popup and the scrolls
# keep visible.
- if pixbuf.get_height() > allocation.height or \
- pixbuf.get_width() > allocation.width:
- self.canvas.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ if height > allocation.height or width > allocation.width:
+ self.canvas.set_policy(gtk.POLICY_AUTOMATIC,
+ gtk.POLICY_AUTOMATIC)
else:
self.canvas.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
- self.area.loadImageFromJournal(pixbuf)
self.center_area()
self.canvas.add_with_viewport(self.fixed)
@@ -186,12 +188,8 @@ class OficinaActivity(activity.Activity):
self.area.d.text(self.area, event=None)
self.area.getout()
- pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
- width, height)
- pixbuf.get_from_drawable(self.area.pixmap,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, -1, -1)
+ self.area.drawing_canvas.write_to_png(file_path)
self.metadata['mime_type'] = 'image/png'
- pixbuf.save(file_path, 'png', {})
def _get_area_displacement(self):
"""Return the point to use as top left corner in order to move
diff --git a/toolbox.py b/toolbox.py
index 8d58306..b5d1e1c 100644
--- a/toolbox.py
+++ b/toolbox.py
@@ -336,6 +336,12 @@ class ToolsToolbarBuilder():
self._activity.area.set_stroke_color(new_color)
self.properties['stroke color'] = new_color
+ if isinstance(new_color, unicode):
+ new_color = gtk.gdk.Color(new_color)
+ self.properties['cairo_stroke_color'] = (new_color.red_float,
+ new_color.green_float,
+ new_color.blue_float, 0.3)
+
def _on_signal_undo_cb(self, widget, data=None):
self._verify_sensitive_buttons()
@@ -378,6 +384,12 @@ class ButtonFillColor(ColorToolButton):
self._activity.area.set_fill_color(new_color)
self.properties['fill color'] = new_color
+ if isinstance(new_color, unicode):
+ new_color = gtk.gdk.Color(new_color)
+ self.properties['cairo_fill_color'] = (new_color.red_float,
+ new_color.green_float,
+ new_color.blue_float, 0.3)
+
def create_palette(self):
self._palette = self.get_child().create_palette()
color_palette_hbox = self._palette._picker_hbox