From f833037b33f94a94eb79a789254f1db263feffb3 Mon Sep 17 00:00:00 2001 From: mike Date: Sat, 05 Dec 2009 22:21:27 +0000 Subject: Changed the DragWrapper behavior to use drag-begin, drag-end and the icon change to implement a move on the overlayer. However, on the regular overlayer, drag-end signal is never emitted Conflicts: tutorius/actions.py tutorius/overlayer.py --- diff --git a/tutorius/actions.py b/tutorius/actions.py index 8cc5f08..7e3199b 100644 --- a/tutorius/actions.py +++ b/tutorius/actions.py @@ -17,7 +17,7 @@ This module defines Actions that can be done and undone on a state """ import gtk - +import logging from gettext import gettext as _ from sugar.graphics import icon @@ -25,6 +25,8 @@ from sugar.graphics import icon from . import addon from .services import ObjectStore from .properties import * +from .constants import * + import pickle @@ -34,6 +36,11 @@ LOGGER = logging.getLogger("actions") class DragWrapper(object): """Wrapper to allow gtk widgets to be dragged around""" + + fromImage = [ ( WIDGET_ID, 0, TARGET_TYPE_WIDGET ) ] + + LOGGER = logging.getLogger("sugar.tutorius.actions.DragWrapper") + def __init__(self, widget, position, update_action_cb, draggable=False): """ Creates a wrapper to allow gtk widgets to be mouse dragged, if the @@ -48,52 +55,52 @@ class DragWrapper(object): self._drag_on = False # whether dragging is enabled self._rel_pos = (0,0) # mouse pos relative to widget self._handles = [] # event handlers - self._dragging = False # whether a drag is in progress self.position = position # position of the widget self.moved = False self.update_action_cb = update_action_cb self.draggable = draggable - def _pressed_cb(self, widget, evt): - """Callback for start of drag event""" - self._eventbox.grab_add() - self._dragging = True - self._rel_pos = evt.get_coords() - - def _moved_cb(self, widget, evt): - """Callback for mouse drag events""" - if not self._dragging: - return - - # Focus on a widget before dragging another would - # create addititonal move event, making the widget jump unexpectedly. - # Solution found was to process those focus events before dragging. - if gtk.events_pending(): - return - + def _drag_begin(self, widget, drag_context, *args): + """Callback for initialisation of drag and drop""" + # Setup the drag icon to what the widget is rendering + self.LOGGER.debug("%s drag-begin"%(str(widget))) + width = self._widget.allocation.width + height = self._widget.allocation.height + x = self._widget.allocation.x + y = self._widget.allocation.y + depth = 24 # Should be set dynamically + + pxbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height) + pxbuf.fill(0xFFFFFFFF) + + px = gtk.gdk.Pixmap(None, width, height, depth) # source, size, colors + px.set_colormap(gtk.gdk.colormap_get_system()) + ctxt = px.cairo_create() + ctxt.set_source_pixbuf(pxbuf,0,0) + ctxt.paint() + + # Compensate when drawing the icon for the context + # translation done to the position occupied by the widget + ctxt.translate(-x, -y) + self._widget.draw_with_context(ctxt) + + pxbuf.get_from_drawable(px,gtk.gdk.colormap_get_system(), 0, 0, 0, 0, -1, -1) + drag_context.set_icon_pixbuf(pxbuf,0,0) + + def _drag_end(self, widget, context, *args): + """Callback for end of drag (stolen focus).""" xrel, yrel = self._rel_pos - xparent, yparent = evt.get_coords() - xparent, yparent = widget.translate_coordinates(widget.parent, - xparent, yparent) - self.position = (xparent-xrel, yparent-yrel) - self.moved = True + rootwin = widget.get_screen().get_root_window() + xparent,yparent,mods = rootwin.get_pointer() + + self.position = (int(xparent-xrel), int(yparent-yrel)) + self.LOGGER.debug("%s drag-end pos: (%s,%s)"%(str(widget),self.position)) self._widget.parent.move(self._eventbox, *self.position) self._widget.parent.move(self._widget, *self.position) self._widget.parent.queue_draw() - def _released_cb(self, *args): - """Callback for end of drag (mouse release).""" - self._eventbox.grab_remove() - self._dragging = False - LOGGER.debug("DragWrapper :: Sending update notification...") - self.update_action_cb('position', self.position) - - def _drag_end(self, *args): - """Callback for end of drag (stolen focus).""" - self._dragging = False - def set_draggable(self, value): """Setter for the draggable property""" if bool(value) ^ bool(self._drag_on): @@ -104,14 +111,15 @@ class DragWrapper(object): size = self._widget.size_request() self._eventbox.set_size_request(*size) self._widget.parent.put(self._eventbox, *self.position) + + # Prepare the widget for drag and drop + self._eventbox.drag_source_set(gtk.gdk.BUTTON1_MASK, + self.fromImage, + gtk.gdk.ACTION_MOVE) self._handles.append(self._eventbox.connect( - "button-press-event", self._pressed_cb)) - self._handles.append(self._eventbox.connect( - "button-release-event", self._released_cb)) - self._handles.append(self._eventbox.connect( - "motion-notify-event", self._moved_cb)) + "drag-begin", self._drag_begin)) self._handles.append(self._eventbox.connect( - "grab-broken-event", self._drag_end)) + "drag-end", self._drag_end)) else: while len(self._handles): handle = self._handles.pop() diff --git a/tutorius/overlayer.py b/tutorius/overlayer.py index 9e4adbf..fcb6974 100644 --- a/tutorius/overlayer.py +++ b/tutorius/overlayer.py @@ -25,6 +25,7 @@ import pangocairo from math import pi from sugar import profile +from .constants import * # for easy profile access from cairo color = profile.get_color().get_stroke_color() @@ -70,6 +71,13 @@ class Overlayer(gtk.Layout): self.__render_handle = None + # Allow drag and drop + self.drag_dest_set(gtk.DEST_DEFAULT_MOTION | + gtk.DEST_DEFAULT_HIGHLIGHT | + gtk.DEST_DEFAULT_DROP, + [ ( WIDGET_ID, 0, TARGET_TYPE_WIDGET ) ], + gtk.gdk.ACTION_MOVE) + def put(self, child, x, y): """ Adds a child widget to be overlayed. This can be, overlay widgets or @@ -149,8 +157,63 @@ class Overlayer(gtk.Layout): # Since widget is laid out in a Layout box, the Layout will honor the # requested size. Using size_allocate could make a nasty nested loop in # some cases. - if self._overlayed: - self._overlayed.set_size_request(allocation.width, allocation.height) + self._overlayed.set_size_request(allocation.width, allocation.height) + + +class FrameOverlayer(gtk.Window): + def __init__(self): + gtk.Window.__init__(self) + self._vbox = gtk.VBox() + self._overlayer = Overlayer(self._vbox) + self.add(self._overlayer) + self._vbox.show() + self._overlayer.show() + self.show_all() + + self._overlayer.drag_dest_set(gtk.DEST_DEFAULT_MOTION | + gtk.DEST_DEFAULT_HIGHLIGHT | + gtk.DEST_DEFAULT_DROP, + [ ( WIDGET_ID, 0, TARGET_TYPE_WIDGET ) ], + gtk.gdk.ACTION_MOVE) + + self._widgets = [] + + + def show(self): + self.set_decorated(False) # Remove borders and title bar + self.set_keep_above(True) # Always on top + self.fullscreen() # Cover the entire screen + + gtk.Window.show(self) + self.expose = self.connect("expose-event", self.apply_mask) + + def apply_mask(self,*args): + self.px = gtk.gdk.Pixmap(None, 1173, 800, 1) # source, size, colors + self.cr = self.px.cairo_create() + self.cr.set_operator(cairo.OPERATOR_CLEAR) + self.cr.paint() + self.cr.set_source_rgb(1,1,1) + self.cr.set_operator(cairo.OPERATOR_SOURCE) + + for widget in self._widgets: + widget.draw_with_context(self.cr) + self.shape_combine_mask(self.px, 0, 0) # pixmap, offset + + def put(self,widget, offset_x, offset_y): + self._widgets.append(widget) + widget.show() + self._overlayer.put(widget, offset_x, offset_y) + self._overlayer.queue_draw() + + def move(self, widget, x, y): + self._overlayer.move(widget,x,y) + + def remove(self, widget): + self._widgets.remove(widget) + self._overlayer.remove(widget) + + def queue_draw(self): + self._overlayer.queue_draw() class TextBubble(gtk.Widget): """ @@ -424,13 +487,20 @@ class TextBubbleWImg(gtk.Widget): #ct = cairo.Context(surface) # paint image + img_upper_left_x = int((self.allocation.width-self.imgsize[0])/2) + img_upper_left_y = int(self.line_width+self.padding/2) context.set_source_pixbuf( self.pixbuf, - int((self.allocation.width-self.imgsize[0])/2), - int(self.line_width+self.padding/2)) + img_upper_left_x, + img_upper_left_y) + # Set a rectangle + context.rectangle(img_upper_left_x, img_upper_left_y, + self.imgsize[0], self.imgsize[1]) + context.clip() context.paint() - + context.reset_clip() + # work done. Be kind to next cairo widgets and reset matrix. context.identity_matrix() -- cgit v0.9.1