Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPootle daemon <pootle@pootle.sugarlabs.org>2012-08-11 04:31:57 (GMT)
committer Pootle daemon <pootle@pootle.sugarlabs.org>2012-08-11 04:31:57 (GMT)
commit90266dc1c7ce8ac91a69d52ddb748458947fa729 (patch)
tree5afd4524914d1cc017f4a450f45c8baf2ca5e6cb
parent70be68f0692c5cead8788b7e8319ddd9fee87a19 (diff)
parent804c5cdb26f2626d92f08acf8b0f76ae618ecc50 (diff)
Merge branch 'master' of git.sugarlabs.org:paint/mainline
-rw-r--r--Area.py1342
-rw-r--r--Desenho.py844
-rw-r--r--OficinaActivity.py57
-rw-r--r--fontcombobox.py29
-rwxr-xr-xsetup.py2
-rw-r--r--toolbox.py195
-rw-r--r--widgets.py249
7 files changed, 1298 insertions, 1420 deletions
diff --git a/Area.py b/Area.py
index a81cda3..fbf2327 100644
--- a/Area.py
+++ b/Area.py
@@ -62,26 +62,32 @@ Walter Bender (walter@laptop.org)
"""
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GdkPixbuf
+from gi.repository import GObject
+from gi.repository import Pango
+
import logging
import os
import tempfile
import math
-import pango
+import cairo
+import StringIO
+import array
from Desenho import Desenho
from urlparse import urlparse
-from sugar.graphics.style import zoom
+from sugar3.graphics.style import zoom
FALLBACK_FILL = True
-try:
- from fill import fill
- FALLBACK_FILL = False
-except:
- logging.debug('No valid fill binaries. Using slower python code')
- pass
+#try:
+# from fill import fill
+# FALLBACK_FILL = False
+#except:
+# logging.debug('No valid fill binaries. Using slower python code')
+# pass
##Tools and events manipulation are handle with this class.
@@ -89,35 +95,35 @@ TARGET_URI = 0
MAX_UNDO_STEPS = 12
-class Area(gtk.DrawingArea):
+class Area(Gtk.DrawingArea):
__gsignals__ = {
- 'undo': (gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ([])),
- 'redo': (gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ([])),
- 'action-saved': (gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ([])),
- 'select': (gobject.SIGNAL_ACTION, gobject.TYPE_NONE, ([])),
+ 'undo': (GObject.SignalFlags.ACTION, None, ([])),
+ 'redo': (GObject.SignalFlags.ACTION, None, ([])),
+ 'action-saved': (GObject.SignalFlags.ACTION, None, ([])),
+ 'select': (GObject.SignalFlags.ACTION, None, ([])),
}
def __init__(self, activity):
""" Initialize the object from class Area which is derived
- from gtk.DrawingArea.
+ from Gtk.DrawingArea.
@param self -- the Area object (GtkDrawingArea)
@param activity -- the parent window
"""
- gtk.DrawingArea.__init__(self)
-
- self.set_events(gtk.gdk.POINTER_MOTION_MASK |
- gtk.gdk.POINTER_MOTION_HINT_MASK |
- gtk.gdk.BUTTON_PRESS_MASK |
- gtk.gdk.BUTTON_RELEASE_MASK |
- gtk.gdk.EXPOSURE_MASK |
- gtk.gdk.LEAVE_NOTIFY_MASK |
- gtk.gdk.ENTER_NOTIFY_MASK |
- gtk.gdk.KEY_PRESS_MASK)
-
- self.connect("expose_event", self.expose)
+ GObject.GObject.__init__(self)
+
+ self.set_events(Gdk.EventMask.POINTER_MOTION_MASK |
+ Gdk.EventMask.POINTER_MOTION_HINT_MASK |
+ Gdk.EventMask.BUTTON_PRESS_MASK |
+ Gdk.EventMask.BUTTON_RELEASE_MASK |
+ Gdk.EventMask.EXPOSURE_MASK |
+ Gdk.EventMask.LEAVE_NOTIFY_MASK |
+ Gdk.EventMask.ENTER_NOTIFY_MASK |
+ Gdk.EventMask.KEY_PRESS_MASK)
+
+ self.connect("draw", self.draw)
self.connect("motion_notify_event", self.mousemove)
self.connect("button_press_event", self.mousedown)
self.connect("button_release_event", self.mouseup)
@@ -125,70 +131,60 @@ class Area(gtk.DrawingArea):
self.connect("leave_notify_event", self.mouseleave)
self.connect("enter_notify_event", self.mouseenter)
- target = [('text/uri-list', 0, TARGET_URI)]
- self.drag_dest_set(gtk.DEST_DEFAULT_ALL, target,
- gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
+ target = [Gtk.TargetEntry.new('text/uri-list', 0, TARGET_URI)]
+ self.drag_dest_set(Gtk.DestDefaults.ALL, target,
+ Gdk.DragAction.COPY | Gdk.DragAction.MOVE)
self.connect('drag_data_received', self.drag_data_received)
- self.set_flags(gtk.CAN_FOCUS)
+ self.set_can_focus(True)
self.grab_focus()
+ # TODO gtk3
+ # self.set_extension_events(Gdk.EXTENSION_EVENTS_CURSOR)
- self.set_extension_events(gtk.gdk.EXTENSION_EVENTS_CURSOR)
## Define which tool is been used.
## It is now described as a dictionnary,
## with the following keys:
## - 'name' : a string
## - 'line size' : a integer
## - 'stamp size' : a integer
- ## - 'fill color' : a gtk.gdk.Color object
- ## - 'stroke color' : a gtk.gdk.Color object
## - 'line shape' : a string - 'circle' or 'square', for now
## - 'fill' : a Boolean value
## - '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,
- 'vertices': 6.0}
+ 'cairo_stroke_color': (0.0, 0.0, 0.0, 1.0),
+ 'cairo_fill_color': (0.0, 0.0, 0.0, 1.0),
+ 'alpha': 1.0,
+ 'vertices': 6.0,
+ 'font_description': 'Sans 12'}
self.desenha = False
- self.selmove = False
- self.sel_get_out = False
+ self._selmove = 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
- self.font_description = pango.FontDescription()
- self.font_description.set_family('Sans')
- self.font_description.set_size(12)
+ self._font_description = None
+ self.set_font_description(
+ Pango.FontDescription(self.tool['font_description']))
- self._set_selection_bounds(0, 0, 0, 0)
+ # selection properties
+ self.clear_selection()
+ self.pending_clean_selection_background = False
- # List of pixmaps for the Undo function:
+ # List of pixbuf for the Undo function:
self._undo_list = []
self._undo_index = None
@@ -197,68 +193,86 @@ class Area(gtk.DrawingArea):
self.x_cursor = 0
self.y_cursor = 0
+ def set_font_description(self, fd):
+ self._font_description = fd
+ self.activity.textview.modify_font(fd)
+ self.tool['font_description'] = fd.to_string()
+
+ def get_font_description(self):
+ return Pango.FontDescription(self.tool['font_description'])
+
def _get_stamp_size(self):
"""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))
+ 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)
+ ##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)
- 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
+ ##This canvas is showed when we need show something and not draw it.
+ self.temp_canvas = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ self.temp_ctx = cairo.Context(self.temp_canvas)
+ self._init_temp_canvas()
- self.gc_eraser.set_foreground(self.white)
- self.gc_rainbow = win.new_gc()
+ self.enable_undo()
- self.gc_brush = win.new_gc()
- self.gc_brush.set_foreground(self.black)
+ # Setting a initial tool
+ self.set_tool(self.tool)
- self.gc_line = win.new_gc()
+ return True
- 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)
+ def get_size(self):
+ rect = self.get_allocation()
+ return rect.width, rect.height
- #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)
+ def _init_temp_canvas(self, area=None):
+ #logging.error('init_temp_canvas.')
+ #self.drawing_canvas.flush()
+ if area == None:
+ width, height = self.get_size()
+ self.temp_ctx.rectangle(0, 0, width, height)
+ else:
+ self.temp_ctx.rectangle(area.x, area.y, area.width, area.height)
+ self.temp_ctx.set_source_surface(self.drawing_canvas)
+ self.temp_ctx.paint()
- self.enableUndo(self, size=(width, height))
+ def display_selection_border(self, ctx):
+ if not self.is_selected():
+ return
+ x, y, width, height = self.get_selection_bounds()
- # Setting a initial tool
- self.set_tool(self.tool)
+ ctx.save()
+ ctx.set_line_width(1)
+ ctx.set_source_rgba(1., 1., 1., 1.)
+ ctx.rectangle(x, y, width, height)
+ ctx.stroke_preserve()
- return True
+ 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.stroke()
+ ctx.restore()
def configure_line(self, size):
"""Configure the new line's size.
@@ -267,11 +281,10 @@ 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)
- def expose(self, widget, event):
- """ This function define which pixmap will be showed to the user.
+ def draw(self, widget, context):
+ """ This function define which canvas will be showed to the user.
Show up the Area object (GtkDrawingArea).
@param self -- the Area object (GtkDrawingArea)
@@ -279,17 +292,27 @@ class Area(gtk.DrawingArea):
@param event -- GdkEvent
"""
- area = event.area
- 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])
- 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
+# area = event.area
- def show_tool_shape(self, widget):
+# context = self.get_window().cairo_create()
+# context.rectangle(area.x, area.y, area.width, area.height)
+# context.clip()
+
+ if self.desenha:
+ #logging.error('Expose use temp canvas area %s', area)
+ # Paint the canvas in the widget:
+ context.set_source_surface(self.temp_canvas)
+ context.paint()
+ else:
+ #logging.error('Expose use drawing canvas area %s', area)
+ context.set_source_surface(self.drawing_canvas)
+ context.paint()
+ self.show_tool_shape(context)
+ # TODO: gtk3 how get the area to avoid redrawing all ?
+ self._init_temp_canvas() # area)
+ self.display_selection_border(context)
+
+ def show_tool_shape(self, context):
"""
Show the shape of the tool selected for pencil, brush,
rainbow and eraser
@@ -297,24 +320,31 @@ class Area(gtk.DrawingArea):
if self.tool['name'] in ['pencil', 'eraser', 'brush', 'rainbow',
'stamp']:
if not self.drawing:
+ context.set_source_rgba(*self.tool['cairo_stroke_color'])
+ context.set_line_width(1)
# 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)
+ 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.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()
+ self.last_x_cursor = self.x_cursor
+ self.last_y_cursor = self.y_cursor
def mousedown(self, widget, event):
"""Make the Area object (GtkDrawingArea) recognize
@@ -325,23 +355,26 @@ class Area(gtk.DrawingArea):
@param event -- GdkEvent
"""
- width, height = self.window.get_size()
+ width, height = self.get_size()
coords = int(event.x), int(event.y)
# text
+ design_mode = True
if self.tool['name'] == 'text':
self.d.text(widget, event)
+ design_mode = False
# This fixes a bug that made the text viewer get stuck in the canvas
elif self.text_in_progress:
+ design_mode = False
try:
- # This works for a gtk.Entry
+ # This works for a Gtk.Entry
text = self.activity.textview.get_text()
except AttributeError:
- # This works for a gtk.TextView
+ # This works for a Gtk.TextView
buf = self.activity.textview.get_buffer()
start, end = buf.get_bounds()
- text = buf.get_text(start, end)
+ text = buf.get_text(start, end, True)
if text is not None:
self.d.text(widget, event)
@@ -350,68 +383,88 @@ 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()
+ # TODO: get_pointer is deprecated
+# http://developer.gnome.org/gtk3/3.4/GtkWidget.html#gtk-widget-get-pointer
+ _pointer, x, y, state = event.window.get_pointer()
if self.tool['name'] == 'picker':
self.pick_color(x, y)
- if state & gtk.gdk.BUTTON3_MASK:
- #Handle with the right button click event.
- if self.tool['name'] == 'marquee-rectangular':
- self.sel_get_out = True
- elif state & gtk.gdk.BUTTON1_MASK:
+ if state & Gdk.ModifierType.BUTTON1_MASK:
#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':
self.configure_line(self.tool['line size'])
- if self.polygon_start == False:
- self.desenha = True
- if self.selmove:
- #get out of the func selection
- if self.tool['name'] != 'marquee-rectangular':
- self.getout()
- self.selmove = False
- else:
- size = self.pixmap_sel.get_size()
- xi = self.orig_x
- yi = self.orig_y
- xf = xi + size[0]
- yf = yi + size[1]
+ self.d.freeform(widget, coords, True,
+ self.tool['fill'], "motion")
+ if self.tool['name'] == 'marquee-rectangular':
+ if self.is_selected():
+ xi, yi, width, height = self.get_selection_bounds()
+ xf = xi + width
+ yf = yi + height
+ # verify is out of the selected area
if (coords[0] < xi) or (coords[0] > xf) or \
(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.desenha = True
- widget.queue_draw()
+ self.getout()
+ self._selmove = False
+ design_mode = False
+ else:
+ # if is inside the selected area move the selection
+ self.d.move_selection(widget, coords)
+ self._selmove = True
+ else:
+ self._selmove = False
+
+ if design_mode:
+ self.desenha = True
+
+ def calculate_damaged_area(self, points):
+ min_x = points[0][0]
+ min_y = points[0][1]
+ max_x = 0
+ max_y = 0
+ for point in points:
+ if point[0] < min_x:
+ min_x = point[0]
+ if point[0] > max_x:
+ max_x = point[0]
+ if point[1] < min_y:
+ min_y = point[1]
+ if point[1] > max_y:
+ max_y = point[1]
+ # add the tool size
+ if self.tool['name'] == 'stamp':
+ wr, hr = self.stamp_dimentions
+ min_x = min_x - wr
+ min_y = min_y - wr
+ max_x = max_x + hr
+ max_y = max_y + hr
+ else:
+ size = self.tool['line size']
+ min_x = min_x - size * 2
+ min_y = min_y - size * 2
+ max_x = max_x + size * 2
+ max_y = max_y + size * 2
+ return (min_x, min_y, max_x - min_x, max_y - min_y)
def mousemove(self, widget, event):
"""Make the Area object (GtkDrawingArea)
@@ -423,33 +476,26 @@ class Area(gtk.DrawingArea):
"""
x = event.x
y = event.y
- state = event.state
+ state = event.get_state()
self.x_cursor, self.y_cursor = int(x), int(y)
coords = int(x), int(y)
if self.tool['name'] in ['rectangle', 'ellipse', 'line']:
- if (state & gtk.gdk.SHIFT_MASK) or \
+ if (state & Gdk.ModifierType.SHIFT_MASK) or \
self.keep_shape_ratio:
if self.tool['name'] in ['rectangle', 'ellipse']:
coords = self._keep_selection_ratio(coords)
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 & Gdk.ModifierType.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,98 +504,85 @@ 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'])
- elif self.tool['name'] == 'marquee-rectangular' and \
- not self.selmove:
- if (state & gtk.gdk.CONTROL_MASK) or \
- self.keep_aspect_ratio:
- coords = self._keep_selection_ratio(coords)
- self.d.selection(widget, coords)
- # selected
- elif self.tool['name'] == 'marquee-rectangular' and \
- self.selmove:
- if not self.sel_get_out:
- self.d.moveSelection(widget, coords)
+ elif self.tool['name'] == 'marquee-rectangular':
+ if self._selmove:
+ # is inside a selected area, move it
+ self.d.move_selection(widget, coords)
+ else:
+ # create a selected area
+ if (state & Gdk.ModifierType.CONTROL_MASK) or \
+ self.keep_aspect_ratio:
+ coords = self._keep_selection_ratio(coords)
+ self.d.selection(widget, coords)
elif self.tool['name'] == 'freeform':
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):
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
+ # define area to update
+ last_coords = (self.last_x_cursor, self.last_y_cursor)
+ area = self.calculate_damaged_area([last_coords, coords])
+ widget.queue_draw_area(*area)
+ if self.tool['name'] == 'marquee-rectangular':
+ sel_x, sel_y, sel_width, sel_height = \
+ self.get_selection_bounds()
+ # show appropiate cursor
+ 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.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.CROSS))
else:
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.FLEUR))
- elif self.tool['name'] == 'freeform' and not self.selmove:
+ elif self.tool['name'] == 'freeform':
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)
+ Gdk.event_request_motions(event)
def mouseup(self, widget, event):
"""Make the Area object (GtkDrawingArea)
@@ -561,21 +594,19 @@ class Area(gtk.DrawingArea):
"""
coords = int(event.x), int(event.y)
if self.tool['name'] in ['rectangle', 'ellipse', 'line']:
- if (event.state & gtk.gdk.SHIFT_MASK) or \
+ if (event.get_state() & Gdk.ModifierType.SHIFT_MASK) or \
self.keep_shape_ratio:
if self.tool['name'] in ['rectangle', 'ellipse']:
coords = self._keep_selection_ratio(coords)
if self.tool['name'] == 'line':
coords = self._keep_line_ratio(coords)
- width, height = self.window.get_size()
+ width, height = self.get_size()
private_undo = False
- if self.desenha or self.sel_get_out:
+ if self.desenha:
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'])
@@ -584,54 +615,26 @@ class Area(gtk.DrawingArea):
self.d.square(widget, event, coords, False, self.tool['fill'])
elif self.tool['name'] == 'marquee-rectangular':
- if self.selmove == False:
- 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.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
- self.selmove = True
- self.sel_get_out = False
+ if self.is_selected() and not self._selmove:
+ self.create_selection_surface()
self.emit('select')
- elif self.sel_get_out: # get out of the func selection
- self.getout()
- try:
- del(self.d.pixbuf_resize)
- except:
- pass
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
- widget.queue_draw()
- self.enableUndo(widget)
- elif self.selmove:
- self.orig_x = self.orig_x + coords[0] - self.oldx
- self.orig_y = self.orig_y + coords[1] - self.oldy
- self.emit('select')
- private_undo = True
+ 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
elif self.tool['name'] == 'bucket':
if FALLBACK_FILL:
- if self.tool['stroke color'] is not None:
- stroke_color = self.tool['stroke color']
- color_r = int(stroke_color.red_float * 65535)
- color_g = int(stroke_color.green_float * 65535)
- color_b = int(stroke_color.blue_float * 65535)
- else:
- color_r, color_g, color_b = 0, 0, 0
- cmap = self.pixmap.get_colormap()
- fill_color = \
- cmap.alloc_color(color_r, color_g, color_b).pixel
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
- gobject.idle_add(self.flood_fill, coords[0], coords[1],
- fill_color)
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.WATCH))
+ GObject.idle_add(self.flood_fill, coords[0], coords[1])
else:
- width, height = self.window.get_size()
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
- gobject.idle_add(self.fast_flood_fill, widget, coords[0],
+ width, height = self.get_size()
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.WATCH))
+ GObject.idle_add(self.fast_flood_fill, widget, coords[0],
coords[1], width, height)
elif self.tool['name'] == 'triangle':
@@ -660,29 +663,50 @@ class Area(gtk.DrawingArea):
if self.tool['name'] in ['brush', 'eraser', 'rainbow', 'pencil',
'stamp']:
self.last = []
- widget.queue_draw()
+ self.d.finish_trace(self)
self.drawing = False
self.desenha = False
if not private_undo and self.tool['name'] != 'bucket':
# We have to avoid saving an undo state if the bucket tool
# is selected because this undo state is called before the
- # gobject.idle_add (with the fill_flood function) finishes
+ # GObject.idle_add (with the fill_flood function) finishes
# and an unconsistent undo state is saved
- self.enableUndo(widget)
+ self.enable_undo()
+ widget.queue_draw()
+ self.d.clear_control_points()
def fast_flood_fill(self, widget, x, y, width, height):
fill(self.pixmap, self.gc, x, y, width,
height, self.gc_line.foreground.pixel)
widget.queue_draw()
- self.enableUndo(widget)
- display = gtk.gdk.display_get_default()
- cursor = gtk.gdk.cursor_new_from_name(display, 'paint-bucket')
- self.window.set_cursor(cursor)
-
- def flood_fill(self, x, y, fill_color):
- width, height = self.window.get_size()
+ self.enable_undo()
+ display = Gdk.Display.get_default()
+ cursor = Gdk.Cursor.new_from_name(display, 'paint-bucket')
+ self.get_window().set_cursor(cursor)
+
+ def flood_fill(self, x, y):
+ stroke_color = self.tool['cairo_stroke_color']
+ r, g, b = stroke_color[0], stroke_color[1], stroke_color[2]
+
+ # pack the color in a int as 0xAARRGGBB
+ fill_color = 0xff000000 + \
+ (int(r * 255 * 65536) + \
+ int(g * 255 * 256) + \
+ int(b * 255))
+ logging.error('fill_color %d', fill_color)
+
+ # load a array with the surface data
+ for array_type in ['H', 'I', 'L']:
+ pixels = array.array(array_type)
+ if pixels.itemsize == 4:
+ break
+ else:
+ raise AssertionError()
+ pixels.fromstring(self.drawing_canvas.get_data())
- gdk_image = self.pixmap.get_image(0, 0, width, height)
+ # process the pixels in the array
+ width = self.drawing_canvas.get_width()
+ height = self.drawing_canvas.get_height()
def within(x, y):
if x < 0 or x >= width:
@@ -695,44 +719,57 @@ class Area(gtk.DrawingArea):
return
edge = [(x, y)]
- old_color = gdk_image.get_pixel(x, y)
+ old_color = pixels[x + y * width]
if old_color == fill_color:
logging.debug('Already filled')
return
- gdk_image.put_pixel(x, y, fill_color)
+ pixels[x + y * width] = fill_color
while len(edge) > 0:
newedge = []
for (x, y) in edge:
for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
if within(s, t) and \
- gdk_image.get_pixel(s, t) == old_color:
- gdk_image.put_pixel(s, t, fill_color)
+ pixels[s + t * width] == old_color:
+ pixels[s + t * width] = fill_color
newedge.append((s, t))
edge = newedge
- self.pixmap.draw_image(self.gc, gdk_image, 0, 0, 0, 0, width, height)
+ # create a updated drawing_canvas
+ self.drawing_canvas = cairo.ImageSurface.create_for_data(pixels,
+ cairo.FORMAT_ARGB32, width, height)
+ self.setup(width, height)
+
self.queue_draw()
- self.enableUndo(self)
+ self.enable_undo()
- display = gtk.gdk.display_get_default()
- cursor = gtk.gdk.cursor_new_from_name(display, 'paint-bucket')
- self.window.set_cursor(cursor)
+ display = Gdk.Display.get_default()
+ cursor = Gdk.Cursor.new_from_name(display, 'paint-bucket')
+ self.get_window().set_cursor(cursor)
def pick_color(self, x, y):
- gdk_image = self.pixmap.get_image(x, y, 1, 1)
- pixel = gdk_image.get_pixel(0, 0)
- cmap = gdk_image.get_colormap()
- gdk_color = cmap.query_color(pixel)
+ # create a new 1x1 cairo surface
+ cairo_surface = cairo.ImageSurface(cairo.FORMAT_RGB24, 1, 1)
+ cairo_context = cairo.Context(cairo_surface)
+ # translate xlib_surface so that target pixel is at 0, 0
+ cairo_context.set_source_surface(self.drawing_canvas, -x, -y)
+ cairo_context.rectangle(0, 0, 1, 1)
+ cairo_context.set_operator(cairo.OPERATOR_SOURCE)
+ cairo_context.fill()
+ cairo_surface.flush()
+ # Read the pixel
+ pixels = cairo_surface.get_data()
+ red = ord(pixels[2]) * 256
+ green = ord(pixels[1]) * 256
+ blue = ord(pixels[0]) * 256
+
+ stroke_color = Gdk.Color(red, green, blue)
# set in the area
- pixmap_cmap = self.pixmap.get_colormap()
- stroke_color = pixmap_cmap.alloc_color(gdk_color)
- self.tool['stroke color'] = stroke_color
- self.set_stroke_color(self.tool['stroke color'])
+ self.set_stroke_color(stroke_color)
- # update the stroke color button
+ # update the stroke_color in the button
self.activity.get_toolbar_box().brush_button.set_color(stroke_color)
self.activity.get_toolbar_box().brush_button.stop_stamping()
@@ -759,11 +796,12 @@ class Area(gtk.DrawingArea):
"""
if self.is_selected():
# Change stamp, get it from selection:
- width, height = self.pixmap_sel.get_size()
- self.pixbuf_stamp = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False,
- 8, width, height)
- self.pixbuf_stamp.get_from_drawable(self.pixmap_sel,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, width, height)
+ pixbuf_data = StringIO.StringIO()
+ self.get_selection().write_to_png(pixbuf_data)
+ pxb_loader = GdkPixbuf.PixbufLoader.new_with_type('png')
+ pxb_loader.write(pixbuf_data.getvalue())
+
+ self.pixbuf_stamp = pxb_loader.get_pixbuf()
self.stamp_size = 0
# Set white color as transparent:
stamp_alpha = self.pixbuf_stamp.add_alpha(True, 255, 255, 255)
@@ -790,7 +828,7 @@ class Area(gtk.DrawingArea):
wr, hr = int(stamp_size * w * 1.0 / h), stamp_size
self.stamp_dimentions = wr, hr
self.resized_stamp = self.pixbuf_stamp.scale_simple(wr, hr,
- gtk.gdk.INTERP_HYPER)
+ GdkPixbuf.InterpType.HYPER)
# Remove selected area
self.getout()
@@ -803,9 +841,8 @@ class Area(gtk.DrawingArea):
@param self -- the Area object (GtkDrawingArea)
"""
logging.debug('Area.undo(self)')
- width, height = self.window.get_size()
- if self.selmove:
+ if self.is_selected():
self.getout(undo=True)
if self.text_in_progress:
@@ -815,14 +852,12 @@ class Area(gtk.DrawingArea):
if self._undo_index > 0:
self._undo_index -= 1
- undo_pix = self._undo_list[self._undo_index]
- self.pixmap.draw_drawable(self.gc, undo_pix, 0, 0, 0, 0, -1, -1)
+ undo_surface = self._undo_list[self._undo_index]
+ self.drawing_ctx.set_source_surface(undo_surface, 0, 0)
+ self.drawing_ctx.set_operator(cairo.OPERATOR_SOURCE)
+ self.drawing_ctx.paint()
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):
@@ -831,41 +866,36 @@ class Area(gtk.DrawingArea):
@param self -- the Area object (GtkDrawingArea)
"""
logging.debug('Area.redo(self)')
- width, height = self.window.get_size()
- if self.selmove:
+ if self.is_selected():
self.getout()
if self._undo_index < len(self._undo_list) - 1:
self._undo_index += 1
- undo_pix = self._undo_list[self._undo_index]
- self.pixmap.draw_drawable(self.gc, undo_pix, 0, 0, 0, 0, -1, -1)
+ undo_surface = self._undo_list[self._undo_index]
+ self.drawing_ctx.set_source_surface(undo_surface, 0, 0)
+ self.drawing_ctx.set_operator(cairo.OPERATOR_SOURCE)
+ self.drawing_ctx.paint()
self.queue_draw()
self.emit('redo')
- def enableUndo(self, widget, size=None, overrite=False):
+ def enable_undo(self, overrite=False):
"""Keep the last change in a list for Undo/Redo commands.
- @param self -- the Area object (GtkDrawingArea)
- @param widget -- the Area object (GtkDrawingArea)
-
"""
- #logging.debug('Area.enableUndo(self,widget)')
-
- width, height = self.window.get_size()
- # We need to pass explicitly the size on set up, because the
- # window size is not allocated yet.
- if size is not None:
- width, height = size
-
if len(self._undo_list) == 0:
# first undo pix, start index:
self._undo_index = 0
elif len(self._undo_list) == MAX_UNDO_STEPS:
# drop the oldest undo pix:
self._undo_list.pop(0)
+
+ # it could be at the middle of the list (clicked many
+ # times undo) and after that draw anything, so we should
+ # discart the next redos because they are obsolete now.
+ self._undo_list = self._undo_list[:self._undo_index]
else:
self._undo_index += 1
# Forget the redos after this one:
@@ -877,11 +907,17 @@ class Area(gtk.DrawingArea):
if overrite and self._undo_index != 0:
self._undo_index -= 1
- undo_pix = gtk.gdk.Pixmap(widget.window, width, height, -1)
- undo_pix.draw_drawable(self.gc, self.pixmap,
- 0, 0, 0, 0, width, height)
+ # copy the drawing surface in a new surface
+ width = self.drawing_canvas.get_width()
+ height = self.drawing_canvas.get_height()
+ undo_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
+ undo_ctx = cairo.Context(undo_surface)
+ undo_ctx.set_source_surface(self.drawing_canvas, 0, 0)
+ undo_ctx.set_operator(cairo.OPERATOR_SOURCE)
+ undo_ctx.paint()
+ undo_surface.flush()
- self._undo_list.append(undo_pix)
+ self._undo_list.append(undo_surface)
self.emit('action-saved')
@@ -892,7 +928,7 @@ class Area(gtk.DrawingArea):
@param self -- the Area object (GtkDrawingArea)
"""
- clipBoard = gtk.Clipboard()
+ clipBoard = Gtk.Clipboard()
if 'SUGAR_ACTIVITY_ROOT' in os.environ:
temp_dir = os.path.join(os.environ.get('SUGAR_ACTIVITY_ROOT'),
'instance')
@@ -902,25 +938,21 @@ class Area(gtk.DrawingArea):
f, tempPath = tempfile.mkstemp(suffix='.png', dir=temp_dir)
del f
- if self.selmove:
- size = self.pixmap_sel.get_size()
- pixbuf_copy = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8,
- size[0], size[1])
- pixbuf_copy.get_from_drawable(self.pixmap_sel,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, size[0], size[1])
- pixbuf_copy.save(tempPath, 'png')
- os.chmod(tempPath, 0604)
-
- clipBoard.set_with_data([('text/uri-list', 0, 0)],
- self._copyGetFunc, self._copyClearFunc, tempPath)
- else:
- logging.debug('Area.copy(self): Please select some area first')
+ selection_surface = self.get_selection()
+ if selection_surface is None:
+ selection_surface = self.drawing_canvas
+ logging.error('Saving file %s', tempPath)
+ selection_surface.write_to_png(tempPath)
+ os.chmod(tempPath, 0604)
- def _copyGetFunc(self, clipboard, selection_data, info, data):
+ clipBoard.set_with_data([('text/uri-list', 0, 0)],
+ self._copy_get_func, self._copy_clear_func, tempPath)
+
+ def _copy_get_func(self, clipboard, selection_data, info, data):
""" Determine type data to put in clipboard
@param self -- the Area object (GtkDrawingArea)
- @param clipboard -- a gtk.Clipboard object
+ @param clipboard -- a Gtk.Clipboard object
@param selection_data -- data of selection
@param info -- the app assigned integer associated with a target
@param data -- user data (tempPath)
@@ -930,11 +962,11 @@ class Area(gtk.DrawingArea):
if selection_data.target == "text/uri-list":
selection_data.set_uris(['file://' + tempPath])
- def _copyClearFunc(self, clipboard, data):
+ def _copy_clear_func(self, clipboard, data):
""" Clear the clipboard
@param self -- the Area object (GtkDrawingArea)
- @param clipboard -- a gtk.Clipboard object
+ @param clipboard -- a Gtk.Clipboard object
@param data -- user data (tempPath)
"""
if (data != None):
@@ -944,58 +976,46 @@ class Area(gtk.DrawingArea):
def drag_data_received(self, w, context, x, y, data, info, time):
if data and data.format == 8:
- self.loadImage(urlparse(data.data).path, self)
+ self.load_image(urlparse(data.data).path, self)
context.finish(True, False, time)
else:
context.finish(False, False, time)
- def past(self, widget):
- """ Past image.
- Past image that is in pixmap
+ def paste(self, widget):
+ """ Paste image.
+ Paste image that is in canvas
@param self -- the Area object (GtkDrawingArea)
"""
- width, height = self.window.get_size()
+ width, height = self.get_size()
tempPath = os.path.join("/tmp", "tempFile")
tempPath = os.path.abspath(tempPath)
- clipBoard = gtk.Clipboard()
+ clipBoard = Gtk.Clipboard()
if clipBoard.wait_is_image_available():
- self.getout(True, widget)
+ logging.debug('Area.paste(self): Wait is image available')
+ self.getout(True)
pixbuf_sel = clipBoard.wait_for_image()
- size = int(pixbuf_sel.get_width()), int(pixbuf_sel.get_height())
- self.pixmap_sel = gtk.gdk.Pixmap(self.window, size[0], size[1], -1)
- self.pixmap_sel.draw_pixbuf(self.gc, pixbuf_sel,
- 0, 0, 0, 0, size[0], size[1],
- dither=gtk.gdk.RGB_DITHER_NORMAL, x_dither=0, y_dither=0)
+ width, height = pixbuf_sel.get_width(), pixbuf_sel.get_height()
- self.selmove = True
+ self.temp_ctx.rectangle(0, 0, width, height)
+ Gdk.cairo_set_source_pixbuf(self.temp_ctx, pixbuf_sel, 0, 0)
+ self.temp_ctx.paint()
+ self.set_selection_bounds(0, 0, width, height)
self.desenha = True
- self.sel_get_out = False
- self.orig_x, self.orig_y = 0, 0
-
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- 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.tool['name'] = 'marquee-rectangular'
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
+ self.tool['name'] = 'marquee-rectangular' # TODO: change toolbar?
self.emit('select')
elif clipBoard.wait_is_uris_available():
+ logging.debug('Area.paste(self): is uris available')
selection = clipBoard.wait_for_contents('text/uri-list')
if selection != None:
for uri in selection.get_uris():
- self.loadImage(urlparse(uri).path, self)
+ self.load_image(urlparse(uri).path, self)
else:
- self.loadImage(tempPath, self)
- logging.debug('Area.past(self): Load from clipboard fails')
+ self.load_image(tempPath, self)
+ logging.debug('Area.paste(self): Load from clipboard fails')
logging.debug('loading from tempPath')
self.queue_draw()
@@ -1004,23 +1024,42 @@ class Area(gtk.DrawingArea):
"""Set fill color.
@param self -- the Area object (GtkDrawingArea)
- @param color -- a gdk.Color object
+ @param color -- a Gdk.Color object
"""
- self.gc.set_foreground(color)
+ alpha = self.tool['alpha']
+ red = color.red / 65535.0
+ green = color.green / 65535.0
+ blue = color.blue / 65535.0
+ self.tool['cairo_fill_color'] = (red, green, blue, alpha)
def set_stroke_color(self, color):
- """Set stroke color.
+ """Set cairo_stroke_color.
@param self -- the Area object (GtkDrawingArea)
- @param color -- a gdk.Color object
+ @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)
- self.activity.textview.modify_text(gtk.STATE_NORMAL, color)
+ alpha = self.tool['alpha']
+ red = color.red / 65535.0
+ green = color.green / 65535.0
+ blue = color.blue / 65535.0
+ self.tool['cairo_stroke_color'] = (red, green, blue, alpha)
+ self.activity.textview.modify_text(Gtk.StateType.NORMAL, color)
+
+ def set_alpha(self, alpha):
+ """
+ Set the alpha value used to draw
+ @ param alpha -- float between 0.0 and 1.0
+ """
+ self.tool['alpha'] = alpha
+ stroke_color = self.tool['cairo_stroke_color']
+ self.tool['cairo_stroke_color'] = (stroke_color[0], stroke_color[1],
+ stroke_color[2], alpha)
+
+ fill_color = self.tool['cairo_fill_color']
+ self.tool['cairo_fill_color'] = (fill_color[0], fill_color[1],
+ fill_color[2], alpha)
def grayscale(self, widget):
"""Apply grayscale effect.
@@ -1044,41 +1083,35 @@ class Area(gtk.DrawingArea):
"""
- def proc_invert_color(temp_pix):
- try:
- import numpy
- # HACK: This numpy version has a bug and breaks the
- # 'invert_color' function
- # http://bugs.sugarlabs.org/ticket/3509
- if numpy.__version__ == '1.6.1':
- logging.warning('You have installed a version of numpy '
- '(1.6.1) that has a bug and can\'t be '
- 'used. Using string module instead '
- '(slower)')
- raise ImportWarning
- pix_manip2 = temp_pix.get_pixels_array()
- pix_manip = numpy.ones(pix_manip2.shape, dtype=numpy.uint8) \
- * 255
- pix_manip2 = pix_manip - pix_manip2
- temp_pix = gtk.gdk.pixbuf_new_from_array(pix_manip2,
- gtk.gdk.COLORSPACE_RGB, 8)
- except (ImportError, ImportWarning):
- import string
- a = temp_pix.get_pixels()
- b = len(a) * ['\0']
- for i in range(len(a)):
- b[i] = chr(255 - ord(a[i]))
- buff = string.join(b, '')
- temp_pix = gtk.gdk.pixbuf_new_from_data(buff,
- temp_pix.get_colorspace(),
- temp_pix.get_has_alpha(),
- temp_pix.get_bits_per_sample(),
- temp_pix.get_width(),
- temp_pix.get_height(),
- temp_pix.get_rowstride())
- return temp_pix
+ def internal_invert(self, old_cursor):
+ # load a array with the surface data
+ for array_type in ['H', 'I', 'L']:
+ pixels = array.array(array_type)
+ if pixels.itemsize == 4:
+ break
+ else:
+ raise AssertionError()
+ pixels.fromstring(self.drawing_canvas.get_data())
- self._do_process(widget, proc_invert_color)
+ # process the pixels in the array
+ new_array = array.array(pixels.typecode, len(pixels) * [0])
+ for i in range(len(pixels)):
+ new_array[i] = 0xffffffff - pixels[i] | 0xff000000
+
+ # create a updated drawing_canvas
+ width = self.drawing_canvas.get_width()
+ height = self.drawing_canvas.get_height()
+ self.drawing_canvas = cairo.ImageSurface.create_for_data(new_array,
+ cairo.FORMAT_ARGB32, width, height)
+ self.setup(width, height)
+
+ self.queue_draw()
+ self.enable_undo()
+ self.get_window().set_cursor(old_cursor)
+
+ old_cursor = self.get_window().get_cursor()
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+ GObject.idle_add(internal_invert, self, old_cursor)
def mirror(self, widget, horizontal=True):
"""Apply mirror horizontal/vertical effect.
@@ -1096,95 +1129,57 @@ class Area(gtk.DrawingArea):
self._do_process(widget, proc_mirror)
def _do_process(self, widget, apply_process):
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
- gobject.idle_add(self._do_process_internal, widget, apply_process)
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+ GObject.idle_add(self._do_process_internal, widget, apply_process)
+
+ def _surface_to_pixbuf(self, surface):
+ # copy from the surface to the pixbuf
+ pixbuf_data = StringIO.StringIO()
+ surface.write_to_png(pixbuf_data)
+ pxb_loader = GdkPixbuf.PixbufLoader.new_with_type('png')
+ pxb_loader.write(pixbuf_data.getvalue())
+ return pxb_loader.get_pixbuf()
+
+ def _pixbuf_to_context(self, pixbuf, context, x=0, y=0):
+ # copy from the pixbuf to the drawing context
+ context.save()
+ context.translate(x, y)
+ Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
+ context.paint()
+ context.restore()
def _do_process_internal(self, widget, apply_process):
- width, height = self.window.get_size()
-
- if self.selmove:
- size = self.pixmap_sel.get_size()
- temp_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
- size[0], size[1])
- temp_pix.get_from_drawable(self.pixmap_sel,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, size[0], size[1])
+ if self.is_selected():
+ x, y, _width, _height = self.get_selection_bounds()
+ surface = self.get_selection()
else:
- temp_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
- width, height)
- temp_pix.get_from_drawable(self.pixmap,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, width, height)
+ x, y = 0, 0
+ surface = self.drawing_canvas
- temp_pix = apply_process(temp_pix)
+ temp_pix = self._surface_to_pixbuf(surface)
- if self.selmove:
- self.pixmap_sel.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
- size[0], size[1], dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
-
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- 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)
+ # process the pixbuf
+ temp_pix = apply_process(temp_pix)
- else:
- self.pixmap.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
- width, height, dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
+ self._pixbuf_to_context(temp_pix, self.drawing_ctx, x, y)
+ self.create_selection_surface()
del temp_pix
self.queue_draw()
- if not self.selmove:
- self.enableUndo(widget)
+ if not self.is_selected():
+ self.enable_undo()
self.set_tool_cursor()
- def drain_events(self, block=gtk.FALSE):
- 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.
@param self -- the Area object (GtkDrawingArea)
@param widget -- the Area object (GtkDrawingArea)
"""
- self._rotate(widget, 90)
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+ GObject.idle_add(self._rotate, widget, 90)
def rotate_right(self, widget):
"""Rotate the image.
@@ -1192,7 +1187,8 @@ class Area(gtk.DrawingArea):
@param self -- the Area object (GtkDrawingArea)
@param widget -- the Area object (GtkDrawingArea)
"""
- self._rotate(widget, 270)
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+ GObject.idle_add(self._rotate, widget, 270)
def _rotate(self, widget, angle):
"""Rotate the image.
@@ -1200,71 +1196,36 @@ class Area(gtk.DrawingArea):
@param self -- the Area object (GtkDrawingArea)
@param widget -- the Area object (GtkDrawingArea)
"""
- width, height = self.window.get_size()
-
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
- self.drain_events()
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
- if self.selmove:
- size = self.pixmap_sel.get_size()
- temp_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
- size[0], size[1])
- temp_pix.get_from_drawable(self.pixmap_sel,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, size[0], size[1])
+ if self.is_selected():
+ x, y, width, height = self.get_selection_bounds()
+ surface = self.get_selection()
else:
- temp_pix = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8,
- width, height)
- temp_pix.get_from_drawable(self.pixmap,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, width, height)
+ x, y = 0, 0
+ width, height = self.get_size()
+ surface = self.drawing_canvas
- temp_pix = temp_pix.rotate_simple(angle)
-
- if self.selmove:
- try:
- self.d.pixbuf_resize = \
- self.d.pixbuf_resize.rotate_simple(angle)
- except:
- pass
-
- try:
- del(self.pixmap_sel)
- except:
- pass
+ temp_pix = self._surface_to_pixbuf(surface)
- self.pixmap_sel = gtk.gdk.Pixmap(widget.window,
- size[1], size[0], -1)
- self.pixmap_sel.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
- width=-1, height=-1, dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
+ temp_pix = temp_pix.rotate_simple(angle)
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- 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)
+ # copy from the pixbuf to the drawing context
+ if self.is_selected():
+ self.set_selection_bounds(x, y, height, width)
else:
- win = self.window
- self.set_size_request(height, width)
- self.pixmap = gtk.gdk.Pixmap(win, height, width, -1)
- self.pixmap.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
- height, width, dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
- self.pixmap_temp = gtk.gdk.Pixmap(win, height, width, -1)
- self.pixmap_temp.draw_pixbuf(self.gc, temp_pix, 0, 0, 0, 0,
- height, width, dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
-
- self.activity.center_area()
+ # create a new canvas with permuted dimensions
+ self.drawing_canvas = None
+ self.setup(height, width)
+
+ self._pixbuf_to_context(temp_pix, self.drawing_ctx, x, y)
del temp_pix
self.queue_draw()
- if not self.selmove:
- self.enableUndo(widget)
+ if not self.is_selected():
+ self.enable_undo()
self.set_tool_cursor()
def can_undo(self):
@@ -1284,45 +1245,81 @@ class Area(gtk.DrawingArea):
def is_selected(self):
"""
Return True if there is some thing selected
-
- @param self -- the Area object (GtkDrawingArea)
"""
- if self.selmove:
- return True
- else:
- return False
+ return self.get_selection_bounds() != (0, 0, 0, 0)
+
+ def clear_selection(self):
+ self.set_selection_bounds(0, 0, 0, 0)
+ self._selection_horizontal_scale = 1.0
+ self._selection_vertical_scale = 1.0
- def _set_selection_bounds(self, x1, y1, x2, y2):
+ def set_selection_bounds(self, x, y, width, height):
"""
Set selection bounds
-
- @param self -- the Area object (GtkDrawingArea)
- @param x1,y1,x2,y2 -- the coords of limit points
+ @param x, y, width, height - the rectangle to define the area
"""
- self._selection_corners = (x1, y1, x2, y2)
+ self._selection_bounds = (x, y, width, height)
+
+ def set_selection_start(self, x, y):
+ self._selection_bounds = (x, y, self._selection_bounds[2],
+ self._selection_bounds[3])
def get_selection_bounds(self):
"""
- Get points of selection
-
- @param self -- the Area object (GtkDrawingArea)
-
- @return selection_corners
-
+ @return x1, y1, width, height - the rectangle to define the area
"""
- 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()
+ x, y = self._selection_bounds[0], self._selection_bounds[1]
+ width, height = self._selection_bounds[2], self._selection_bounds[3]
+ width = width * self._selection_horizontal_scale
+ height = height * self._selection_vertical_scale
+ return (x, y, int(width), int(height))
+
+ def create_selection_surface(self, clear_background=True):
+ x, y, width, height = self.get_selection_bounds()
+ logging.error('create_selection_surface %s', (x, y, width, height))
+ self.selection_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ selection_ctx = cairo.Context(self.selection_surface)
+ selection_ctx.translate(-x, -y)
+ selection_ctx.set_source_surface(self.drawing_canvas)
+ selection_ctx.paint()
+ self.selection_resized_surface = None
+ if clear_background:
+ self.pending_clean_selection_background = True
+
+ def resize_selection_surface(self, horizontal_scale, vertical_scale):
+ x, y = self._selection_bounds[0], self._selection_bounds[1]
+ new_width = int(self .selection_surface.get_width() * horizontal_scale)
+ new_height = int(self.selection_surface.get_height() * vertical_scale)
+
+ # create a surface with the selection scaled to the new size
+ self.selection_resized_surface = cairo.ImageSurface(
+ cairo.FORMAT_ARGB32, new_width, new_height)
+ temp_ctx = cairo.Context(self.selection_resized_surface)
+ temp_ctx.scale(horizontal_scale, vertical_scale)
+ temp_ctx.set_source_surface(self.selection_surface)
+ temp_ctx.paint()
+
+ # draw over temp canvas
+ self.temp_ctx.save()
+ self.temp_ctx.translate(x, y)
+ self.temp_ctx.set_source_surface(self.selection_resized_surface)
+ self.temp_ctx.rectangle(0, 0, new_width, new_height)
+ self.temp_ctx.paint()
+ self.temp_ctx.restore()
+
+ self._selection_horizontal_scale = horizontal_scale
+ self._selection_vertical_scale = vertical_scale
+
+ def get_selection(self):
+ if self.selection_resized_surface is not None:
+ return self.selection_resized_surface
+ if self.selection_surface is not None:
+ return self.selection_surface
+ else:
+ return None
- def loadImage(self, name, widget=None):
+ def load_image(self, name, widget=None):
"""Load an image.
@param self -- Area instance
@@ -1330,36 +1327,31 @@ class Area(gtk.DrawingArea):
@param widget -- GtkDrawingArea
"""
- logging.debug('Area.loadImage Loading file %s', name)
-
- pixbuf = gtk.gdk.pixbuf_new_from_file(name)
- size = (int)(pixbuf.get_width()), (int)(pixbuf.get_height())
- #self.getout(True,widget)
- self.getout(True)
- #self.pixmap_sel = gtk.gdk.Pixmap(widget.window,size[0],size[1],-1)
- self.pixmap_sel = gtk.gdk.Pixmap(self.window, size[0], size[1], -1)
- self.pixmap_sel.draw_pixbuf(self.gc, pixbuf, 0, 0, 0, 0,
- size[0], size[1], dither=gtk.gdk.RGB_DITHER_NORMAL,
- x_dither=0, y_dither=0)
-
- self.sel_get_out = False
- self.selmove = True
+ logging.debug('Area.load_image Loading file %s', name)
+
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(name)
+ width, height = (int)(pixbuf.get_width()), (int)(pixbuf.get_height())
+
+ logging.debug('image size %d x %d', width, height)
+
+ # load in the selection surface
+ self.selection_surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,
+ width, height)
+ selection_ctx = cairo.Context(self.selection_surface)
+ self._pixbuf_to_context(pixbuf, selection_ctx)
+
+ # show in the temp context too
+ self.temp_ctx.save()
+ self.temp_ctx.translate(0, 0)
+ self.temp_ctx.set_source_surface(self.selection_surface)
+ self.temp_ctx.paint()
+ self.temp_ctx.restore()
+
+ self.set_selection_bounds(0, 0, width, height)
self.desenha = True
- self.orig_x, self.orig_y = 0, 0
- #width, height = widget.window.get_size()
- width, height = self.window.get_size()
-
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- 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._selmove = True
self.tool['name'] = 'marquee-rectangular'
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
self.emit('select')
self.queue_draw()
@@ -1374,20 +1366,13 @@ class Area(gtk.DrawingArea):
# If something is selected, the action will be saved
# after it is unselected
if not self.is_selected():
- self.enableUndo(self)
+ self.enable_undo()
def set_tool(self, tool):
'''
Method to configure all tools.
- @param - tool: a dictionary with the following keys:
- 'name': a string
- 'line size': a integer
- 'fill color': a gtk.gdk.Color object
- 'stroke color': a gtk.gdk.Color object
- 'line shape': a string - 'circle' or 'square', for now
- 'fill': a Boolean value
- 'vertices': a integer
+ @param - tool: a dictionary with the tool keys
'''
# logging.debug('Area.set_tool %s', tool)
self.tool = tool
@@ -1395,17 +1380,17 @@ class Area(gtk.DrawingArea):
if self.tool['line size'] is not None:
self.configure_line(self.tool['line size'])
- if self.tool['fill color'] is not None:
- self.set_fill_color(self.tool['fill color'])
- else:
- # use black
- self.set_fill_color(self.black)
+# if self.tool['fill color'] is not None:
+# self.set_fill_color(self.tool['fill color'])
+# else:
+# # use black
+# self.set_fill_color(self.black)
- if self.tool['stroke color'] is not None:
- self.set_stroke_color(self.tool['stroke color'])
- else:
- # use black
- self.set_stroke_color(self.black)
+# if self.tool['stroke color'] is not None:
+# self.set_stroke_color(self.tool['stroke color'])
+# else:
+# # use black
+# self.set_stroke_color(self.black)
except AttributeError:
pass
@@ -1420,49 +1405,56 @@ class Area(gtk.DrawingArea):
'eraser': 'eraser',
'bucket': 'paint-bucket'}
- display = gtk.gdk.display_get_default()
+ display = Gdk.Display.get_default()
if self.tool['name'] in cursors:
name = cursors[self.tool['name']]
- cursor = gtk.gdk.cursor_new_from_name(display, name)
+ cursor = Gdk.Cursor.new_from_name(display, name)
elif self.tool['name'] == 'marquee-rectangular':
- cursor = gtk.gdk.Cursor(gtk.gdk.CROSS)
+ cursor = Gdk.Cursor.new(Gdk.CursorType.CROSS)
else:
filename = os.path.join('images', self.tool['name'] + '.png')
- pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
# Decide which is the cursor hot spot offset:
if self.tool['name'] == 'stamp':
- hotspot_x, hotspot_y = 20, 38 # horizontal
+ hotspot_x, hotspot_y = 20, 38 # horizontal
# center and
# bottom
elif self.tool['name'] == 'picker':
- hotspot_x, hotspot_y = 1, 38 # bottom left
+ hotspot_x, hotspot_y = 1, 38 # bottom left
# corner
else:
- hotspot_x, hotspot_y = 0, 0
+ hotspot_x, hotspot_y = 0, 0
- cursor = gtk.gdk.Cursor(display, pixbuf, hotspot_x, hotspot_y)
- except gobject.GError:
+ cursor = Gdk.Cursor.new_from_pixbuf(display, pixbuf,
+ hotspot_x, hotspot_y)
+ except GObject.GError:
cursor = None
- self.window.set_cursor(cursor)
+ self.get_window().set_cursor(cursor)
- def getout(self, undo=False, widget=None):
- logging.debug('Area.getout')
+ def getout(self, undo=False):
+ """
+ Apply the selected area in the canvas.
- try:
- self.pixmap_sel
- size = self.pixmap_sel.get_size()
- self.pixmap.draw_drawable(self.gc, self.pixmap_sel, 0, 0,
- self.orig_x, self.orig_y, size[0], size[1])
- self.selmove = False
- if undo:
- if widget is not None:
- self.enableUndo(widget)
- else:
- self.enableUndo(self)
+ @param - undo: enable undo
+ """
- del(self.pixmap_sel)
- del(self.pixbuf_resize)
+ try:
+ # apply selection over canvas
+ if self.is_selected():
+ x, y, width, height = self.get_selection_bounds()
+ selection_surface = self.get_selection()
+ self.drawing_ctx.save()
+ self.drawing_ctx.translate(x, y)
+ self.drawing_ctx.set_source_surface(selection_surface)
+ self.drawing_ctx.rectangle(0, 0, width, height)
+ self.drawing_ctx.paint()
+ self.drawing_ctx.restore()
+ self.desenha = False
+
+ self.clear_selection()
+ if undo:
+ self.enable_undo()
except NameError, message:
logging.debug(message)
@@ -1470,50 +1462,38 @@ class Area(gtk.DrawingArea):
logging.debug('Unexpected error: %s', message)
def key_press(self, widget, event):
- if event.keyval == gtk.keysyms.BackSpace:
- if self.selmove:
- self.selmove = False
- try:
- del(self.pixmap_sel)
- del(self.pixbuf_resize)
- except:
- pass
+ if event.keyval == Gdk.KEY_BackSpace:
+ if self.is_selected():
+ # Remove selection
+ # TODO
if self.tool['name'] == 'marquee-rectangular':
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.CROSS))
widget.queue_draw()
- self.enableUndo(widget)
- elif event.keyval == gtk.keysyms.a and gtk.gdk.CONTROL_MASK:
- if self.selmove:
+ self.enable_undo()
+ elif event.keyval == Gdk.KEY_a and Gdk.ModifierType.CONTROL_MASK:
+ if self.is_selected():
self.getout()
- width, height = self.window.get_size()
+ width, height = self.get_size()
if self.tool['name'] == 'marquee-rectangular':
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR))
- self.pixmap_sel = gtk.gdk.Pixmap(self.window, width, height, -1)
- self.pixmap_sel.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- width, height)
- self.pixmap_temp.draw_drawable(self.gc, self.pixmap, 0, 0, 0, 0,
- width, height)
- self.pixmap.draw_rectangle(self.get_style().white_gc, True, 0, 0,
- 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.selmove = True
- self.sel_get_out = False
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorTypeFLEUR))
+ self.set_selection_bounds(0, 0, width - 1, height - 1)
self.emit('select')
widget.queue_draw()
- elif event.keyval == gtk.keysyms.d and gtk.gdk.CONTROL_MASK:
- if self.selmove:
- self.getout(True, widget)
+ elif event.keyval == Gdk.KEY_d and Gdk.ModifierType.CONTROL_MASK:
+ if self.is_selected():
+ self.getout(True)
if self.tool['name'] == 'marquee-rectangular':
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.CROSS))
widget.queue_draw()
- elif event.keyval == gtk.keysyms.Return:
- self.getout(True, widget)
+ elif event.keyval == Gdk.KEY_Return:
+ self.getout(True)
if self.tool['name'] == 'marquee-rectangular':
- self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.CROSS))
+ self.get_window().set_cursor(Gdk.Cursor.new(
+ Gdk.CursorType.CROSS))
widget.queue_draw()
def change_line_size(self, delta):
@@ -1524,9 +1504,11 @@ class Area(gtk.DrawingArea):
size = 1
self.tool['line size'] = size
self.configure_line(size)
+ # TODO: clip
self.queue_draw()
if self.tool['name'] == 'stamp':
self.resize_stamp(self.stamp_size + delta)
+ # TODO: clip
self.queue_draw()
def _keep_selection_ratio(self, coords):
diff --git a/Desenho.py b/Desenho.py
index d4572c9..e110aa2 100644
--- a/Desenho.py
+++ b/Desenho.py
@@ -61,14 +61,12 @@ Walter Bender (walter@laptop.org)
"""
-
-import pygtk
-pygtk.require('2.0')
-import gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import PangoCairo
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 +83,27 @@ 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 = []
+ self._last_points_used = self.points
+
+ def clear_control_points(self):
+ self._last_points_used = []
+
+ def line(self, widget, coords, temp):
"""Draw line.
@param self -- Desenho.Desenho instance
@@ -95,16 +111,21 @@ class Desenho:
@param coords -- Two value tuple
"""
- 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()
+ # TODO: clip
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,9 @@ class Desenho:
@param shape -- string (default 'circle')
"""
- widget.desenha = False
- self._trace(widget, widget.gc_eraser, coords, last, size, shape)
- #widget.queue_draw()
+ 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 +149,7 @@ class Desenho:
@param shape -- string (default 'circle')
"""
- widget.desenha = False
- self._trace(widget, widget.gc_brush, coords, last, size, shape)
+ self._trace(widget, coords, last)
def stamp(self, widget, coords, last, stamp_size=20):
"""Paint with stamp.
@@ -143,19 +161,25 @@ class Desenho:
@param stamp_size -- integer (default 20)
"""
+
widget.desenha = False
- gc = widget.gc_brush
width = widget.resized_stamp.get_width()
height = widget.resized_stamp.get_height()
dx = coords[0] - width / 2
dy = coords[1] - height / 2
- widget.pixmap.draw_pixbuf(gc, widget.resized_stamp,
- 0, 0, dx, dy, width, height)
- widget.queue_draw()
+ widget.drawing_ctx.save()
+ widget.drawing_ctx.translate(dx, dy)
+ widget.drawing_ctx.rectangle(dx, dy, width, height)
+ Gdk.cairo_set_source_pixbuf(widget.drawing_ctx, widget.resized_stamp,
+ 0, 0)
+ widget.drawing_ctx.paint()
+ widget.drawing_ctx.restore()
+
+ widget.queue_draw_area(dx, dy, width, height)
- 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 +191,62 @@ 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 = Gdk.color_parse(_color_str)
+ self._rainbow_counter += 1
+ if self._rainbow_counter > 11:
+ self._rainbow_counter = 0
+
+ widget.drawing_ctx.set_source_rgba(_color.red, _color.green,
+ _color.blue, 0.3)
+ self._old_trace(widget, coords, last)
- def _trace(self, widget, gc, coords, last, size, shape):
+ def _old_trace(self, widget, coords, last):
+ """
+ _old_trace is used only by rainbow
+ """
+ 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)
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)
+ 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
@@ -224,171 +258,184 @@ class Desenho:
else:
widget.queue_draw()
+ def finish_trace(self, widget):
+ widget.desenha = False
+ shape = widget.tool['line shape']
+ rounded = (shape == 'circle')
+ self._draw_polygon(widget, False, False, self.points, False, rounded)
+ if not rounded and len(self.points) == 1:
+ # draw a square if the mouse was not moved
+ size = widget.tool['line size']
+ coords = self.points[0]
+ widget.drawing_ctx.save()
+ if widget.tool['name'] == 'eraser':
+ color = (1.0, 1.0, 1.0, 1.0)
+ else:
+ color = widget.tool['cairo_stroke_color']
+ widget.drawing_ctx.set_source_rgba(*color)
+ 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()
+ widget.drawing_ctx.restore()
+
+ self.points = []
+
+ def _trace(self, widget, coords, last):
+ widget.desenha = True
+ size = widget.tool['line size']
+ shape = widget.tool['line shape']
+
+ rounded = (shape == 'circle')
+
+ self.points.append((coords[0], coords[1]))
+ if last:
+ self._draw_polygon(widget, True, False, self.points, False,
+ rounded)
+ self.clear_control_points()
+ if last:
+ x = min(coords[0], last[0])
+ width = max(coords[0], last[0]) - x
+ y = min(coords[1], last[1])
+ height = max(coords[1], last[1]) - y
+ # We add size to avoid drawing dotted lines
+ widget.queue_draw_area(x - size, y - size,
+ width + size * 2, height + size * 2)
+
def square(self, widget, event, coords, temp, fill):
"""Draw a square.
@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()
x, y, dx, dy, = self.adjust(widget, coords)
+ points = [(x, y), (x + dx, y), (x + dx, y + dy), (x, y + dy)]
+ self._draw_polygon(widget, temp, fill, points)
- pixmap.draw_drawable(widget.gc, widget.pixmap, 0, 0, 0, 0,
- width, height)
- if fill == True:
- pixmap.draw_rectangle(widget.gc, True, x, y, dx, dy)
- pixmap.draw_rectangle(widget.gc_line, False, x, y, dx, dy)
- widget.queue_draw()
+ def _draw_polygon(self, widget, temp, fill, points, closed=True,
+ rounded=False):
+ if not points:
+ return
+ if temp == True:
+ ctx = widget.temp_ctx
+ else:
+ ctx = widget.drawing_ctx
+
+ ctx.save()
+ ctx.new_path()
+ ctx.move_to(*points[0])
+ for point in points:
+ ctx.line_to(*point)
+ if closed:
+ ctx.close_path()
+ if rounded:
+ ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+ ctx.set_line_join(cairo.LINE_JOIN_ROUND)
+ else:
+ ctx.set_line_cap(cairo.LINE_CAP_SQUARE)
+ ctx.set_line_join(cairo.LINE_JOIN_MITER)
+ if fill:
+ ctx.set_source_rgba(*widget.tool['cairo_fill_color'])
+ ctx.set_line_width(0)
+ ctx.fill_preserve()
+
+ if widget.tool['name'] == 'eraser':
+ ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
+ else:
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+ ctx.set_line_width(widget.tool['line size'])
+ ctx.stroke()
+ ctx.restore()
+ self._last_points_used.extend(points)
+ area = widget.calculate_damaged_area(self._last_points_used)
+ widget.queue_draw_area(*area)
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)
dA = 2 * math.pi / 2
r = math.hypot(y, x)
- m = math.sin(A)
p = [(widget.oldx, widget.oldy)]
- p.append((widget.oldx + int(r * math.cos(A)),\
+ p.append((widget.oldx + int(r * math.cos(A)),
widget.oldy + int(r * math.sin(A))))
- p.append((widget.oldx + int(0.74 * r * math.cos(A + dA / 6)),\
+ p.append((widget.oldx + int(0.74 * r * math.cos(A + dA / 6)),
widget.oldy + int(0.74 * r * math.sin(A + dA / 6))))
- p.append((widget.oldx + int(2 * r * math.cos(A + dA / 6 + dA / 20)),\
+ p.append((widget.oldx + int(2 * r * math.cos(A + dA / 6 + dA / 20)),
widget.oldy + int(2 * r * math.sin(A + dA / 6 + dA / 20))))
p.append((widget.oldx +\
- int(2 * r * math.cos(A + dA / 6 - dA / 20 + dA / 6)),\
+ int(2 * r * math.cos(A + dA / 6 - dA / 20 + dA / 6)), \
widget.oldy +\
int(2 * r * math.sin(A + dA / 6 - dA / 20 + dA / 6))))
- p.append((widget.oldx + int(0.74 * r * math.cos(A + dA / 6 + dA / 6)),\
+ p.append((widget.oldx + int(0.74 * r * math.cos(A + dA / 6 + dA / 6)),
widget.oldy + int(0.74 * r * math.sin(A + dA / 6 + dA / 6))))
- p.append((widget.oldx + int(r * math.cos(A + dA / 2)),\
+ 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)
@@ -398,38 +445,23 @@ class Desenho:
widget.oldy + int(r * math.sin(A))), \
(widget.oldx + int(0.4 * r * math.cos(A + dA / 2)),
widget.oldy + int(0.4 * r * math.sin(A + dA / 2)))]
- for i in range(int(n) - 1):
+ for _i in range(int(n) - 1):
A = A + dA
p.append((widget.oldx + int(r * math.cos(A)), \
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)
@@ -437,158 +469,117 @@ class Desenho:
r = math.hypot(y, x)
p = [(widget.oldx + int(r * math.cos(A)), \
widget.oldy + int(r * math.sin(A)))]
- for i in range(int(n) - 1):
+ for _i in range(int(n) - 1):
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
- width, height = widget.window.get_size()
+ ctx = widget.drawing_ctx
- if coords[0] < widget.oldx:
- x = coords[0]
- else:
- x = widget.oldx
- if coords[1] < widget.oldy:
- y = coords[1]
- else:
- y = widget.oldy
-
- 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.new_path()
+ 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()
+
+ # TODO: clip
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
- width, height = widget.window.get_size()
+ ctx = widget.drawing_ctx
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.new_path()
+ 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()
+ # TODO: clip
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.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()
+
+ 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:
@@ -602,76 +593,54 @@ class Desenho:
else:
widget.text_in_progress = False
- try:
- # This works for a gtk.Entry
- text = widget.activity.textview.get_text()
- except AttributeError:
- # This works for a gtk.TextView
- buf = widget.activity.textview.get_buffer()
- start, end = buf.get_bounds()
- text = buf.get_text(start, end)
+ buf = widget.activity.textview.get_buffer()
+ start, end = buf.get_bounds()
+ text = buf.get_text(start, end, True)
+
+ textview = widget.activity.textview
+ tv_layout = textview.create_pango_layout(text)
- layout = widget.activity.textview.create_pango_layout(text)
+ ctx = widget.drawing_ctx
+
+ ctx.save()
+ ctx.new_path()
+ ctx.set_source_rgba(*widget.tool['cairo_stroke_color'])
+
+ pango_layout = PangoCairo.create_layout(ctx)
+ pango_layout.set_font_description(widget.get_font_description())
+ pango_layout.set_text(unicode(text), len(unicode(text)))
+
+ tv_alloc = textview.get_allocation()
+ ctx.move_to(tv_alloc.x, tv_alloc.y)
+ PangoCairo.show_layout(ctx, pango_layout)
+ ctx.stroke()
+ ctx.restore()
- widget.pixmap.draw_layout(widget.gc_brush,
- widget.oldx, widget.oldy, layout)
- widget.pixmap_temp.draw_layout(widget.gc,
- widget.oldx, widget.oldy, layout)
widget.activity.textview.hide()
+ widget.drawing_canvas.flush()
try:
widget.activity.textview.set_text('')
except AttributeError:
buf.set_text('')
- widget.enableUndo(widget)
-
+ widget.enable_undo()
+ # TODO: clip
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)
+ # TODO: clip
widget.queue_draw()
- def moveSelection(self, widget, coords):
+ def move_selection(self, widget, coords):
"""Move the selection.
@param self -- Desenho.Desenho instance
@@ -681,25 +650,34 @@ class Desenho:
@param pixbuf_copy -- For import image
"""
-
- width, height = widget.window.get_size()
-
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap,
- 0, 0, 0, 0, width, height)
+ widget.desenha = True
dx = int(coords[0] - widget.oldx)
dy = int(coords[1] - widget.oldy)
- size = widget.pixmap_sel.get_size()
-
- 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)
+ x, y, width, height = widget.get_selection_bounds()
+
+ if widget.pending_clean_selection_background:
+ # clear the selection background
+ widget.drawing_ctx.save()
+ widget.drawing_ctx.new_path()
+ 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.drawing_ctx.restore()
+ widget.pending_clean_selection_background = False
+
+ selection_surface = widget.get_selection()
+ widget.oldx = coords[0]
+ widget.oldy = coords[1]
+
+ new_x, new_y = x + dx, y + dy
+ widget.temp_ctx.save()
+ widget.temp_ctx.translate(new_x, new_y)
+ widget.temp_ctx.set_source_surface(selection_surface)
+ widget.temp_ctx.paint()
+ widget.temp_ctx.restore()
+ widget.set_selection_start(new_x, new_y)
widget.queue_draw()
@@ -711,173 +689,73 @@ class Desenho:
@param height_percent -- Percent of y scale
"""
- width, height = widget.window.get_size()
- widget.desenha = True
- widget.selmove = True
-
- #Create the pixbuf for future resizes
- try:
- self.pixbuf_resize
- except:
- size = widget.pixmap_sel.get_size()
- self.pixbuf_resize = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False,
- 8, size[0], size[1])
- self.pixbuf_resize.get_from_drawable(widget.pixmap_sel,
- gtk.gdk.colormap_get_system(), 0, 0, 0, 0, size[0], size[1])
-
- w = self.pixbuf_resize.get_width()
- h = self.pixbuf_resize.get_height()
- wr = int(w * width_percent)
- hr = int(h * height_percent)
-
- self._draw_selection(widget, wr, hr, is_preview=True)
-
# Add a timer for resize or update it if there is one already:
if self._resize_timer is not None:
- gobject.source_remove(self._resize_timer)
- self._resize_timer = gobject.timeout_add(RESIZE_DELAY,
- self._do_resize, widget, wr, hr)
+ GObject.source_remove(self._resize_timer)
+ self._resize_timer = GObject.timeout_add(RESIZE_DELAY,
+ self._do_resize, widget, width_percent, height_percent)
- def _do_resize(self, widget, wr, hr):
+ def _do_resize(self, widget, width_percent, height_percent):
"""Do the resize calculation.
-
"""
- resized = self.pixbuf_resize.scale_simple(wr, hr, gtk.gdk.INTERP_HYPER)
-
- #Copy the resized picture to pixmap_sel
- try:
- del (widget.pixmap_sel)
- except:
- pass
- widget.pixmap_sel = gtk.gdk.Pixmap(widget.window, wr, hr, -1)
- widget.pixmap_sel.draw_pixbuf(widget.get_style().white_gc, resized,
- 0, 0, 0, 0, wr, hr)
-
- #Draw the new pixmap_sel
- self._draw_selection(widget, wr, hr)
-
- # Clean the timer:
- self.resize_timer = None
- return False
-
- def _draw_selection(self, widget, wr, hr, is_preview=False):
- gc.collect()
- width, height = widget.window.get_size()
-
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap,
- 0, 0, 0, 0, width, height)
- if is_preview:
- widget.pixmap_temp.draw_drawable(widget.gc, widget.pixmap_sel,
- 0, 0, widget.orig_x, widget.orig_y, -1, -1)
- 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.desenha = True
+ widget.resize_selection_surface(float(width_percent),
+ float(height_percent))
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)
-
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.enable_undo(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
+ self.points.append((first[0], first[1]))
+ self._draw_polygon(widget, False, fill, self.points)
widget.last = []
- widget.polygon_start = True
- 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()
+ self.points = []
+ widget.enable_undo(overrite=True)
+ widget.queue_draw()
+ return
+
+ widget.desenha = True
+ # Display the polygon open in the temp canvas
+ self._draw_polygon(widget, True, False, self.points, closed=False)
+ self.clear_control_points()
def adjust(self, widget, coords, locked=False):
- width, height = widget.window.get_size()
+ width, height = widget.get_size()
if widget.oldx > int(coords[0]):
xi = int(coords[0])
xf = widget.oldx
diff --git a/OficinaActivity.py b/OficinaActivity.py
index 64dace4..29cb2d3 100644
--- a/OficinaActivity.py
+++ b/OficinaActivity.py
@@ -61,11 +61,11 @@ Walter Bender (walter@laptop.org)
"""
-import gtk
+from gi.repository import Gtk
import logging
-from sugar.activity import activity
-from sugar.graphics import style
+from sugar3.activity import activity
+from sugar3.graphics import style
from Area import Area
from toolbox import DrawToolbarBox
@@ -85,23 +85,23 @@ class OficinaActivity(activity.Activity):
logging.debug('Starting Paint activity (Oficina)')
- self.fixed = gtk.Fixed()
+ self.fixed = Gtk.Fixed()
self.fixed.show()
- self.fixed.modify_bg(gtk.STATE_NORMAL,
+ self.fixed.modify_bg(Gtk.StateType.NORMAL,
style.COLOR_WHITE.get_gdk_color())
+ self.textview = Gtk.TextView()
+ self.fixed.put(self.textview, 0, 0)
+
# These attributes are used in other classes, so they should be public
self.area = Area(self)
self.area.show()
self.fixed.put(self.area, 0, 0)
- self.textview = gtk.TextView()
- self.fixed.put(self.textview, 0, 0)
-
- sw = gtk.ScrolledWindow()
- sw.show()
- sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.set_canvas(sw)
+ self._sw = Gtk.ScrolledWindow()
+ self._sw.show()
+ self._sw.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
+ self.set_canvas(self._sw)
toolbar_box = DrawToolbarBox(self)
@@ -121,9 +121,9 @@ class OficinaActivity(activity.Activity):
self.canvas.add_with_viewport(self.fixed)
# to remove the border, we need set the shadowtype
# in the viewport child of the scrolledwindow
- self.canvas.get_children()[0].set_shadow_type(gtk.SHADOW_NONE)
+ self.canvas.get_children()[0].set_shadow_type(Gtk.ShadowType.NONE)
self.disconnect(self._setup_handle)
- self._setup_handle = self.fixed.connect('size_allocate',
+ self._setup_handle = self._sw.connect('size_allocate',
size_allocate_cb)
self._setup_handle = self.connect('map', map_cp)
@@ -140,27 +140,30 @@ 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.PolicyType.AUTOMATIC,
+ Gtk.PolicyType.AUTOMATIC)
else:
- self.canvas.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ self.canvas.set_policy(Gtk.PolicyType.NEVER,
+ Gtk.PolicyType.AUTOMATIC)
- self.area.loadImageFromJournal(pixbuf)
self.center_area()
self.canvas.add_with_viewport(self.fixed)
# to remove the border, we need set the shadowtype
# in the viewport child of the scrolledwindow
- self.canvas.get_children()[0].set_shadow_type(gtk.SHADOW_NONE)
+ self.canvas.get_children()[0].set_shadow_type(Gtk.ShadowType.NONE)
self.canvas.get_children()[0].set_border_width(0)
self.disconnect(self._setup_handle)
@@ -186,20 +189,16 @@ 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
the drawing area and center it on the canvas.
"""
- canvas_width = self.canvas.allocation.width
- canvas_height = self.canvas.allocation.height
+ canvas_width = self.canvas.get_allocation().width
+ canvas_height = self.canvas.get_allocation().height
area_width, area_height = self.area.get_size_request()
# Avoid 'x' and 'y' to be outside the screen
diff --git a/fontcombobox.py b/fontcombobox.py
index 58f9140..9de5e34 100644
--- a/fontcombobox.py
+++ b/fontcombobox.py
@@ -15,21 +15,22 @@
# 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
-import gtk
+from gi.repository import Gtk
+from gi.repository import GObject
FONT_BLACKLIST = ['cmex10', 'cmmi10', 'cmr10', 'cmsy10', 'esint10', 'eufm10',
'msam10', 'msbm10', 'rsfs10', 'wasy10']
-class FontComboBox(gtk.ComboBox):
+class FontComboBox(Gtk.ComboBox):
def __init__(self):
- gtk.ComboBox.__init__(self)
- font_renderer = gtk.CellRendererText()
- self.pack_start(font_renderer)
+ GObject.GObject.__init__(self)
+ font_renderer = Gtk.CellRendererText()
+ self.pack_start(font_renderer, True)
self.add_attribute(font_renderer, 'text', 0)
self.add_attribute(font_renderer, 'font', 0)
- font_model = gtk.ListStore(str)
+ font_model = Gtk.ListStore(str)
context = self.get_pango_context()
font_index = 0
@@ -39,15 +40,15 @@ class FontComboBox(gtk.ComboBox):
name = family.get_name()
if name not in FONT_BLACKLIST:
font_model.append([name])
- font_faces = []
- for face in family.list_faces():
- face_name = face.get_face_name()
- font_faces.append(face_name)
- self.faces[name] = font_faces
+ # TODO gtk3
+# font_faces = []
+# for face in family.list_faces():
+# face_name = face.get_face_name()
+# font_faces.append(face_name)
+# self.faces[name] = font_faces
- sorter = gtk.TreeModelSort(font_model)
- sorter.set_sort_column_id(0, gtk.SORT_ASCENDING)
- self.set_model(sorter)
+ font_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
+ self.set_model(font_model)
self.show()
def set_font_name(self, font_name):
diff --git a/setup.py b/setup.py
index d46c873..5b17d28 100755
--- a/setup.py
+++ b/setup.py
@@ -16,6 +16,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-from sugar.activity import bundlebuilder
+from sugar3.activity import bundlebuilder
if __name__ == "__main__":
bundlebuilder.start()
diff --git a/toolbox.py b/toolbox.py
index 8d58306..3d44877 100644
--- a/toolbox.py
+++ b/toolbox.py
@@ -63,24 +63,26 @@ Walter Bender (walter@laptop.org)
from gettext import gettext as _
-import gtk
-import pango
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import Pango
import logging
-from sugar.activity.activity import EditToolbar
-from sugar.graphics.toolcombobox import ToolComboBox
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics.radiotoolbutton import RadioToolButton
-from sugar.graphics.toggletoolbutton import ToggleToolButton
-from sugar.graphics.objectchooser import ObjectChooser
+from sugar3.activity.widgets import EditToolbar
+from sugar3.graphics.toolcombobox import ToolComboBox
+from sugar3.graphics.toolbutton import ToolButton
+from sugar3.graphics.radiotoolbutton import RadioToolButton
+from sugar3.graphics.toggletoolbutton import ToggleToolButton
+from sugar3.graphics.objectchooser import ObjectChooser
from widgets import ButtonStrokeColor
-from sugar.graphics.colorbutton import ColorToolButton
+from sugar3.graphics.colorbutton import ColorToolButton
-from sugar.graphics import style
+from sugar3.graphics import style
-from sugar.activity.widgets import ActivityToolbarButton
-from sugar.graphics.toolbarbox import ToolbarButton, ToolbarBox
-from sugar.activity.widgets import StopButton
+from sugar3.activity.widgets import ActivityToolbarButton
+from sugar3.graphics.toolbarbox import ToolbarButton, ToolbarBox
+from sugar3.activity.widgets import StopButton
from fontcombobox import FontComboBox
@@ -125,7 +127,7 @@ class DrawToolbarBox(ToolbarBox):
image_button.props.label = _('Image')
self.toolbar.insert(image_button, -1)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.props.draw = False
separator.set_size_request(0, -1)
separator.set_expand(True)
@@ -142,8 +144,15 @@ class DrawToolbarBox(ToolbarBox):
self.brush_button.set_brush_shape(area.tool['line shape'])
self.brush_button.set_brush_size(area.tool['line size'])
self.brush_button.set_stamp_size(area.tool['stamp size'])
- if self._activity.area.tool['stroke color'] is not None:
- self.brush_button.set_color(area.tool['stroke color'])
+
+ # init the color
+ cairo_stroke_color = area.tool['cairo_stroke_color']
+ red = cairo_stroke_color[0] * 65535
+ green = cairo_stroke_color[1] * 65535
+ blue = cairo_stroke_color[2] * 65535
+
+ stroke_color = Gdk.Color(red, green, blue)
+ self.brush_button.set_color(stroke_color)
##Make the Edit Toolbar
@@ -159,7 +168,7 @@ class DrawEditToolbar(EditToolbar):
self.copy.set_tooltip(_('Copy'))
self.paste.set_tooltip(_('Paste'))
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
@@ -191,7 +200,7 @@ class DrawEditToolbar(EditToolbar):
self._activity.area.copy()
def _paste_cb(self, widget, data=None):
- self._activity.area.past(self._activity.area)
+ self._activity.area.paste(self._activity.area)
def _on_signal_undo_cb(self, widget, data=None):
self._verify_sensitive_buttons()
@@ -248,11 +257,11 @@ class ToolsToolbarBuilder():
#self._stroke_color.set_icon_name('icon-stroke')
self._stroke_color.set_title(_('Brush properties'))
self._stroke_color.connect('notify::color', self._color_button_cb)
- item = gtk.ToolItem()
+ item = Gtk.ToolItem()
item.add(self._stroke_color)
toolbar.insert(item, -1)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
toolbar.insert(separator, -1)
@@ -290,7 +299,7 @@ class ToolsToolbarBuilder():
activity.tool_group, _('Select Area'))
toolbar.insert(self._tool_marquee_rectangular, -1)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
toolbar.insert(separator, -1)
@@ -315,7 +324,7 @@ class ToolsToolbarBuilder():
"""
Set tool to the Area object. Configures tool's color and size.
- @param self -- gtk.Toolbar
+ @param self -- Gtk.Toolbar
@param widget -- The connected widget, if any;
necessary in case this method is used in a connect()
@param tool_name --The name of the selected tool
@@ -332,9 +341,8 @@ class ToolsToolbarBuilder():
def _color_button_cb(self, widget, pspec):
logging.error('ToolsToolbarBuilder._color_button_cb')
- new_color = widget.alloc_color(widget.get_color())
+ new_color = widget.get_color()
self._activity.area.set_stroke_color(new_color)
- self.properties['stroke color'] = new_color
def _on_signal_undo_cb(self, widget, data=None):
self._verify_sensitive_buttons()
@@ -369,61 +377,55 @@ class ButtonFillColor(ColorToolButton):
color = self.get_color()
self.set_fill_color(color)
- def alloc_color(self, color):
- colormap = self._activity.area.get_colormap()
- return colormap.alloc_color(color.red, color.green, color.blue)
-
def set_fill_color(self, color):
- new_color = self.alloc_color(color)
- self._activity.area.set_fill_color(new_color)
- self.properties['fill color'] = new_color
+ self._activity.area.set_fill_color(color)
def create_palette(self):
self._palette = self.get_child().create_palette()
color_palette_hbox = self._palette._picker_hbox
- content_box = gtk.VBox()
+ content_box = Gtk.VBox()
# Fill option
- fill_checkbutton = gtk.CheckButton(_('Fill'))
+ fill_checkbutton = Gtk.CheckButton(_('Fill'))
fill_checkbutton.set_active(self.properties['fill'])
fill_checkbutton.connect('toggled',
self._on_fill_checkbutton_toggled)
- content_box.pack_start(fill_checkbutton)
+ content_box.pack_start(fill_checkbutton, True, True, 0)
- keep_aspect_checkbutton = gtk.CheckButton(_('Keep aspect'))
+ keep_aspect_checkbutton = Gtk.CheckButton(_('Keep aspect'))
logging.error('Create palette : tool name %s', self.properties['name'])
ratio = self._activity.area.keep_shape_ratio
keep_aspect_checkbutton.set_active(ratio)
keep_aspect_checkbutton.connect('toggled',
self._on_keep_aspect_checkbutton_toggled)
- content_box.pack_start(keep_aspect_checkbutton)
+ content_box.pack_start(keep_aspect_checkbutton, True, True, 0)
# We want choose the number of sides to our polygon
- spin = gtk.SpinButton()
+ spin = Gtk.SpinButton()
# This is where we set restrictions for sides in Regular Polygon:
# Initial value, minimum value, maximum value, step
- adj = gtk.Adjustment(self.properties['vertices'], 3.0, 50.0, 1.0)
+ adj = Gtk.Adjustment(self.properties['vertices'], 3.0, 50.0, 1.0)
spin.set_adjustment(adj)
spin.set_numeric(True)
- label = gtk.Label(_('Sides: '))
+ label = Gtk.Label(label=_('Sides: '))
#For stars
- #label = gtk.Label(_('Points: '))
+ #label = Gtk.Label(label=_('Points: '))
- hbox = gtk.HBox()
+ hbox = Gtk.HBox()
hbox.show_all()
- hbox.pack_start(label)
- hbox.pack_start(spin)
+ hbox.pack_start(label, True, True, 0)
+ hbox.pack_start(spin, True, True, 0)
- content_box.pack_start(hbox)
+ content_box.pack_start(hbox, True, True, 0)
hbox.show_all()
spin.connect('value-changed', self._on_vertices_value_changed)
- color_palette_hbox.pack_start(gtk.VSeparator(),
+ color_palette_hbox.pack_start(Gtk.VSeparator(), True, True,
padding=style.DEFAULT_SPACING)
- color_palette_hbox.pack_start(content_box)
+ color_palette_hbox.pack_start(content_box, True, True, 0)
color_palette_hbox.show_all()
return self._palette
@@ -439,7 +441,7 @@ class ButtonFillColor(ColorToolButton):
##Make the Shapes Toolbar
-class ShapesToolbar(gtk.Toolbar):
+class ShapesToolbar(Gtk.Toolbar):
_SHAPE_ARROW_NAME = 'arrow'
_SHAPE_CURVE_NAME = 'curve'
@@ -456,7 +458,7 @@ class ShapesToolbar(gtk.Toolbar):
##The Constructor
def __init__(self, activity):
- gtk.Toolbar.__init__(self)
+ GObject.GObject.__init__(self)
self._activity = activity
self.properties = self._activity.area.tool
@@ -464,11 +466,11 @@ class ShapesToolbar(gtk.Toolbar):
self._fill_color = ButtonFillColor(activity)
self._fill_color.set_icon_name('icon-fill')
self._fill_color.set_title(_('Shapes properties'))
- item = gtk.ToolItem()
+ item = Gtk.ToolItem()
item.add(self._fill_color)
self.insert(item, -1)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
@@ -544,20 +546,16 @@ class ShapesToolbar(gtk.Toolbar):
def set_tool(self, widget, tool, tool_name):
tool['name'] = tool_name
-
- fill_color = self._fill_color.get_color()
- tool['fill color'] = self._fill_color.alloc_color(fill_color)
-
self._activity.area.set_tool(tool)
##Make the Text Toolbar
-class TextToolbar(gtk.Toolbar):
+class TextToolbar(Gtk.Toolbar):
_ACTION_TEXT_NAME = 'text'
def __init__(self, activity):
- gtk.Toolbar.__init__(self)
+ GObject.GObject.__init__(self)
self._activity = activity
self.properties = self._activity.area.tool
@@ -566,7 +564,7 @@ class TextToolbar(gtk.Toolbar):
self.insert(self._text, -1)
self._text.connect('clicked', self.set_tool, self._ACTION_TEXT_NAME)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
@@ -580,33 +578,20 @@ class TextToolbar(gtk.Toolbar):
self._italic.show()
self._italic.connect('clicked', self.__italic_bt_cb)
- """
- self._text_color = ButtonFillColor(activity)
- item = gtk.ToolItem()
- item.add(self._text_color)
- self.insert(item, -1)
- """
-
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
- """
- self._font_size_icon = Icon(icon_name="format-text-size",
- icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR)
- tool_item = gtk.ToolItem()
- tool_item.add(self._font_size_icon)
- self.insert(tool_item, -1)
- """
+ fd = activity.area.get_font_description()
- self._font_size_combo = gtk.combo_box_new_text()
+ self._font_size_combo = Gtk.ComboBoxText()
self._font_sizes = ['8', '10', '12', '14', '16', '20',
'22', '24', '26', '28', '36', '48', '72']
self._font_size_changed_id = self._font_size_combo.connect('changed',
self.__font_size_changed_cb)
for i, s in enumerate(self._font_sizes):
self._font_size_combo.append_text(s)
- if int(s) == activity.area.font_description.get_size():
+ if int(s) == (fd.get_size() /Pango.SCALE):
self._font_size_combo.set_active(i)
tool_item = ToolComboBox(self._font_size_combo)
@@ -615,39 +600,39 @@ class TextToolbar(gtk.Toolbar):
self._font_combo = FontComboBox()
self._fonts_changed_id = self._font_combo.connect('changed',
self.__font_changed_cb)
- font_name = activity.area.font_description.get_family()
+ font_name = fd.get_family()
self._font_combo.set_font_name(font_name)
tool_item = ToolComboBox(self._font_combo)
self.insert(tool_item, -1)
self.show_all()
def __bold_bt_cb(self, button):
- activity = self._activity
+ fd = self._activity.area.get_font_description()
if button.get_active():
- activity.area.font_description.set_weight(pango.WEIGHT_BOLD)
+ fd.set_weight(Pango.Weight.BOLD)
else:
- activity.area.font_description.set_weight(pango.WEIGHT_NORMAL)
- activity.textview.modify_font(activity.area.font_description)
+ fd.set_weight(Pango.Weight.NORMAL)
+ self._activity.area.set_font_description(fd)
def __italic_bt_cb(self, button):
- activity = self._activity
+ fd = self._activity.area.get_font_description()
if button.get_active():
- activity.area.font_description.set_style(pango.STYLE_ITALIC)
+ fd.set_style(Pango.Style.ITALIC)
else:
- activity.area.font_description.set_style(pango.STYLE_NORMAL)
- activity.textview.modify_font(activity.area.font_description)
+ fd.set_style(Pango.Style.NORMAL)
+ self._activity.area.set_font_description(fd)
def __font_size_changed_cb(self, combo):
- activity = self._activity
+ fd = self._activity.area.get_font_description()
value = self.get_active_text(combo)
- activity.area.font_description.set_size(int(value) * pango.SCALE)
- activity.textview.modify_font(activity.area.font_description)
+ fd.set_size(int(value) * Pango.SCALE)
+ self._activity.area.set_font_description(fd)
def __font_changed_cb(self, combo):
- activity = self._activity
+ fd = self._activity.area.get_font_description()
font_name = combo.get_font_name()
- activity.area.font_description.set_family(font_name)
- activity.textview.modify_font(activity.area.font_description)
+ fd.set_family(font_name)
+ self._activity.area.set_font_description(fd)
def get_active_text(self, combobox):
model = combobox.get_model()
@@ -662,12 +647,12 @@ class TextToolbar(gtk.Toolbar):
##Make the Images Toolbar
-class ImageToolbar(gtk.Toolbar):
+class ImageToolbar(Gtk.Toolbar):
_EFFECT_RAINBOW_NAME = 'rainbow'
def __init__(self, activity):
- gtk.Toolbar.__init__(self)
+ GObject.GObject.__init__(self)
self._activity = activity
self.properties = self._activity.area.tool
@@ -675,7 +660,7 @@ class ImageToolbar(gtk.Toolbar):
self.insert(self._object_insert, -1)
self._object_insert.set_tooltip(_('Insert Image'))
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
@@ -709,7 +694,7 @@ class ImageToolbar(gtk.Toolbar):
self.height_spinButton = self._create_spinButton(self._object_height,
'object-height', activity)
- item = gtk.ToolItem()
+ item = Gtk.ToolItem()
item.add(self.height_spinButton)
self.insert(item, -1)
@@ -720,11 +705,11 @@ class ImageToolbar(gtk.Toolbar):
self.width_spinButton = self._create_spinButton(self._object_width,
'object-width', activity)
- item = gtk.ToolItem()
+ item = Gtk.ToolItem()
item.add(self.width_spinButton)
self.insert(item, -1)
- separator = gtk.SeparatorToolItem()
+ separator = Gtk.SeparatorToolItem()
separator.set_draw(True)
self.insert(separator, -1)
@@ -774,7 +759,7 @@ class ImageToolbar(gtk.Toolbar):
def resize(self, spinButton, tool, activity):
if activity.area.tool['name'] == 'marquee-rectangular' and \
- activity.area.selmove:
+ activity.area.is_selected():
if tool == "object-height":
self.height_percent = spinButton.get_value_as_int() / 100.
activity.area.d.resizeSelection(activity.area,
@@ -787,7 +772,7 @@ class ImageToolbar(gtk.Toolbar):
def _create_spinButton(self, widget, tool, activity):
"""Set palette for a tool - width or height
- @param self -- gtk.Toolbar
+ @param self -- Gtk.Toolbar
@param widget - the widget which Palette will be set,
a ToolButton object
@param tool
@@ -795,13 +780,13 @@ class ImageToolbar(gtk.Toolbar):
"""
logging.debug('setting a spinButton for %s', tool)
- spin = gtk.SpinButton()
+ spin = Gtk.SpinButton()
spin.show()
# This is where we set restrictions for Resizing:
# Initial value, minimum value, maximum value, step
initial = float(100)
- adj = gtk.Adjustment(initial, 10.0, 500.0, 1.0)
+ adj = Gtk.Adjustment(initial, 10.0, 500.0, 1.0)
spin.set_adjustment(adj)
spin.set_numeric(True)
@@ -814,20 +799,20 @@ class ImageToolbar(gtk.Toolbar):
def insertImage(self, widget, activity):
try:
chooser = ObjectChooser(_('Choose image'),
- self._activity, gtk.DIALOG_MODAL |
- gtk.DIALOG_DESTROY_WITH_PARENT, what_filter='Image')
+ self._activity, Gtk.DialogFlags.MODAL |
+ Gtk.DialogFlags.DESTROY_WITH_PARENT, what_filter='Image')
except:
chooser = ObjectChooser(_('Choose image'),
- self._activity, gtk.DIALOG_MODAL |
- gtk.DIALOG_DESTROY_WITH_PARENT)
+ self._activity, Gtk.DialogFlags.MODAL |
+ Gtk.DialogFlags.DESTROY_WITH_PARENT)
try:
result = chooser.run()
- if result == gtk.RESPONSE_ACCEPT:
+ if result == Gtk.ResponseType.ACCEPT:
logging.debug('ObjectChooser: %r',
chooser.get_selected_object())
jobject = chooser.get_selected_object()
if jobject and jobject.file_path:
- self._activity.area.loadImage(jobject.file_path)
+ self._activity.area.load_image(jobject.file_path)
finally:
chooser.destroy()
del chooser
diff --git a/widgets.py b/widgets.py
index c1833fa..46c8db2 100644
--- a/widgets.py
+++ b/widgets.py
@@ -2,12 +2,19 @@
from gettext import gettext as _
-import gtk
-import gobject
+from gi.repository import Gtk
+from gi.repository import Gdk
+from gi.repository import GObject
+import math
-from sugar.graphics import style
-from sugar.graphics.palette import ToolInvoker
-from sugar.graphics.colorbutton import _ColorButton
+from sugar3.graphics import style
+from sugar3.graphics.palette import ToolInvoker
+from sugar3.graphics.colorbutton import _ColorButton
+from sugar3.graphics.radiotoolbutton import RadioToolButton
+
+# this strings are here only to enable pootle to translate them
+# and do not broke the old versions
+_old_strings = [_('Size: '), _('Opacity: '), _('Circle'), _('Square')]
class BrushButton(_ColorButton):
@@ -22,7 +29,7 @@ class BrushButton(_ColorButton):
def __init__(self, **kwargs):
self._title = _('Choose brush properties')
- self._color = gtk.gdk.Color(0, 0, 0)
+ self._color = Gdk.Color(0, 0, 0)
self._has_palette = True
self._has_invoker = True
self._palette = None
@@ -30,35 +37,30 @@ class BrushButton(_ColorButton):
self._brush_size = 2
self._stamp_size = 20
self._brush_shape = 'circle'
+ self._alpha = 1.0
self._resized_stamp = None
- self._preview = gtk.DrawingArea()
+ self._preview = Gtk.DrawingArea()
self._preview.set_size_request(style.STANDARD_ICON_SIZE,
style.STANDARD_ICON_SIZE)
+ self._ctx = None
- gobject.GObject.__init__(self, **kwargs)
- self._preview.set_events(gtk.gdk.BUTTON_PRESS_MASK)
+ GObject.GObject.__init__(self, **kwargs)
+ self._preview.set_events(Gdk.EventMask.BUTTON_PRESS_MASK)
self._preview.connect('button_press_event', self.__mouse_down_cb)
- self._preview.connect("expose_event", self.expose)
+ self._preview.connect("draw", self.draw)
self.set_image(self._preview)
- self._gc = None
-
if self._has_palette and self._has_invoker:
self._invoker = WidgetInvoker(self)
# FIXME: This is a hack.
self._invoker.has_rectangle_gap = lambda: False
self._invoker.palette = self._palette
- def _setup(self):
- if self.get_window() is not None:
- self._preview.fill_color = ''
- self._preview.show()
- self.pixmap = gtk.gdk.Pixmap(self.get_window(),
- style.STANDARD_ICON_SIZE,
- style.STANDARD_ICON_SIZE, -1)
- self._gc = self.get_window().new_gc()
- self.show_all()
+# def _setup(self):
+# if self.get_window() is not None:
+# self._preview.show()
+# self.show_all()
def get_brush_size(self):
return self._brush_size
@@ -67,7 +69,7 @@ class BrushButton(_ColorButton):
self._brush_size = brush_size
self._preview.queue_draw()
- brush_size = gobject.property(type=int, getter=get_brush_size,
+ brush_size = GObject.property(type=int, getter=get_brush_size,
setter=set_brush_size)
def get_brush_shape(self):
@@ -77,11 +79,13 @@ class BrushButton(_ColorButton):
self._brush_shape = brush_shape
self._preview.queue_draw()
- brush_shape = gobject.property(type=str, getter=get_brush_shape,
+ brush_shape = GObject.property(type=str, getter=get_brush_shape,
setter=set_brush_shape)
def set_color(self, color):
- # receive gtk.gdk.Color
+ """
+ @ param color Gdk.Color
+ """
self._color = color
self._preview.queue_draw()
@@ -92,7 +96,7 @@ class BrushButton(_ColorButton):
self._stamp_size = stamp_size
self._preview.queue_draw()
- stamp_size = gobject.property(type=int, getter=get_stamp_size,
+ stamp_size = GObject.property(type=int, getter=get_stamp_size,
setter=set_stamp_size)
def set_resized_stamp(self, resized_stamp):
@@ -105,40 +109,47 @@ class BrushButton(_ColorButton):
def is_stamping(self):
return self._resized_stamp != None
- def expose(self, widget, event):
- if self._gc is None:
- self._setup()
+ def set_alpha(self, alpha):
+ self._alpha = alpha
+ self._preview.queue_draw()
+
+ def draw(self, widget, ctx):
+ #if self._ctx is None:
+ # self._setup()
if self.get_window() is not None:
center = style.STANDARD_ICON_SIZE / 2
- self.pixmap.draw_rectangle(self._preview.get_style().white_gc,
- True, 0, 0, style.STANDARD_ICON_SIZE, style.STANDARD_ICON_SIZE)
- self._gc.set_foreground(self._color)
+ ctx.rectangle(0, 0, style.STANDARD_ICON_SIZE,
+ style.STANDARD_ICON_SIZE)
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.fill()
if self.is_stamping():
width = self._resized_stamp.get_width()
height = self._resized_stamp.get_height()
dx = center - width / 2
dy = center - height / 2
- self.pixmap.draw_pixbuf(self._gc, self._resized_stamp,
- 0, 0, dx, dy, width, height)
+
+ ctx.rectangle(dx, dy, width, height)
+ Gdk.cairo_set_source_pixbuf(ctx, self._resized_stamp, 0, 0)
+ ctx.paint()
else:
+ red = float(self._color.red) / 65535.0
+ green = float(self._color.green) / 65535.0
+ blue = float(self._color.blue) / 65535.0
+ ctx.set_source_rgba(red, green, blue, self._alpha)
if self._brush_shape == 'circle':
- self.pixmap.draw_arc(self._gc, True,
- center - self._brush_size / 2,
- center - self._brush_size / 2,
- self._brush_size, self._brush_size, 0, 360 * 64)
+ ctx.arc(center, center, self._brush_size / 2, 0.,
+ 2 * math.pi)
+ ctx.fill()
elif self._brush_shape == 'square':
- self.pixmap.draw_rectangle(self._gc, True,
- center - self._brush_size / 2,
- center - self._brush_size / 2,
- self._brush_size, self._brush_size)
-
- area = event.area
- widget.window.draw_drawable(self._gc, self.pixmap,
- area[0], area[1], area[0], area[1], area[2], area[3])
+ ctx.rectangle(center - self._brush_size / 2,
+ center - self._brush_size / 2, self._brush_size,
+ self._brush_size)
+ ctx.fill()
+
return False
def do_style_set(self, previous_style):
@@ -166,11 +177,11 @@ class BrushButton(_ColorButton):
return True
-class ButtonStrokeColor(gtk.ToolItem):
+class ButtonStrokeColor(Gtk.ToolItem):
"""Class to manage the Stroke Color of a Button"""
__gtype_name__ = 'BrushColorToolButton'
- __gsignals__ = {'color-set': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ __gsignals__ = {'color-set': (GObject.SignalFlags.RUN_FIRST, None,
tuple())}
def __init__(self, activity, **kwargs):
@@ -181,9 +192,9 @@ class ButtonStrokeColor(gtk.ToolItem):
self._palette_invoker = ToolInvoker()
self._palette = None
- gobject.GObject.__init__(self, **kwargs)
+ GObject.GObject.__init__(self, **kwargs)
- # The gtk.ToolButton has already added a normal button.
+ # The Gtk.ToolButton has already added a normal button.
# Replace it with a ColorButton
self.color_button = BrushButton(has_invoker=False)
self.add(self.color_button)
@@ -192,7 +203,7 @@ class ButtonStrokeColor(gtk.ToolItem):
self.color_button.set_stamp_size(20)
# The following is so that the behaviour on the toolbar is correct.
- self.color_button.set_relief(gtk.RELIEF_NONE)
+ self.color_button.set_relief(Gtk.ReliefStyle.NONE)
self._palette_invoker.attach_tool(self)
@@ -211,79 +222,92 @@ class ButtonStrokeColor(gtk.ToolItem):
return True
def __notify_change(self, widget, pspec):
- new_color = self.alloc_color(self.get_color())
- self.color_button.set_color(new_color)
+ #new_color = self.alloc_color(self.get_color())
+ #self.color_button.set_color(new_color)
+ self.color_button.set_color(self.get_color())
self.notify(pspec.name)
def _color_button_cb(self, widget, pspec):
color = self.get_color()
self.set_stroke_color(color)
- def alloc_color(self, color):
- colormap = self._activity.area.get_colormap()
- return colormap.alloc_color(color.red, color.green, color.blue)
+# def alloc_color(self, color):
+# colormap = self._activity.area.get_colormap()
+# return colormap.alloc_color(color.red, color.green, color.blue)
def create_palette(self):
self._palette = self.get_child().create_palette()
color_palette_hbox = self._palette._picker_hbox
- content_box = gtk.VBox()
- self.size_spinbutton = gtk.SpinButton()
- # This is where we set restrictions for size:
- # Initial value, minimum value, maximum value, step
- adj = gtk.Adjustment(self.properties['line size'], 1.0, 100.0, 1.0)
- self.size_spinbutton.set_adjustment(adj)
- self.size_spinbutton.set_numeric(True)
+ content_box = Gtk.VBox()
- label = gtk.Label(_('Size: '))
- hbox_size = gtk.HBox()
- self.vbox_brush_options = gtk.VBox()
- content_box.pack_start(hbox_size)
- content_box.pack_start(self.vbox_brush_options)
+ self._brush_table = Gtk.Table(2, 2)
+ self._brush_table.set_col_spacing(0, style.DEFAULT_PADDING)
- hbox_size.pack_start(label)
- hbox_size.pack_start(self.size_spinbutton)
- self.size_spinbutton.connect('value-changed', self._on_value_changed)
+ # This is where we set restrictions for size:
+ # Initial value, minimum value, maximum value, step
+ adj = Gtk.Adjustment(self.properties['line size'], 1.0, 100.0, 1.0)
+ self.size_scale = Gtk.HScale()
+ self.size_scale.set_adjustment(adj)
+ self.size_scale.set_value_pos(Gtk.PositionType.RIGHT)
+ self.size_scale.set_digits(0)
+ self.size_scale.set_size_request(style.zoom(150), -1)
+ label = Gtk.Label(label=_('Size'))
+ row = 0
+ self._brush_table.attach(label, 0, 1, row, row + 1)
+ self._brush_table.attach(self.size_scale, 1, 2, row, row + 1)
+
+ content_box.pack_start(self._brush_table, True, True, 0)
+
+ self.size_scale.connect('value-changed', self._on_value_changed)
+
+ # Control alpha
+ alpha = self.properties['alpha'] * 100
+ adj_alpha = Gtk.Adjustment(alpha, 10.0, 100.0, 1.0)
+ self.alpha_scale = Gtk.HScale()
+ self.alpha_scale.set_adjustment(adj_alpha)
+ self.alpha_scale.set_value_pos(Gtk.PositionType.RIGHT)
+ self.alpha_scale.set_digits(0)
+ self.alpha_scale.set_size_request(style.zoom(150), -1)
+ self.alpha_label = Gtk.Label(label=_('Opacity'))
+ row = row + 1
+ self._brush_table.attach(self.alpha_label, 0, 1, row, row + 1)
+ self._brush_table.attach(self.alpha_scale, 1, 2, row, row + 1)
+
+ self.alpha_scale.connect('value-changed', self._on_alpha_changed)
# User is able to choose Shapes for 'Brush' and 'Eraser'
- item1 = gtk.RadioButton(None, _('Circle'))
+ self.vbox_brush_options = Gtk.VBox()
+ shape_box = Gtk.HBox()
+ content_box.pack_start(self.vbox_brush_options, True, True, 0)
+ item1 = RadioToolButton()
+ item1.set_icon_name('tool-shape-ellipse')
item1.set_active(True)
- image1 = gtk.Image()
- pixbuf1 = gtk.gdk.pixbuf_new_from_file_at_size(
- './icons/tool-shape-ellipse.svg',
- style.SMALL_ICON_SIZE,
- style.SMALL_ICON_SIZE)
- image1.set_from_pixbuf(pixbuf1)
- item1.set_image(image1)
-
- item2 = gtk.RadioButton(item1, _('Square'))
- image2 = gtk.Image()
- pixbuf2 = gtk.gdk.pixbuf_new_from_file_at_size(
- './icons/tool-shape-rectangle.svg',
- style.SMALL_ICON_SIZE,
- style.SMALL_ICON_SIZE)
- image2.set_from_pixbuf(pixbuf2)
- item2.set_image(image2)
+
+ item2 = RadioToolButton()
+ item2.set_icon_name('tool-shape-rectangle')
+ item2.props.group = item1
item1.connect('toggled', self._on_toggled, self.properties, 'circle')
item2.connect('toggled', self._on_toggled, self.properties, 'square')
- label = gtk.Label(_('Shape'))
+ shape_box.pack_start(Gtk.Label(_('Shape')), True, True, 0)
+ shape_box.pack_start(item1, True, True, 0)
+ shape_box.pack_start(item2, True, True, 0)
- self.vbox_brush_options.pack_start(label)
- self.vbox_brush_options.pack_start(item1)
- self.vbox_brush_options.pack_start(item2)
+ self.vbox_brush_options.pack_start(shape_box, True, True, 0)
- keep_aspect_checkbutton = gtk.CheckButton(_('Keep aspect'))
+ keep_aspect_checkbutton = Gtk.CheckButton(_('Keep aspect'))
ratio = self._activity.area.keep_aspect_ratio
keep_aspect_checkbutton.set_active(ratio)
keep_aspect_checkbutton.connect('toggled',
self._keep_aspect_checkbutton_toggled)
- self.vbox_brush_options.pack_start(keep_aspect_checkbutton)
+ self.vbox_brush_options.pack_start(keep_aspect_checkbutton, True, True,
+ 0)
- color_palette_hbox.pack_start(gtk.VSeparator(),
+ color_palette_hbox.pack_start(Gtk.VSeparator(), True, True,
padding=style.DEFAULT_SPACING)
- color_palette_hbox.pack_start(content_box)
+ color_palette_hbox.pack_start(content_box, True, True, 0)
color_palette_hbox.show_all()
self._update_palette()
return self._palette
@@ -296,9 +320,11 @@ class ButtonStrokeColor(gtk.ToolItem):
if self.color_button.is_stamping():
# Hide palette color widgets:
for ch in palette_children[:4]:
- ch.hide_all()
+ ch.hide()
# Hide brush options:
- self.vbox_brush_options.hide_all()
+ self.vbox_brush_options.hide()
+ self.alpha_label.hide()
+ self.alpha_scale.hide()
# Change title:
self.set_title(_('Stamp properties'))
else:
@@ -307,6 +333,8 @@ class ButtonStrokeColor(gtk.ToolItem):
ch.show_all()
# Show brush options:
self.vbox_brush_options.show_all()
+ self.alpha_label.show()
+ self.alpha_scale.show()
# Change title:
self.set_title(_('Brush properties'))
@@ -315,13 +343,18 @@ class ButtonStrokeColor(gtk.ToolItem):
def update_stamping(self):
if self.color_button.is_stamping():
- self.size_spinbutton.set_value(self.color_button.stamp_size)
+ self.size_scale.set_value(self.color_button.stamp_size)
else:
- self.size_spinbutton.set_value(self.color_button.brush_size)
+ self.size_scale.set_value(self.color_button.brush_size)
self._update_palette()
- def _on_value_changed(self, spinbutton):
- size = spinbutton.get_value_as_int()
+ def _on_alpha_changed(self, scale):
+ alpha = scale.get_value() / 100.0
+ self._activity.area.set_alpha(alpha)
+ self.color_button.set_alpha(alpha)
+
+ def _on_value_changed(self, scale):
+ size = int(scale.get_value())
if self.color_button.is_stamping():
self.properties['stamp size'] = size
resized_stamp = self._activity.area.resize_stamp(size)
@@ -345,7 +378,7 @@ class ButtonStrokeColor(gtk.ToolItem):
self._palette_invoker.detach()
self._palette_invoker = palette_invoker
- palette_invoker = gobject.property(
+ palette_invoker = GObject.property(
type=object, setter=set_palette_invoker, getter=get_palette_invoker)
def set_color(self, color):
@@ -354,7 +387,7 @@ class ButtonStrokeColor(gtk.ToolItem):
def get_color(self):
return self.get_child().props.color
- color = gobject.property(type=object, getter=get_color, setter=set_color)
+ color = GObject.property(type=object, getter=get_color, setter=set_color)
def set_title(self, title):
self.get_child().props.title = title
@@ -362,7 +395,7 @@ class ButtonStrokeColor(gtk.ToolItem):
def get_title(self):
return self.get_child().props.title
- title = gobject.property(type=str, getter=get_title, setter=set_title)
+ title = GObject.property(type=str, getter=get_title, setter=set_title)
def do_expose_event(self, event):
child = self.get_child()
@@ -370,11 +403,11 @@ class ButtonStrokeColor(gtk.ToolItem):
if self._palette and self._palette.is_up():
invoker = self._palette.props.invoker
invoker.draw_rectangle(event, self._palette)
- elif child.state == gtk.STATE_PRELIGHT:
- child.style.paint_box(event.window, gtk.STATE_PRELIGHT,
- gtk.SHADOW_NONE, event.area,
+ elif child.state == Gtk.StateType.PRELIGHT:
+ child.style.paint_box(event.window, Gtk.StateType.PRELIGHT,
+ Gtk.ShadowType.NONE, event.area,
child, 'toolbutton-prelight',
allocation.x, allocation.y,
allocation.width, allocation.height)
- gtk.ToolButton.do_expose_event(self, event)
+ Gtk.ToolButton.do_expose_event(self, event)