Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Area.py
diff options
context:
space:
mode:
Diffstat (limited to 'Area.py')
-rw-r--r--Area.py1342
1 files changed, 662 insertions, 680 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):