diff options
Diffstat (limited to 'grc/gui/DrawingArea.py')
-rw-r--r-- | grc/gui/DrawingArea.py | 196 |
1 files changed, 114 insertions, 82 deletions
diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index 6a1df27a8c..f279d50557 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -17,15 +17,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import pygtk -pygtk.require('2.0') -import gtk +from __future__ import absolute_import +from gi.repository import Gtk, Gdk, GObject -from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS -import Colors +from . import Constants, Colors -class DrawingArea(gtk.DrawingArea): + +class DrawingArea(Gtk.DrawingArea): """ DrawingArea is the gtk pixel map that graphical elements may draw themselves on. The drawing area also responds to mouse and key events. @@ -39,52 +38,47 @@ class DrawingArea(gtk.DrawingArea): Args: main_window: the main_window containing all flow graphs """ + Gtk.DrawingArea.__init__(self) + + self._flow_graph = flow_graph + + self.zoom_factor = 1.0 self.ctrl_mask = False self.mod1_mask = False - self._flow_graph = flow_graph - gtk.DrawingArea.__init__(self) - self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) + self.button_state = [False] * 10 + + # self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) self.connect('realize', self._handle_window_realize) - self.connect('configure-event', self._handle_window_configure) - self.connect('expose-event', self._handle_window_expose) + self.connect('draw', self.draw) self.connect('motion-notify-event', self._handle_mouse_motion) self.connect('button-press-event', self._handle_mouse_button_press) self.connect('button-release-event', self._handle_mouse_button_release) self.connect('scroll-event', self._handle_mouse_scroll) self.add_events( - gtk.gdk.BUTTON_PRESS_MASK | \ - gtk.gdk.POINTER_MOTION_MASK | \ - gtk.gdk.BUTTON_RELEASE_MASK | \ - gtk.gdk.LEAVE_NOTIFY_MASK | \ - gtk.gdk.ENTER_NOTIFY_MASK | \ - gtk.gdk.FOCUS_CHANGE_MASK + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.SCROLL_MASK | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK + #Gdk.EventMask.FOCUS_CHANGE_MASK ) - #setup drag and drop - self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY) + + # setup drag and drop + self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY) self.connect('drag-data-received', self._handle_drag_data_received) - #setup the focus flag + self.drag_dest_set_target_list(None) + self.drag_dest_add_text_targets() + + # setup the focus flag self._focus_flag = False self.get_focus_flag = lambda: self._focus_flag def _handle_notify_event(widget, event, focus_flag): self._focus_flag = focus_flag self.connect('leave-notify-event', _handle_notify_event, False) self.connect('enter-notify-event', _handle_notify_event, True) - self.set_flags(gtk.CAN_FOCUS) # self.set_can_focus(True) - self.connect('focus-out-event', self._handle_focus_lost_event) - - def new_pixmap(self, width, height): - return gtk.gdk.Pixmap(self.window, width, height, -1) - - def get_screenshot(self, transparent_bg=False): - pixmap = self._pixmap - W, H = pixmap.get_size() - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, W, H) - pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8) - pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1) - if transparent_bg: - bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR - pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue) - return pixbuf - + # todo: fix +# self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True) +# self.connect('focus-out-event', self._handle_focus_lost_event) ########################################################################## ## Handlers @@ -93,83 +87,121 @@ class DrawingArea(gtk.DrawingArea): """ Handle a drag and drop by adding a block at the given coordinate. """ - self._flow_graph.add_new_block(selection_data.data, (x, y)) + self._flow_graph.add_new_block(selection_data.get_text(), (x, y)) def _handle_mouse_scroll(self, widget, event): - if event.state & gtk.gdk.SHIFT_MASK: - if event.direction == gtk.gdk.SCROLL_UP: - event.direction = gtk.gdk.SCROLL_LEFT - else: - event.direction = gtk.gdk.SCROLL_RIGHT + if event.get_state() & Gdk.ModifierType.SHIFT_MASK: + if event.direction == Gdk.ScrollDirection.UP: + event.direction = Gdk.ScrollDirection.LEFT + else: + event.direction = Gdk.ScrollDirection.RIGHT + + elif event.get_state() & Gdk.ModifierType.CONTROL_MASK: + change = 1.2 if event.direction == Gdk.ScrollDirection.UP else 1/1.2 + zoom_factor = min(max(self.zoom_factor * change, 0.1), 5.0) + + if zoom_factor != self.zoom_factor: + self.zoom_factor = zoom_factor + self.queue_draw() + return True + + return False def _handle_mouse_button_press(self, widget, event): """ Forward button click information to the flow graph. """ self.grab_focus() - self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self.mod1_mask = event.state & gtk.gdk.MOD1_MASK - if event.button == 1: self._flow_graph.handle_mouse_selector_press( - double_click=(event.type == gtk.gdk._2BUTTON_PRESS), - coordinate=(event.x, event.y), - ) - if event.button == 3: self._flow_graph.handle_mouse_context_press( - coordinate=(event.x, event.y), - event=event, - ) + self.ctrl_mask = event.get_state() & Gdk.ModifierType.CONTROL_MASK + self.mod1_mask = event.get_state() & Gdk.ModifierType.MOD1_MASK + self.button_state[event.button] = True + + if event.button == 1: + double_click = (event.type == Gdk.EventType._2BUTTON_PRESS) + self.button_state[1] = not double_click + self._flow_graph.handle_mouse_selector_press( + double_click=double_click, + coordinate=self._translate_event_coords(event), + ) + elif event.button == 3: + self._flow_graph.handle_mouse_context_press( + coordinate=self._translate_event_coords(event), + event=event, + ) def _handle_mouse_button_release(self, widget, event): """ Forward button release information to the flow graph. """ - self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self.mod1_mask = event.state & gtk.gdk.MOD1_MASK - if event.button == 1: self._flow_graph.handle_mouse_selector_release( - coordinate=(event.x, event.y), - ) + self.ctrl_mask = event.get_state() & Gdk.ModifierType.CONTROL_MASK + self.mod1_mask = event.get_state() & Gdk.ModifierType.MOD1_MASK + self.button_state[event.button] = False + if event.button == 1: + self._flow_graph.handle_mouse_selector_release( + coordinate=self._translate_event_coords(event), + ) def _handle_mouse_motion(self, widget, event): """ Forward mouse motion information to the flow graph. """ - self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self.mod1_mask = event.state & gtk.gdk.MOD1_MASK + self.ctrl_mask = event.get_state() & Gdk.ModifierType.CONTROL_MASK + self.mod1_mask = event.get_state() & Gdk.ModifierType.MOD1_MASK + + if self.button_state[1]: + self._auto_scroll(event) + self._flow_graph.handle_mouse_motion( - coordinate=(event.x, event.y), + coordinate=self._translate_event_coords(event), ) + def _auto_scroll(self, event): + x, y = event.x, event.y + scrollbox = self.get_parent().get_parent() + + w, h = self._flow_graph.get_max_coords(initial=(x, y)) + self.set_size_request(w + 100, h + 100) + + def scroll(pos, adj): + """scroll if we moved near the border""" + adj_val = adj.get_value() + adj_len = adj.get_page_size() + if pos - adj_val > adj_len - Constants.SCROLL_PROXIMITY_SENSITIVITY: + adj.set_value(adj_val + Constants.SCROLL_DISTANCE) + adj.emit('changed') + elif pos - adj_val < Constants.SCROLL_PROXIMITY_SENSITIVITY: + adj.set_value(adj_val - Constants.SCROLL_DISTANCE) + adj.emit('changed') + + scroll(x, scrollbox.get_hadjustment()) + scroll(y, scrollbox.get_vadjustment()) + def _handle_window_realize(self, widget): """ Called when the window is realized. Update the flowgraph, which calls new pixmap. """ self._flow_graph.update() + w, h = self._flow_graph.get_max_coords() + self.set_size_request(w + 100, h + 100) - def _handle_window_configure(self, widget, event): - """ - Called when the window is resized. - Create a new pixmap for background buffer. - """ - self._pixmap = self.new_pixmap(*self.get_size_request()) + def draw(self, widget, cr): + width = widget.get_allocated_width() + height = widget.get_allocated_height() + cr.set_source_rgba(*Colors.FLOWGRAPH_BACKGROUND_COLOR) + cr.rectangle(0, 0, width, height) - def _handle_window_expose(self, widget, event): - """ - Called when window is exposed, or queue_draw is called. - Double buffering: draw to pixmap, then draw pixmap to window. - """ - gc = self.window.new_gc() - self._flow_graph.draw(gc, self._pixmap) - self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1) - # draw a light grey line on the bottom and right end of the canvas. - # this is useful when the theme uses the same panel bg color as the canvas - W, H = self._pixmap.get_size() - gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR) - self.window.draw_line(gc, 0, H-1, W, H-1) - self.window.draw_line(gc, W-1, 0, W-1, H) + cr.scale(self.zoom_factor, self.zoom_factor) + cr.fill() + + self._flow_graph.draw(cr) + + def _translate_event_coords(self, event): + return event.x / self.zoom_factor, event.y / self.zoom_factor def _handle_focus_lost_event(self, widget, event): # don't clear selection while context menu is active - if not self._flow_graph.get_context_menu().flags() & gtk.VISIBLE: + if not self._flow_graph.get_context_menu().flags() & Gtk.VISIBLE: self._flow_graph.unselect() self._flow_graph.update_selected() self._flow_graph.queue_draw() |