From f347ec202fe5b4404fa380694d7fe3d3d070ae7b Mon Sep 17 00:00:00 2001 From: Simon Poirier Date: Mon, 18 May 2009 20:27:41 +0000 Subject: fixed major missing parts in bundler integrated bundler to creator tutorial loading still is unusable (fiters don't seem to load) --- (limited to 'src/sugar/tutorius/actions.py') diff --git a/src/sugar/tutorius/actions.py b/src/sugar/tutorius/actions.py index ff7f427..570bff8 100644 --- a/src/sugar/tutorius/actions.py +++ b/src/sugar/tutorius/actions.py @@ -24,6 +24,112 @@ import overlayer from sugar.tutorius.editor import WidgetIdentifier from sugar.tutorius.services import ObjectStore from sugar.tutorius.properties import * +import gtk.gdk + +class DragWrapper(object): + """Wrapper to allow gtk widgets to be dragged around""" + def __init__(self, widget, position, draggable=False): + """ + Creates a wrapper to allow gtk widgets to be mouse dragged, if the + parent container supports the move() method, like a gtk.Layout. + @param widget the widget to enhance with drag capability + @param position the widget's position. Will translate the widget if needed + @param draggable wether to enable the drag functionality now + """ + self._widget = widget + self._eventbox = None + 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.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 + + 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._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 + + 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): + if value: + self._eventbox = gtk.EventBox() + self._eventbox.show() + self._eventbox.set_visible_window(False) + size = self._widget.size_request() + self._eventbox.set_size_request(*size) + self._widget.parent.put(self._eventbox, *self.position) + 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)) + self._handles.append(self._eventbox.connect( + "grab-broken-event", self._drag_end)) + else: + while len(self._handles): + handle = self._handles.pop() + self._eventbox.disconnect(handle) + self._eventbox.parent.remove(self._eventbox) + self._eventbox.destroy() + self._eventbox = None + self._drag_on = value + + def get_draggable(self): + """Getter for the draggable property""" + return self._drag_on + + draggable = property(fset=set_draggable, fget=get_draggable, \ + doc="Property to enable the draggable behaviour of the widget") + + def set_widget(self, widget): + """Setter for the widget property""" + if self._dragging or self._drag_on: + raise Exception("Can't change widget while dragging is enabled.") + + assert hasattr(widget, "parent"), "wrapped widget should have a parent" + parent = widget.parent + assert hasattr(parent, "move"), "container of widget need move method" + self._widget = widget + + def get_widget(self): + """Getter for the widget property""" + return self._widget + + widget = property(fset=set_widget, fget=get_widget) class Action(object): """Base class for Actions""" @@ -56,6 +162,13 @@ class Action(object): self.properties[i] = getattr(self,i) return self.properties.keys() + def enter_editmode(self, **kwargs): + """ + Enters edit mode. The action should display itself in some way, + without affecting the currently running application. + """ + raise NotImplementedError("Not implemented") + class OnceWrapper(object): """ Wraps a class to perform an action once only @@ -142,6 +255,7 @@ class BubbleMessage(Action): self.overlay = None self._bubble = None self._speaker = None + self.__drag = None def do(self): """ @@ -154,12 +268,14 @@ class BubbleMessage(Action): # handled either by rendering over them, or by finding different way to # draw the overlay. + if not self.overlay: + self.overlay = ObjectStore().activity._overlayer if not self._bubble: - x, y = self._position + x, y = self.position.value # TODO: tails are relative to tailpos. They should be relative to # the speaking widget. Same of the bubble position. - self._bubble = overlayer.TextBubble(text=self._message, - tailpos=self._tailpos) + self._bubble = overlayer.TextBubble(text=self.message.value, + tailpos=self.tail_pos.value) self._bubble.show() self.overlay.put(self._bubble, x, y) self.overlay.queue_draw() @@ -171,7 +287,34 @@ class BubbleMessage(Action): if self._bubble: self._bubble.destroy() self._bubble = None - + + def enter_editmode(self, *args): + """ + Enters edit mode. The action should display itself in some way, + without affecting the currently running application. + """ + if not self.overlay: + self.overlay = ObjectStore().activity._overlayer + assert not self.__drag, "bubble action set to editmode twice" + x, y = self.position.value + self._bubble = overlayer.TextBubble(text=self.message.value, + tailpos=self.tail_pos.value) + self.overlay.put(self._bubble, x, y) + self._bubble.show() + + self.__drag = DragWrapper(self._bubble, self.position.value, True) + + def exit_editmode(self, *args): + x,y = self.__drag.position + self.position.set([int(x), int(y)]) + if self.__drag: + self.__drag.draggable = False + self.__drag = None + if self._bubble: + self.overlay.remove(self._bubble) + self._bubble = None + self.overlay = None + class WidgetIdentifyAction(Action): def __init__(self): self.activity = None -- cgit v0.9.1