Merge remote branch 'ets/grc-usrp2-clock-source'
[debian/gnuradio] / grc / gui / DrawingArea.py
1 """
2 Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3 This file is part of GNU Radio
4
5 GNU Radio Companion is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 GNU Radio Companion is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18 """
19
20 import pygtk
21 pygtk.require('2.0')
22 import gtk
23 from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT, DND_TARGETS
24
25 class DrawingArea(gtk.DrawingArea):
26         """
27         DrawingArea is the gtk pixel map that graphical elements may draw themselves on.
28         The drawing area also responds to mouse and key events.
29         """
30
31         def __init__(self, flow_graph):
32                 """
33                 DrawingArea contructor.
34                 Connect event handlers.
35                 @param main_window the main_window containing all flow graphs
36                 """
37                 self.ctrl_mask = False
38                 self._flow_graph = flow_graph
39                 gtk.DrawingArea.__init__(self)
40                 self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
41                 self.connect('realize', self._handle_window_realize)
42                 self.connect('configure-event', self._handle_window_configure)
43                 self.connect('expose-event', self._handle_window_expose)
44                 self.connect('motion-notify-event', self._handle_mouse_motion)
45                 self.connect('button-press-event', self._handle_mouse_button_press)
46                 self.connect('button-release-event', self._handle_mouse_button_release)
47                 self.add_events(
48                         gtk.gdk.BUTTON_PRESS_MASK | \
49                         gtk.gdk.POINTER_MOTION_MASK | \
50                         gtk.gdk.BUTTON_RELEASE_MASK | \
51                         gtk.gdk.LEAVE_NOTIFY_MASK | \
52                         gtk.gdk.ENTER_NOTIFY_MASK
53                 )
54                 #setup drag and drop
55                 self.drag_dest_set(gtk.DEST_DEFAULT_ALL, DND_TARGETS, gtk.gdk.ACTION_COPY)
56                 self.connect('drag-data-received', self._handle_drag_data_received)
57                 #setup the focus flag
58                 self._focus_flag = False
59                 self.get_focus_flag = lambda: self._focus_flag
60                 def _handle_focus_event(widget, event, focus_flag): self._focus_flag = focus_flag
61                 self.connect('leave-notify-event', _handle_focus_event, False)
62                 self.connect('enter-notify-event', _handle_focus_event, True)
63
64         def new_pixmap(self, width, height): return gtk.gdk.Pixmap(self.window, width, height, -1)
65         def get_pixbuf(self):
66                 width, height = self._pixmap.get_size()
67                 pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, width, height)
68                 pixbuf.get_from_drawable(self._pixmap, self._pixmap.get_colormap(), 0, 0, 0, 0, width, height)
69                 return pixbuf
70
71         ##########################################################################
72         ## Handlers
73         ##########################################################################
74         def _handle_drag_data_received(self, widget, drag_context, x, y, selection_data, info, time):
75                 """
76                 Handle a drag and drop by adding a block at the given coordinate.
77                 """
78                 self._flow_graph.add_new_block(selection_data.data, (x, y))
79
80         def _handle_mouse_button_press(self, widget, event):
81                 """
82                 Forward button click information to the flow graph.
83                 """
84                 self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
85                 if event.button == 1: self._flow_graph.handle_mouse_selector_press(
86                         double_click=(event.type == gtk.gdk._2BUTTON_PRESS),
87                         coordinate=(event.x, event.y),
88                 )
89                 if event.button == 3: self._flow_graph.handle_mouse_context_press(
90                         coordinate=(event.x, event.y),
91                         event=event,
92                 )
93
94         def _handle_mouse_button_release(self, widget, event):
95                 """
96                 Forward button release information to the flow graph.
97                 """
98                 self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
99                 if event.button == 1: self._flow_graph.handle_mouse_selector_release(
100                         coordinate=(event.x, event.y),
101                 )
102
103         def _handle_mouse_motion(self, widget, event):
104                 """
105                 Forward mouse motion information to the flow graph.
106                 """
107                 self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK
108                 self._flow_graph.handle_mouse_motion(
109                         coordinate=(event.x, event.y),
110                 )
111
112         def _handle_window_realize(self, widget):
113                 """
114                 Called when the window is realized.
115                 Update the flowgraph, which calls new pixmap.
116                 """
117                 self._flow_graph.update()
118
119         def _handle_window_configure(self, widget, event):
120                 """
121                 Called when the window is resized.
122                 Create a new pixmap for background buffer.
123                 """
124                 self._pixmap = self.new_pixmap(*self.get_size_request())
125
126         def _handle_window_expose(self, widget, event):
127                 """
128                 Called when window is exposed, or queue_draw is called.
129                 Double buffering: draw to pixmap, then draw pixmap to window.
130                 """
131                 gc = self.window.new_gc()
132                 self._flow_graph.draw(gc, self._pixmap)
133                 self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1)