summaryrefslogtreecommitdiff
path: root/grc/gui/DrawingArea.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/gui/DrawingArea.py')
-rw-r--r--grc/gui/DrawingArea.py196
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()