diff options
Diffstat (limited to 'grc/gui')
-rw-r--r-- | grc/gui/ActionHandler.py | 1 | ||||
-rw-r--r-- | grc/gui/Block.py | 21 | ||||
-rw-r--r-- | grc/gui/Dialogs.py | 1 | ||||
-rw-r--r-- | grc/gui/DrawingArea.py | 12 | ||||
-rw-r--r-- | grc/gui/Element.py | 3 | ||||
-rw-r--r-- | grc/gui/FlowGraph.py | 42 | ||||
-rw-r--r-- | grc/gui/Makefile.am | 4 | ||||
-rw-r--r-- | grc/gui/Param.py | 51 | ||||
-rw-r--r-- | grc/gui/Port.py | 13 | ||||
-rw-r--r-- | grc/gui/Utils.py | 23 |
10 files changed, 115 insertions, 56 deletions
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index ee3e19a6c..108e23a23 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -29,7 +29,6 @@ import Preferences from threading import Thread import Messages from .. base import ParseXML -import random from MainWindow import MainWindow from PropsDialog import PropsDialog import Dialogs diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 8c65bf06f..27143e070 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -29,6 +29,7 @@ from Constants import \ import pygtk pygtk.require('2.0') import gtk +import pango BLOCK_MARKUP_TMPL="""\ #set $foreground = $block.is_valid() and 'black' or 'red' @@ -130,8 +131,11 @@ class Block(Element): layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self)) self.label_width, self.label_height = layout.get_pixel_size() #display the params - for param in filter(lambda p: p.get_hide() not in ('all', 'part'), self.get_params()): - layout = param.get_layout() + markups = [param.get_markup() for param in self.get_params() if param.get_hide() not in ('all', 'part')] + if markups: + layout = gtk.DrawingArea().create_pango_layout('') + layout.set_spacing(LABEL_SEPARATION*pango.SCALE) + layout.set_markup('\n'.join(markups)) layouts.append(layout) w,h = layout.get_pixel_size() self.label_width = max(w, self.label_width) @@ -151,12 +155,11 @@ class Block(Element): else: w_off = 0 pixmap.draw_layout(gc, w_off, h_off, layout) h_off = h + h_off + LABEL_SEPARATION - #create vertical and horizontal images - self.horizontal_label = image = pixmap.get_image(0, 0, width, height) + #create vertical and horizontal pixmaps + self.horizontal_label = pixmap if self.is_vertical(): - self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), height, width) - for i in range(width): - for j in range(height): vimage.put_pixel(j, width-i-1, image.get_pixel(i, j)) + self.vertical_label = self.get_parent().new_pixmap(height, width) + Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) #calculate width and height needed self.W = self.label_width + 2*BLOCK_LABEL_PADDING self.H = max(*( @@ -179,9 +182,9 @@ class Block(Element): ) #draw label image if self.is_horizontal(): - window.draw_image(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) + window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) elif self.is_vertical(): - window.draw_image(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) + window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) #draw ports for port in self.get_ports(): port.draw(gc, window) diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index af40f47c0..473c796af 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA import pygtk pygtk.require('2.0') import gtk -import Preferences import Utils class TextDisplay(gtk.TextView): diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index b70468ed0..790df7c3f 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -82,19 +82,21 @@ class DrawingArea(gtk.DrawingArea): Forward button click information to the flow graph. """ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self._flow_graph.handle_mouse_button_press( - left_click=(event.button == 1), + 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, + ) 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._flow_graph.handle_mouse_button_release( - left_click=(event.button == 1), + if event.button == 1: self._flow_graph.handle_mouse_selector_release( coordinate=(event.x, event.y), ) diff --git a/grc/gui/Element.py b/grc/gui/Element.py index f0518ee12..e020c5caa 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -17,9 +17,6 @@ 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 Constants import LINE_SELECT_SENSITIVITY from Constants import POSSIBLE_ROTATIONS diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 8feb171f1..897145a1d 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -22,7 +22,6 @@ import Actions import Colors import Utils from Element import Element -from .. base import FlowGraph as _FlowGraph import pygtk pygtk.require('2.0') import gtk @@ -52,6 +51,19 @@ class FlowGraph(Element): #selected ports self._old_selected_port = None self._new_selected_port = None + #context menu + self._context_menu = gtk.Menu() + for action in [ + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + Actions.BLOCK_PARAM_MODIFY, + ]: self._context_menu.append(action.create_menu_item()) ########################################################################### # Access Drawing Area @@ -426,14 +438,27 @@ class FlowGraph(Element): ########################################################################## ## Event Handlers ########################################################################## - def handle_mouse_button_press(self, left_click, double_click, coordinate): + def handle_mouse_context_press(self, coordinate, event): """ - A mouse button is pressed, only respond to left clicks. + The context mouse button was pressed: + If no elements were selected, perform re-selection at this coordinate. + Then, show the context menu at the mouse click location. + """ + selections = self.what_is_selected(coordinate) + if not set(selections).intersection(self.get_selected_elements()): + self.set_coordinate(coordinate) + self.mouse_pressed = True + self.update_selected_elements() + self.mouse_pressed = False + self._context_menu.popup(None, None, None, event.button, event.time) + + def handle_mouse_selector_press(self, double_click, coordinate): + """ + The selector mouse button was pressed: Find the selected element. Attempt a new connection if possible. Open the block params window on a double click. Update the selection state of the flow graph. """ - if not left_click: return self.press_coor = coordinate self.set_coordinate(coordinate) self.time = 0 @@ -445,11 +470,12 @@ class FlowGraph(Element): self.mouse_pressed = False Actions.BLOCK_PARAM_MODIFY() - def handle_mouse_button_release(self, left_click, coordinate): + def handle_mouse_selector_release(self, coordinate): """ - A mouse button is released, record the state. + The selector mouse button was released: + Update the state, handle motion (dragging). + And update the selected flowgraph elements. """ - if not left_click: return self.set_coordinate(coordinate) self.time = 0 self.mouse_pressed = False diff --git a/grc/gui/Makefile.am b/grc/gui/Makefile.am index b14817d04..a73b6855d 100644 --- a/grc/gui/Makefile.am +++ b/grc/gui/Makefile.am @@ -19,9 +19,9 @@ # Boston, MA 02110-1301, USA. # -include $(top_srcdir)/grc/Makefile.inc +include $(top_srcdir)/Makefile.common -ourpythondir = $(grc_src_prefix)/gui +ourpythondir = $(pkgpythondir)/grc/gui ourpython_PYTHON = \ Block.py \ Colors.py \ diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 4464a57ab..7c00c1b67 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -38,6 +38,7 @@ class InputParam(gtk.HBox): #connect events self.connect('show', self._update_gui) def set_color(self, color): pass + def set_tooltip_text(self, text): pass def _update_gui(self, *args): """ @@ -51,8 +52,7 @@ class InputParam(gtk.HBox): #set the color self.set_color(self.param.get_color()) #set the tooltip - if self.tp: self.tp.set_tip( - self.entry, + self.set_tooltip_text( Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(), ) #show/hide @@ -77,16 +77,13 @@ class EntryParam(InputParam): def __init__(self, *args, **kwargs): InputParam.__init__(self, *args, **kwargs) - self.entry = input = gtk.Entry() - input.set_text(self.param.get_value()) - input.connect('changed', self._handle_changed) - self.pack_start(input, True) - self.get_text = input.get_text - #tool tip - self.tp = gtk.Tooltips() - self.tp.set_tip(self.entry, '') - self.tp.enable() - def set_color(self, color): self.entry.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + self._input = gtk.Entry() + self._input.set_text(self.param.get_value()) + self._input.connect('changed', self._handle_changed) + self.pack_start(self._input, True) + def get_text(self): return self._input.get_text() + def set_color(self, color): self._input.modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) + def set_tooltip_text(self, text): self._input.set_tooltip_text(text) class EnumParam(InputParam): """Provide an entry box for Enum types with a drop down menu.""" @@ -99,6 +96,7 @@ class EnumParam(InputParam): self._input.connect('changed', self._handle_changed) self.pack_start(self._input, False) def get_text(self): return self.param.get_option_keys()[self._input.get_active()] + def set_tooltip_text(self, text): self._input.set_tooltip_text(text) class EnumEntryParam(InputParam): """Provide an entry box and drop down menu for Raw Enum types.""" @@ -117,6 +115,10 @@ class EnumEntryParam(InputParam): def get_text(self): if self._input.get_active() == -1: return self._input.get_child().get_text() return self.param.get_option_keys()[self._input.get_active()] + def set_tooltip_text(self, text): + if self._input.get_active() == -1: #custom entry + self._input.get_child().set_tooltip_text(text) + else: self._input.set_tooltip_text(text) def set_color(self, color): if self._input.get_active() == -1: #custom entry, use color self._input.get_child().modify_base(gtk.STATE_NORMAL, gtk.gdk.color_parse(color)) @@ -133,10 +135,21 @@ PARAM_LABEL_MARKUP_TMPL="""\ <span underline="$underline" foreground="$foreground" font_desc="Sans 9">$encode($param.get_name())</span>""" TIP_MARKUP_TMPL="""\ +######################################## +#def truncate(string) + #set $max_len = 100 + #set $string = str($string) + #if len($string) > $max_len +$('%s...%s'%($string[:$max_len/2], $string[-$max_len/2:]))#slurp + #else +$string#slurp + #end if +#end def +######################################## Key: $param.get_key() Type: $param.get_type() #if $param.is_valid() -Value: $param.get_evaluated() +Value: $truncate($param.get_evaluated()) #elif len($param.get_error_messages()) == 1 Error: $(param.get_error_messages()[0]) #else @@ -163,11 +176,9 @@ class Param(Element): if self.get_options(): return EnumEntryParam(self, *args, **kwargs) return EntryParam(self, *args, **kwargs) - def get_layout(self): + def get_markup(self): """ - Create a layout based on the current markup. - @return the pango layout + Get the markup for this param. + @return a pango markup string """ - layout = gtk.DrawingArea().create_pango_layout('') - layout.set_markup(Utils.parse_template(PARAM_MARKUP_TMPL, param=self)) - return layout + return Utils.parse_template(PARAM_MARKUP_TMPL, param=self) diff --git a/grc/gui/Port.py b/grc/gui/Port.py index 6763f6cbd..2896d04c1 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -97,12 +97,11 @@ class Port(Element): gc.set_foreground(self._bg_color) pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h) pixmap.draw_layout(gc, 0, 0, layout) - #create the images - self.horizontal_label = image = pixmap.get_image(0, 0, self.w, self.h) + #create vertical and horizontal pixmaps + self.horizontal_label = pixmap if self.is_vertical(): - self.vertical_label = vimage = gtk.gdk.Image(gtk.gdk.IMAGE_NORMAL, pixmap.get_visual(), self.h, self.w) - for i in range(self.w): - for j in range(self.h): vimage.put_pixel(j, self.w-i-1, image.get_pixel(i, j)) + self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w) + Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) def draw(self, gc, window): """ @@ -117,9 +116,9 @@ class Port(Element): X,Y = self.get_coordinate() (x,y),(w,h) = self._areas_list[0] #use the first area's sizes to place the labels if self.is_horizontal(): - window.draw_image(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) + window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) elif self.is_vertical(): - window.draw_image(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1) + window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1) def get_connector_coordinate(self): """ diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index 83036a4b8..b5489d56e 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -19,8 +19,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Constants import POSSIBLE_ROTATIONS from Cheetah.Template import Template +import pygtk +pygtk.require('2.0') +import gtk import gobject +def rotate_pixmap(gc, src_pixmap, dst_pixmap, angle=gtk.gdk.PIXBUF_ROTATE_COUNTERCLOCKWISE): + """ + Load the destination pixmap with a rotated version of the source pixmap. + The source pixmap will be loaded into a pixbuf, rotated, and drawn to the destination pixmap. + The pixbuf is a client-side drawable, where a pixmap is a server-side drawable. + @param gc the graphics context + @param src_pixmap the source pixmap + @param dst_pixmap the destination pixmap + @param angle the angle to rotate by + """ + width, height = src_pixmap.get_size() + pixbuf = gtk.gdk.Pixbuf( + colorspace=gtk.gdk.COLORSPACE_RGB, + has_alpha=False, bits_per_sample=8, + width=width, height=height, + ) + pixbuf.get_from_drawable(src_pixmap, src_pixmap.get_colormap(), 0, 0, 0, 0, -1, -1) + pixbuf = pixbuf.rotate_simple(angle) + dst_pixmap.draw_pixbuf(gc, pixbuf, 0, 0, 0, 0) + def get_rotated_coordinate(coor, rotation): """ Rotate the coordinate by the given rotation. |