From 58cebfd63726dc2082ab31681afcd78e25c36132 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 00:45:14 -0700 Subject: Implement a recursive validation api in the base Element class. The rewrite and validate methods will invoke themselves on the child elements. The error messages are now a super-list of element and child error messages. As a side-effect, this cleans up code in base Block and Flowgraph class. --- grc/base/Block.py | 23 +---------------------- grc/base/Element.py | 48 +++++++++++++++++++++++++++++++++++++++++++----- grc/base/FlowGraph.py | 21 +-------------------- 3 files changed, 45 insertions(+), 47 deletions(-) (limited to 'grc') diff --git a/grc/base/Block.py b/grc/base/Block.py index fc501205f..cb21c3958 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -132,28 +132,6 @@ class Block(Element): """ self.get_param('_enabled').set_value(str(enabled)) - def rewrite(self): - """ - Rewrite critical structures. - Call rewrite on all sub elements. - """ - Element.rewrite(self) - for elem in self.get_ports() + self.get_params(): elem.rewrite() - - def validate(self): - """ - Validate the block. - All ports and params must be valid. - All checks must evaluate to true. - Validate the params, ports, and the connections to this block. - """ - Element.validate(self) - for c in self.get_params() + self.get_ports() + self.get_connections(): - c.validate() - if not c.is_valid(): - for msg in c.get_error_messages(): - self.add_error_message('>>> %s:\n\t%s'%(c, msg)) - def __str__(self): return 'Block - %s - %s(%s)'%(self.get_id(), self.get_name(), self.get_key()) def get_id(self): return self.get_param('id').get_value() @@ -163,6 +141,7 @@ class Block(Element): def get_category(self): return self._category def get_doc(self): return '' def get_ports(self): return self.get_sources() + self.get_sinks() + def get_children(self): return self.get_ports() + self.get_params() def get_block_wrapper_path(self): return self._block_wrapper_path ############################################## diff --git a/grc/base/Element.py b/grc/base/Element.py index 43cee886c..e77e7ce08 100644 --- a/grc/base/Element.py +++ b/grc/base/Element.py @@ -25,16 +25,54 @@ class Element(object): ################################################## # Element Validation API ################################################## - def validate(self): self._error_messages = list() - def is_valid(self): return not self.get_error_messages() or not self.get_enabled() - def add_error_message(self, msg): self._error_messages.append(msg) - def get_error_messages(self): return self._error_messages + def validate(self): + """ + Validate this element and call validate on all children. + Call this base method before adding error messages in the subclass. + """ + self._error_messages = list() + for child in self.get_children(): child.validate() - def rewrite(self): pass + def is_valid(self): + """ + Is this element valid? + @return true when the element is enabled and has no error messages + """ + return not self.get_error_messages() or not self.get_enabled() + + def add_error_message(self, msg): + """ + Add an error message to the list of errors. + @param msg the error message string + """ + self._error_messages.append(msg) + + def get_error_messages(self): + """ + Get the list of error messages from this element and all of its children. + Cleverly indent the children error messages for printing purposes. + @return a list of error message strings + """ + error_messages = list(self._error_messages) #make a copy + for child in self.get_children(): + for msg in child.get_error_messages(): + error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t"))) + return error_messages + + def rewrite(self): + """ + Rewrite this element and call rewrite on all children. + Call this base method before rewriting the element. + """ + for child in self.get_children(): child.rewrite() def get_enabled(self): return True + ############################################## + ## Tree-like API + ############################################## def get_parent(self): return self._parent + def get_children(self): return list() ############################################## ## Type testing methods diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py index b24f13b09..ce370ca24 100644 --- a/grc/base/FlowGraph.py +++ b/grc/base/FlowGraph.py @@ -68,6 +68,7 @@ class FlowGraph(Element): def get_block(self, id): return filter(lambda b: b.get_id() == id, self.get_blocks())[0] def get_blocks(self): return filter(lambda e: e.is_block(), self.get_elements()) def get_connections(self): return filter(lambda e: e.is_connection(), self.get_elements()) + def get_children(self): return self.get_elements() def get_elements(self): """ Get a list of all the elements. @@ -144,26 +145,6 @@ class FlowGraph(Element): """ raise NotImplementedError - def rewrite(self): - """ - Rewrite critical structures. - Call rewrite on all sub elements. - """ - Element.rewrite(self) - for elem in self.get_elements(): elem.rewrite() - - def validate(self): - """ - Validate the flow graph. - Validate only the blocks. - Connections will be validated within the blocks. - """ - Element.validate(self) - for c in self.get_blocks(): - c.validate() - if not c.is_valid(): - self.add_error_message('Element "%s" is not valid.'%c) - ############################################## ## Import/Export Methods ############################################## -- cgit From 4cc3667b348d58ef4fb30f0ecbe494cdb109fc83 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 00:54:56 -0700 Subject: better error msg for empty statements --- grc/python/FlowGraph.py | 1 + grc/todo.txt | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/python/FlowGraph.py b/grc/python/FlowGraph.py index 6b2936c75..4dd18a81f 100644 --- a/grc/python/FlowGraph.py +++ b/grc/python/FlowGraph.py @@ -42,6 +42,7 @@ class FlowGraph(_FlowGraph, _GUIFlowGraph): @param namespace_hash a unique hash for the namespace @return the resultant object """ + if not code: raise Exception, 'Cannot evaluate empty statement.' my_hash = hash(code) ^ namespace_hash #cache if does not exist if not self._eval_cache.has_key(my_hash): diff --git a/grc/todo.txt b/grc/todo.txt index ffc9d64db..ca9a68180 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -68,7 +68,6 @@ * save/restore cwd * threads dont die on exit in probe and variable sink * align param titles in paramsdialog -* better error for blank string params * weird grid params misbehaving * params dialog needs to dynamically update for all params * will not update for non-enum params -- cgit From 5f54b018b3a84ba4b68009a1c326ba73eaea8cfd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 01:54:41 -0700 Subject: standardized the Element inheritance __init__ usage in gui --- grc/gui/Block.py | 2 +- grc/gui/Connection.py | 2 ++ grc/gui/Element.py | 2 +- grc/gui/FlowGraph.py | 2 +- grc/gui/Param.py | 2 ++ grc/gui/Platform.py | 3 ++- grc/gui/Port.py | 2 +- 7 files changed, 10 insertions(+), 5 deletions(-) (limited to 'grc') diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 0f3e511d8..68c4da9c3 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -37,7 +37,7 @@ BLOCK_MARKUP_TMPL="""\ class Block(Element): """The graphical signal block.""" - def __init__(self, *args, **kwargs): + def __init__(self): """ Block contructor. Add graphics related params to the block. diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 013bcb00f..a85650ee2 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -32,6 +32,8 @@ class Connection(Element): The arrow coloring exposes the enabled and valid states. """ + def __init__(self): Element.__init__(self) + def get_coordinate(self): """ Get the 0,0 coordinate. diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 315191723..ecf1de1ca 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -32,7 +32,7 @@ class Element(object): and methods to detect selection of those areas. """ - def __init__(self, *args, **kwargs): + def __init__(self): """ Make a new list of rectangular areas and lines, and set the coordinate and the rotation. """ diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 5e645be72..8a908ff50 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -39,7 +39,7 @@ class FlowGraph(Element): and the connections between inputs and outputs. """ - def __init__(self, *args, **kwargs): + def __init__(self): """ FlowGraph contructor. Create a list for signal blocks and connections. Connect mouse handlers. diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 4955d3336..5cc8d9c7f 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -114,6 +114,8 @@ Error: class Param(Element): """The graphical parameter.""" + def __init__(self): Element.__init__(self) + def get_input_class(self): """ Get the graphical gtk class to represent this parameter. diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py index 8f0aa533d..8bbfaca23 100644 --- a/grc/gui/Platform.py +++ b/grc/gui/Platform.py @@ -19,4 +19,5 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Element import Element -class Platform(Element): pass +class Platform(Element): + def __init__(self): Element.__init__(self) diff --git a/grc/gui/Port.py b/grc/gui/Port.py index 6fc2c4b15..9c8d87a16 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -34,7 +34,7 @@ PORT_MARKUP_TMPL="""\ class Port(Element): """The graphical port.""" - def __init__(self, *args, **kwargs): + def __init__(self): """ Port contructor. Create list of connector coordinates. -- cgit From 5bb2a70a94be9c0f83712ee259b7125e3a582b08 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 02:01:41 -0700 Subject: replaced dict[rot] storage of areas and lines with a single list for the current rotation --- grc/gui/Element.py | 28 ++++++++++++---------------- grc/gui/Port.py | 2 +- 2 files changed, 13 insertions(+), 17 deletions(-) (limited to 'grc') diff --git a/grc/gui/Element.py b/grc/gui/Element.py index ecf1de1ca..bda187059 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -70,14 +70,14 @@ class Element(object): @param bg_color the color for the inside of the rectangle """ X,Y = self.get_coordinate() - for (rX,rY),(W,H) in self.areas_dict[self.get_rotation()]: + for (rX,rY),(W,H) in self._areas_list: aX = X + rX aY = Y + rY gc.set_foreground(bg_color) window.draw_rectangle(gc, True, aX, aY, W, H) gc.set_foreground(border_color) window.draw_rectangle(gc, False, aX, aY, W, H) - for (x1, y1),(x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1),(x2, y2) in self._lines_list: gc.set_foreground(border_color) window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) @@ -90,8 +90,8 @@ class Element(object): def clear(self): """Empty the lines and areas.""" - self.areas_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) - self.lines_dict = dict((rotation, list()) for rotation in POSSIBLE_ROTATIONS) + self._areas_list = list() + self._lines_list = list() def set_coordinate(self, coor): """ @@ -136,7 +136,7 @@ class Element(object): X, Y = self.get_coordinate() self.set_coordinate((X+deltaX, Y+deltaY)) - def add_area(self, rel_coor, area, rotation=None): + def add_area(self, rel_coor, area): """ Add an area to the area list. An area is actually a coordinate relative to the main coordinate @@ -144,25 +144,21 @@ class Element(object): A positive width is to the right of the coordinate. A positive height is above the coordinate. The area is associated with a rotation. - If rotation is not specified, the element's current rotation is used. @param rel_coor (x,y) offset from this element's coordinate @param area (width,height) tuple - @param rotation rotation in degrees """ - self.areas_dict[rotation or self.get_rotation()].append((rel_coor, area)) + self._areas_list.append((rel_coor, area)) - def add_line(self, rel_coor1, rel_coor2, rotation=None): + def add_line(self, rel_coor1, rel_coor2): """ Add a line to the line list. A line is defined by 2 relative coordinates. Lines must be horizontal or vertical. The line is associated with a rotation. - If rotation is not specified, the element's current rotation is used. @param rel_coor1 relative (x1,y1) tuple @param rel_coor2 relative (x2,y2) tuple - @param rotation rotation in degrees """ - self.lines_dict[rotation or self.get_rotation()].append((rel_coor1, rel_coor2)) + self._lines_list.append((rel_coor1, rel_coor2)) def what_is_selected(self, coor, coor_m=None): """ @@ -183,24 +179,24 @@ class Element(object): if coor_m: x_m, y_m = [a-b for a,b in zip(coor_m, self.get_coordinate())] #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: + for (x1,y1), (w,h) in self._areas_list: if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ in_between(x1+w, x, x_m) and in_between(y1, y, y_m) or \ in_between(x1, x, x_m) and in_between(y1+h, y, y_m) or \ in_between(x1+w, x, x_m) and in_between(y1+h, y, y_m): return self #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1), (x2, y2) in self._lines_list: if in_between(x1, x, x_m) and in_between(y1, y, y_m) or \ in_between(x2, x, x_m) and in_between(y2, y, y_m): return self return None else: #handle rectangular areas - for (x1,y1), (w,h) in self.areas_dict[self.get_rotation()]: + for (x1,y1), (w,h) in self._areas_list: if in_between(x, x1, x1+w) and in_between(y, y1, y1+h): return self #handle horizontal or vertical lines - for (x1, y1), (x2, y2) in self.lines_dict[self.get_rotation()]: + for (x1, y1), (x2, y2) in self._lines_list: if x1 == x2: x1, x2 = x1-LINE_SELECT_SENSITIVITY, x2+LINE_SELECT_SENSITIVITY if y1 == y2: y1, y2 = y1-LINE_SELECT_SENSITIVITY, y2+LINE_SELECT_SENSITIVITY if in_between(x, x1, x2) and in_between(y, y1, y2): return self diff --git a/grc/gui/Port.py b/grc/gui/Port.py index 9c8d87a16..f8bfefee6 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -114,7 +114,7 @@ class Port(Element): border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or Colors.BORDER_COLOR, ) X,Y = self.get_coordinate() - (x,y),(w,h) = self.areas_dict[self.get_rotation()][0] #use the first area's sizes to place the labels + (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) elif self.is_vertical(): -- cgit From fa465d160b0c53fae3ad7876cf429263157dd60a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 02:21:37 -0700 Subject: Created recursive create labels and shapes method for gui element. Replaces update methods in the gui classes and simplifies calls. The master update method in flow graph calls create labels and shapes. --- grc/gui/Block.py | 25 ++++++++++++------------- grc/gui/Connection.py | 7 ++++--- grc/gui/Element.py | 19 +++++++++++++++---- grc/gui/FlowGraph.py | 7 ++++--- grc/gui/Port.py | 7 ++++--- 5 files changed, 39 insertions(+), 26 deletions(-) (limited to 'grc') diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 68c4da9c3..fd8cfc226 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -113,23 +113,16 @@ class Block(Element): """ self.get_param('_rotation').set_value(str(rot)) - def update(self): + def create_shapes(self): """Update the block, parameters, and ports when a change occurs.""" - self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR - self.clear() - self._create_labels() - self.W = self.label_width + 2*BLOCK_LABEL_PADDING - self.H = max(*( - [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ - sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION - for ports in (self.get_sources(), self.get_sinks())] - )) + Element.create_shapes(self) if self.is_horizontal(): self.add_area((0, 0), (self.W, self.H)) elif self.is_vertical(): self.add_area((0, 0), (self.H, self.W)) - map(lambda p: p.update(), self.get_ports()) - def _create_labels(self): + def create_labels(self): """Create the labels for the signal block.""" + Element.create_labels(self) + self._bg_color = self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR layouts = list() #create the main layout layout = gtk.DrawingArea().create_pango_layout('') @@ -164,7 +157,13 @@ class Block(Element): 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)) - map(lambda p: p._create_labels(), self.get_ports()) + #calculate width and height needed + self.W = self.label_width + 2*BLOCK_LABEL_PADDING + self.H = max(*( + [self.label_height+2*BLOCK_LABEL_PADDING] + [2*PORT_BORDER_SEPARATION + \ + sum([port.H + PORT_SEPARATION for port in ports]) - PORT_SEPARATION + for ports in (self.get_sources(), self.get_sinks())] + )) def draw(self, gc, window): """ diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index a85650ee2..45f8a689a 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -50,8 +50,9 @@ class Connection(Element): """ return 0 - def update(self): + def create_shapes(self): """Precalculate relative coordinates.""" + Element.create_shapes(self) self._sink_rot = None self._source_rot = None self._sink_coor = None @@ -74,7 +75,7 @@ class Connection(Element): def _update_after_move(self): """Calculate coordinates.""" - self.clear() + self.clear() #FIXME do i want this here? #source connector source = self.get_source() X, Y = source.get_connector_coordinate() @@ -125,7 +126,7 @@ class Connection(Element): sink = self.get_sink() source = self.get_source() #check for changes - if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.update() + if self._sink_rot != sink.get_rotation() or self._source_rot != source.get_rotation(): self.create_shapes() elif self._sink_coor != sink.get_coordinate() or self._source_coor != source.get_coordinate(): self._update_after_move() #cache values self._sink_rot = sink.get_rotation() diff --git a/grc/gui/Element.py b/grc/gui/Element.py index bda187059..2e20b9a22 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -61,6 +61,21 @@ class Element(object): rotation = rotation or self.get_rotation() return rotation in (90, 270) + def create_labels(self): + """ + Create labels (if applicable) and call on all children. + Call this base method before creating labels in the element. + """ + for child in self.get_children(): child.create_labels() + + def create_shapes(self): + """ + Create shapes (if applicable) and call on all children. + Call this base method before creating shapes in the element. + """ + self.clear() + for child in self.get_children(): child.create_shapes() + def draw(self, gc, window, border_color, bg_color): """ Draw in the given window. @@ -216,7 +231,3 @@ class Element(object): if rotation not in POSSIBLE_ROTATIONS: raise Exception('"%s" is not one of the possible rotations: (%s)'%(rotation, POSSIBLE_ROTATIONS)) self.rotation = rotation - - def update(self): - """Do nothing for the update. Dummy method.""" - pass diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 8a908ff50..35ccf5e27 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -291,12 +291,13 @@ class FlowGraph(Element): def update(self): """ - Do a global rewrite and validate. - Call update on all elements. + Call the top level rewrite and validate. + Call the top level create labels and shapes. """ self.rewrite() self.validate() - for element in self.get_elements(): element.update() + self.create_labels() + self.create_shapes() ########################################################################## ## Get Selected diff --git a/grc/gui/Port.py b/grc/gui/Port.py index f8bfefee6..6763f6cbd 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -42,9 +42,9 @@ class Port(Element): Element.__init__(self) self.connector_coordinates = dict() - def update(self): + def create_shapes(self): """Create new areas and labels for the port.""" - self.clear() + Element.create_shapes(self) #get current rotation rotation = self.get_rotation() #get all sibling ports @@ -82,8 +82,9 @@ class Port(Element): #the connector length self._connector_length = CONNECTOR_EXTENSION_MINIMAL + CONNECTOR_EXTENSION_INCREMENT*index - def _create_labels(self): + def create_labels(self): """Create the labels for the socket.""" + Element.create_labels(self) self._bg_color = Colors.get_color(self.get_color()) #create the layout layout = gtk.DrawingArea().create_pango_layout('') -- cgit From caf93a02068e8379ffa7f553deabb62cfc42b9a7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 02:38:46 -0700 Subject: remove unused imports, copyright date update, tweak --- grc/gui/Block.py | 2 +- grc/gui/Connection.py | 2 +- grc/gui/Element.py | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'grc') diff --git a/grc/gui/Block.py b/grc/gui/Block.py index fd8cfc226..8c65bf06f 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -135,7 +135,7 @@ class Block(Element): layouts.append(layout) w,h = layout.get_pixel_size() self.label_width = max(w, self.label_width) - self.label_height = self.label_height + h + LABEL_SEPARATION + self.label_height += h + LABEL_SEPARATION width = self.label_width height = self.label_height #setup the pixmap diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 45f8a689a..fabf34ee7 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 2e20b9a22..f0518ee12 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -1,5 +1,5 @@ """ -Copyright 2007 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -17,11 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import Colors import pygtk pygtk.require('2.0') import gtk -import pango from Constants import LINE_SELECT_SENSITIVITY from Constants import POSSIBLE_ROTATIONS -- cgit From 79bace9eb9e441405535e082f3f0ee1a26740fe0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 21:11:51 -0700 Subject: renamed params dialog to props dialog --- grc/gui/ActionHandler.py | 4 +- grc/gui/Makefile.am | 2 +- grc/gui/ParamsDialog.py | 145 ----------------------------------------------- grc/gui/PropsDialog.py | 145 +++++++++++++++++++++++++++++++++++++++++++++++ grc/todo.txt | 2 + 5 files changed, 150 insertions(+), 148 deletions(-) delete mode 100644 grc/gui/ParamsDialog.py create mode 100644 grc/gui/PropsDialog.py (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 8f317d6a8..f12893579 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -31,7 +31,7 @@ import Messages from .. base import ParseXML import random from MainWindow import MainWindow -from ParamsDialog import ParamsDialog +from PropsDialog import PropsDialog import Dialogs from FileDialogs import OpenFlowGraphFileDialog, SaveFlowGraphFileDialog, SaveImageFileDialog @@ -240,7 +240,7 @@ class ActionHandler: ################################################## elif state == Actions.BLOCK_PARAM_MODIFY: selected_block = self.get_flow_graph().get_selected_block() - if selected_block and ParamsDialog(selected_block).run(): + if selected_block and PropsDialog(selected_block).run(): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) diff --git a/grc/gui/Makefile.am b/grc/gui/Makefile.am index cb45d5359..b14817d04 100644 --- a/grc/gui/Makefile.am +++ b/grc/gui/Makefile.am @@ -43,7 +43,7 @@ ourpython_PYTHON = \ MainWindow.py \ Messages.py \ NotebookPage.py \ - ParamsDialog.py \ + PropsDialog.py \ Preferences.py \ StateCache.py \ __init__.py diff --git a/grc/gui/ParamsDialog.py b/grc/gui/ParamsDialog.py deleted file mode 100644 index ccf19d1a2..000000000 --- a/grc/gui/ParamsDialog.py +++ /dev/null @@ -1,145 +0,0 @@ -""" -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -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 Dialogs import TextDisplay -from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT - -def get_title_label(title): - """ - Get a title label for the params window. - The title will be bold, underlined, and left justified. - @param title the text of the title - @return a gtk object - """ - label = gtk.Label() - label.set_markup('\n%s:\n'%title) - hbox = gtk.HBox() - hbox.pack_start(label, False, False, padding=11) - return hbox - -class ParamsDialog(gtk.Dialog): - """A dialog box to set block parameters.""" - - def __init__(self, block): - """ - SignalBlockParamsDialog contructor. - @param block the signal block - """ - gtk.Dialog.__init__(self, - title='Properties: %s'%block.get_name(), - buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), - ) - self.block = block - self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) - vbox = gtk.VBox() - #Add the title label - vbox.pack_start(get_title_label('Parameters'), False) - #Create the scrolled window to hold all the parameters - scrolled_window = gtk.ScrolledWindow() - scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - scrolled_window.add_with_viewport(vbox) - self.vbox.pack_start(scrolled_window, True) - #Error Messages for the block - self._error_box = gtk.VBox() - self._error_messages_text_display = TextDisplay() - self._error_box.pack_start(gtk.Label(), False, False, 7) #spacing - self._error_box.pack_start(get_title_label('Error Messages'), False) - self._error_box.pack_start(self._error_messages_text_display, False) - #Docs for the block - self._docs_box = err_box = gtk.VBox() - self._docs_text_display = TextDisplay() - self._docs_box.pack_start(gtk.Label(), False, False, 7) #spacing - self._docs_box.pack_start(get_title_label('Documentation'), False) - self._docs_box.pack_start(self._docs_text_display, False) - #Add all the parameters - for param in self.block.get_params(): - vbox.pack_start(param.get_input_object(self._handle_changed), False) - #Add the error and docs box - vbox.pack_start(self._error_box, False) - vbox.pack_start(self._docs_box, False) - #connect and show - self.connect('key_press_event', self._handle_key_press) - self.show_all() - #initial update - for param in self.block.get_params(): param.update() - self._update() - - def _update(self): - """ - Update the error messages box. - Hide the box if there are no errors. - Update the documentation block. - Hide the box if there are no docs. - """ - self.block.validate() - #update the errors box - if self.block.is_valid(): self._error_box.hide() - else: self._error_box.show() - messages = '\n\n'.join(self.block.get_error_messages()) - self._error_messages_text_display.set_text(messages) - #update the docs box - if self.block.get_doc(): self._docs_box.show() - else: self._docs_box.hide() - self._docs_text_display.set_text(self.block.get_doc()) - - def _handle_key_press(self, widget, event): - """ - Handle key presses from the keyboard. - Call the ok response when enter is pressed. - @return false to forward the keypress - """ - keyname = gtk.gdk.keyval_name(event.keyval) - if keyname == 'Return': self.response(gtk.RESPONSE_OK) - return False #forward the keypress - - def _handle_changed(self, param): - """ - A change occured, update any dependent parameters: - The enum inside the variable type may have changed and, - the variable param will need an external update. - @param param the graphical parameter that initiated the callback - """ - #update dependent params - if param.is_enum(): - for other_param in param.get_parent().get_params(): - if param.get_key() is not other_param.get_key() and ( - param.get_key() in other_param._type or \ - param.get_key() in other_param._hide): other_param.update() - #update - self._update() - return True - - def run(self): - """ - Call run(). - @return true if a change occured. - """ - original_data = list() - for param in self.block.get_params(): - original_data.append(param.get_value()) - gtk.Dialog.run(self) - self.destroy() - new_data = list() - for param in self.block.get_params(): - new_data.append(param.get_value()) - return original_data != new_data diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py new file mode 100644 index 000000000..200cff1f5 --- /dev/null +++ b/grc/gui/PropsDialog.py @@ -0,0 +1,145 @@ +""" +Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +This file is part of GNU Radio + +GNU Radio Companion is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +GNU Radio Companion is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +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 Dialogs import TextDisplay +from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT + +def get_title_label(title): + """ + Get a title label for the params window. + The title will be bold, underlined, and left justified. + @param title the text of the title + @return a gtk object + """ + label = gtk.Label() + label.set_markup('\n%s:\n'%title) + hbox = gtk.HBox() + hbox.pack_start(label, False, False, padding=11) + return hbox + +class PropsDialog(gtk.Dialog): + """A dialog box to set block parameters.""" + + def __init__(self, block): + """ + SignalBlockParamsDialog contructor. + @param block the signal block + """ + gtk.Dialog.__init__(self, + title='Properties: %s'%block.get_name(), + buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), + ) + self.block = block + self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) + vbox = gtk.VBox() + #Add the title label + vbox.pack_start(get_title_label('Parameters'), False) + #Create the scrolled window to hold all the parameters + scrolled_window = gtk.ScrolledWindow() + scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window.add_with_viewport(vbox) + self.vbox.pack_start(scrolled_window, True) + #Error Messages for the block + self._error_box = gtk.VBox() + self._error_messages_text_display = TextDisplay() + self._error_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._error_box.pack_start(get_title_label('Error Messages'), False) + self._error_box.pack_start(self._error_messages_text_display, False) + #Docs for the block + self._docs_box = err_box = gtk.VBox() + self._docs_text_display = TextDisplay() + self._docs_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._docs_box.pack_start(get_title_label('Documentation'), False) + self._docs_box.pack_start(self._docs_text_display, False) + #Add all the parameters + for param in self.block.get_params(): + vbox.pack_start(param.get_input_object(self._handle_changed), False) + #Add the error and docs box + vbox.pack_start(self._error_box, False) + vbox.pack_start(self._docs_box, False) + #connect and show + self.connect('key_press_event', self._handle_key_press) + self.show_all() + #initial update + for param in self.block.get_params(): param.update() + self._update() + + def _update(self): + """ + Update the error messages box. + Hide the box if there are no errors. + Update the documentation block. + Hide the box if there are no docs. + """ + self.block.validate() + #update the errors box + if self.block.is_valid(): self._error_box.hide() + else: self._error_box.show() + messages = '\n\n'.join(self.block.get_error_messages()) + self._error_messages_text_display.set_text(messages) + #update the docs box + if self.block.get_doc(): self._docs_box.show() + else: self._docs_box.hide() + self._docs_text_display.set_text(self.block.get_doc()) + + def _handle_key_press(self, widget, event): + """ + Handle key presses from the keyboard. + Call the ok response when enter is pressed. + @return false to forward the keypress + """ + keyname = gtk.gdk.keyval_name(event.keyval) + if keyname == 'Return': self.response(gtk.RESPONSE_OK) + return False #forward the keypress + + def _handle_changed(self, param): + """ + A change occured, update any dependent parameters: + The enum inside the variable type may have changed and, + the variable param will need an external update. + @param param the graphical parameter that initiated the callback + """ + #update dependent params + if param.is_enum(): + for other_param in param.get_parent().get_params(): + if param.get_key() is not other_param.get_key() and ( + param.get_key() in other_param._type or \ + param.get_key() in other_param._hide): other_param.update() + #update + self._update() + return True + + def run(self): + """ + Call run(). + @return true if a change occured. + """ + original_data = list() + for param in self.block.get_params(): + original_data.append(param.get_value()) + gtk.Dialog.run(self) + self.destroy() + new_data = list() + for param in self.block.get_params(): + new_data.append(param.get_value()) + return original_data != new_data diff --git a/grc/todo.txt b/grc/todo.txt index ca9a68180..8afd2f145 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -73,6 +73,8 @@ * will not update for non-enum params * needs to account for added or removed params * example with grid params need update after notebook change + * idea: hash the current param keys list and types, + if changed, redo the whole dialog (params part) ################################################## # Future -- cgit From 49b8dd0586241f59df4b74679349718cbe946fde Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 23:41:49 -0700 Subject: Rework the params/properties dialog and param gui class: Better handles dynamic changes and subsequent code cleanup. --- grc/gui/Param.py | 65 +++++++++++++++++++------------------- grc/gui/PropsDialog.py | 84 +++++++++++++++++++++++++++++++------------------- grc/todo.txt | 9 ++---- 3 files changed, 87 insertions(+), 71 deletions(-) (limited to 'grc') diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 5cc8d9c7f..3c5e99e9e 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -26,10 +26,10 @@ import gtk class InputParam(gtk.HBox): """The base class for an input parameter inside the input parameters dialog.""" - def __init__(self, param, _handle_changed): + def __init__(self, param, callback=None): gtk.HBox.__init__(self) self.param = param - self._handle_changed = _handle_changed + self._callback = callback self.label = gtk.Label('') #no label, markup is added by set_markup self.label.set_size_request(150, -1) self.pack_start(self.label, False) @@ -37,6 +37,34 @@ class InputParam(gtk.HBox): self.tp = None def set_color(self, color): pass + def update(self): + """ + Set the markup, color, and tooltip. + """ + #set the markup + has_cb = \ + hasattr(self.param.get_parent(), 'get_callbacks') and \ + filter(lambda c: self.param.get_key() in c, self.param.get_parent()._callbacks) + self.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self.param, has_cb=has_cb)) + #set the color + self.set_color(self.param.get_color()) + #set the tooltip + if self.tp: self.tp.set_tip( + self.entry, + Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(), + ) + + def _handle_changed(self, *args): + """ + Handle a gui change by setting the new param value, + calling the callback (if applicable), and updating. + """ + #set the new value + self.param.set_value(self.get_text()) + #call the callback + if self._callback: self._callback() + #self.update() #dont update here, parent will update + class EntryParam(InputParam): """Provide an entry box for strings and numbers.""" @@ -138,39 +166,10 @@ class Param(Element): def get_input_object(self, callback=None): """ Get the graphical gtk object to represent this parameter. - Create the input object with this data type and the handle changed method. - @param callback a function of one argument(this param) to be called from the change handler + @param callback a function to be called from the input object. @return gtk input object """ - self._callback = callback - self._input = self.get_input_class()(self, self._handle_changed) - if not self._callback: self.update() - return self._input - - def _handle_changed(self, widget=None): - """ - When the input changes, write the inputs to the data type. - Finish by calling the exteral callback. - """ - self.set_value(self._input.get_text()) - self.validate() - #is param is involved in a callback? #FIXME: messy - has_cb = \ - hasattr(self.get_parent(), 'get_callbacks') and \ - filter(lambda c: self.get_key() in c, self.get_parent()._callbacks) - self._input.set_markup(Utils.parse_template(PARAM_LABEL_MARKUP_TMPL, param=self, has_cb=has_cb)) - #hide/show - if self.get_hide() == 'all': self._input.hide_all() - else: self._input.show_all() - #set the color - self._input.set_color(self.get_color()) - #set the tooltip - if self._input.tp: self._input.tp.set_tip( - self._input.entry, - Utils.parse_template(TIP_MARKUP_TMPL, param=self).strip(), - ) - #execute the external callback - if self._callback: self._callback(self) + return self.get_input_class()(self, callback=callback) def get_layout(self): """ diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 200cff1f5..bd66b1178 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -38,13 +38,17 @@ def get_title_label(title): return hbox class PropsDialog(gtk.Dialog): - """A dialog box to set block parameters.""" + """ + A dialog to set block parameters, view errors, and view documentation. + """ def __init__(self, block): """ - SignalBlockParamsDialog contructor. - @param block the signal block + Properties dialog contructor. + @param block a block instance """ + self._hash = '' + LABEL_SPACING = 7 gtk.Dialog.__init__(self, title='Properties: %s'%block.get_name(), buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), @@ -52,46 +56,81 @@ class PropsDialog(gtk.Dialog): self.block = block self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) vbox = gtk.VBox() - #Add the title label - vbox.pack_start(get_title_label('Parameters'), False) #Create the scrolled window to hold all the parameters scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolled_window.add_with_viewport(vbox) self.vbox.pack_start(scrolled_window, True) + #Params box for block parameters + self._params_box = gtk.VBox() + self._params_box.pack_start(get_title_label('Parameters'), False) + self._input_object_params = list() #Error Messages for the block self._error_box = gtk.VBox() self._error_messages_text_display = TextDisplay() - self._error_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._error_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) self._error_box.pack_start(get_title_label('Error Messages'), False) self._error_box.pack_start(self._error_messages_text_display, False) #Docs for the block self._docs_box = err_box = gtk.VBox() self._docs_text_display = TextDisplay() - self._docs_box.pack_start(gtk.Label(), False, False, 7) #spacing + self._docs_box.pack_start(gtk.Label(), False, False, LABEL_SPACING) self._docs_box.pack_start(get_title_label('Documentation'), False) self._docs_box.pack_start(self._docs_text_display, False) - #Add all the parameters - for param in self.block.get_params(): - vbox.pack_start(param.get_input_object(self._handle_changed), False) - #Add the error and docs box + #Add the boxes + vbox.pack_start(self._params_box, False) vbox.pack_start(self._error_box, False) vbox.pack_start(self._docs_box, False) - #connect and show + #connect key press event self.connect('key_press_event', self._handle_key_press) + #initial update to populate the params self.show_all() - #initial update - for param in self.block.get_params(): param.update() self._update() + def _params_changed(self): + """ + Have the params in this dialog changed? + Ex: Added, removed, type change, hidden, shown? + Make a hash that uniquely represents the params state. + @return true if changed + """ + old_hash = self._hash + str_accum = '' + for param in self.block.get_params(): + str_accum += param.get_key() + str_accum += param.get_type() + str_accum += param.get_hide() + self._hash = hash(str_accum) + return self._hash != old_hash + def _update(self): """ + Repopulate the parameters box (if changed). + Update all the input parameters. Update the error messages box. Hide the box if there are no errors. Update the documentation block. Hide the box if there are no docs. """ + #update for the block + self.block.rewrite() self.block.validate() + #update the params box + if self._params_changed(): + #empty the params box + for io_param in list(self._input_object_params): + self._params_box.remove(io_param) + self._input_object_params.remove(io_param) + io_param.destroy() + #repopulate the params box + for param in self.block.get_params(): + if param.get_hide() == 'all': continue + io_param = param.get_input_object(self._update) + self._input_object_params.append(io_param) + self._params_box.pack_start(io_param, False) + self._params_box.show_all() + #update the gui inputs + for io_param in self._input_object_params: io_param.update() #update the errors box if self.block.is_valid(): self._error_box.hide() else: self._error_box.show() @@ -112,23 +151,6 @@ class PropsDialog(gtk.Dialog): if keyname == 'Return': self.response(gtk.RESPONSE_OK) return False #forward the keypress - def _handle_changed(self, param): - """ - A change occured, update any dependent parameters: - The enum inside the variable type may have changed and, - the variable param will need an external update. - @param param the graphical parameter that initiated the callback - """ - #update dependent params - if param.is_enum(): - for other_param in param.get_parent().get_params(): - if param.get_key() is not other_param.get_key() and ( - param.get_key() in other_param._type or \ - param.get_key() in other_param._hide): other_param.update() - #update - self._update() - return True - def run(self): """ Call run(). diff --git a/grc/todo.txt b/grc/todo.txt index 8afd2f145..99351a912 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -67,14 +67,9 @@ * dont generate py files in saved flowgraph dir * save/restore cwd * threads dont die on exit in probe and variable sink -* align param titles in paramsdialog +* align param titles in properties dialog * weird grid params misbehaving -* params dialog needs to dynamically update for all params - * will not update for non-enum params - * needs to account for added or removed params - * example with grid params need update after notebook change - * idea: hash the current param keys list and types, - if changed, redo the whole dialog (params part) +* properties dialog needs to show connection errors ################################################## # Future -- cgit From a6cb9eceeb62593e852b6dea0f640436381ec947 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sat, 5 Sep 2009 23:49:34 -0700 Subject: more code cleanup for properties dialog --- grc/gui/Param.py | 15 --------------- grc/gui/PropsDialog.py | 2 +- grc/todo.txt | 1 + 3 files changed, 2 insertions(+), 16 deletions(-) (limited to 'grc') diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 3c5e99e9e..9cd31b8a4 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -156,21 +156,6 @@ class Param(Element): if self.get_options(): return EnumEntryParam return EntryParam - def update(self): - """ - Called when an external change occurs. - Update the graphical input by calling the change handler. - """ - if hasattr(self, '_input'): self._handle_changed() - - def get_input_object(self, callback=None): - """ - Get the graphical gtk object to represent this parameter. - @param callback a function to be called from the input object. - @return gtk input object - """ - return self.get_input_class()(self, callback=callback) - def get_layout(self): """ Create a layout based on the current markup. diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index bd66b1178..9be0400fe 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -125,7 +125,7 @@ class PropsDialog(gtk.Dialog): #repopulate the params box for param in self.block.get_params(): if param.get_hide() == 'all': continue - io_param = param.get_input_object(self._update) + io_param = param.get_input_class()(param, callback=self._update) self._input_object_params.append(io_param) self._params_box.pack_start(io_param, False) self._params_box.show_all() diff --git a/grc/todo.txt b/grc/todo.txt index 99351a912..2735ff2af 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -70,6 +70,7 @@ * align param titles in properties dialog * weird grid params misbehaving * properties dialog needs to show connection errors +* fix param input stuff for usrp probes ################################################## # Future -- cgit From e39507bf32666f9b17d2249106aac0d6cbcacc58 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 6 Sep 2009 01:17:35 -0700 Subject: propsdialog tweaks --- grc/gui/Param.py | 13 ++++++++----- grc/gui/PropsDialog.py | 39 ++++++++++++++++++--------------------- grc/python/Param.py | 6 +++--- grc/todo.txt | 1 - 4 files changed, 29 insertions(+), 30 deletions(-) (limited to 'grc') diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 9cd31b8a4..b84598e61 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -39,7 +39,7 @@ class InputParam(gtk.HBox): def update(self): """ - Set the markup, color, and tooltip. + Set the markup, color, tooltip, show/hide. """ #set the markup has_cb = \ @@ -53,6 +53,9 @@ class InputParam(gtk.HBox): self.entry, Utils.parse_template(TIP_MARKUP_TMPL, param=self.param).strip(), ) + #show/hide + if self.param.get_hide() == 'all': self.hide_all() + else: self.show_all() def _handle_changed(self, *args): """ @@ -144,7 +147,7 @@ class Param(Element): def __init__(self): Element.__init__(self) - def get_input_class(self): + def get_input(self, *args, **kwargs): """ Get the graphical gtk class to represent this parameter. An enum requires and combo parameter. @@ -152,9 +155,9 @@ class Param(Element): All others get a standard entry parameter. @return gtk input class """ - if self.is_enum(): return EnumParam - if self.get_options(): return EnumEntryParam - return EntryParam + if self.is_enum(): return EnumParam(*args, **kwargs) + if self.get_options(): return EnumEntryParam(*args, **kwargs) + return EntryParam(*args, **kwargs) def get_layout(self): """ diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 9be0400fe..aa86f7214 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -47,13 +47,13 @@ class PropsDialog(gtk.Dialog): Properties dialog contructor. @param block a block instance """ - self._hash = '' + self._hash = 0 LABEL_SPACING = 7 gtk.Dialog.__init__(self, title='Properties: %s'%block.get_name(), buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), ) - self.block = block + self._block = block self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) vbox = gtk.VBox() #Create the scrolled window to hold all the parameters @@ -90,17 +90,15 @@ class PropsDialog(gtk.Dialog): def _params_changed(self): """ Have the params in this dialog changed? - Ex: Added, removed, type change, hidden, shown? + Ex: Added, removed, type change... Make a hash that uniquely represents the params state. @return true if changed """ old_hash = self._hash - str_accum = '' - for param in self.block.get_params(): - str_accum += param.get_key() - str_accum += param.get_type() - str_accum += param.get_hide() - self._hash = hash(str_accum) + self._hash = 0 + for param in self._block.get_params(): + self._hash ^= hash(param) + self._hash ^= hash(param.get_type()) return self._hash != old_hash def _update(self): @@ -113,33 +111,32 @@ class PropsDialog(gtk.Dialog): Hide the box if there are no docs. """ #update for the block - self.block.rewrite() - self.block.validate() + self._block.rewrite() + self._block.validate() #update the params box if self._params_changed(): #empty the params box for io_param in list(self._input_object_params): + io_param.hide_all() self._params_box.remove(io_param) self._input_object_params.remove(io_param) io_param.destroy() #repopulate the params box - for param in self.block.get_params(): - if param.get_hide() == 'all': continue - io_param = param.get_input_class()(param, callback=self._update) + for param in self._block.get_params(): + io_param = param.get_input(param, callback=self._update) self._input_object_params.append(io_param) self._params_box.pack_start(io_param, False) - self._params_box.show_all() #update the gui inputs for io_param in self._input_object_params: io_param.update() #update the errors box - if self.block.is_valid(): self._error_box.hide() + if self._block.is_valid(): self._error_box.hide() else: self._error_box.show() - messages = '\n\n'.join(self.block.get_error_messages()) + messages = '\n\n'.join(self._block.get_error_messages()) self._error_messages_text_display.set_text(messages) #update the docs box - if self.block.get_doc(): self._docs_box.show() + if self._block.get_doc(): self._docs_box.show() else: self._docs_box.hide() - self._docs_text_display.set_text(self.block.get_doc()) + self._docs_text_display.set_text(self._block.get_doc()) def _handle_key_press(self, widget, event): """ @@ -157,11 +154,11 @@ class PropsDialog(gtk.Dialog): @return true if a change occured. """ original_data = list() - for param in self.block.get_params(): + for param in self._block.get_params(): original_data.append(param.get_value()) gtk.Dialog.run(self) self.destroy() new_data = list() - for param in self.block.get_params(): + for param in self._block.get_params(): new_data.append(param.get_value()) return original_data != new_data diff --git a/grc/python/Param.py b/grc/python/Param.py index e61779136..c64659a08 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -153,9 +153,9 @@ class Param(_Param, _GUIParam): dt_str = dt_str[:max_len-3] + '...' return dt_str - def get_input_class(self): - if self.get_type() in ('file_open', 'file_save'): return FileParam - return _GUIParam.get_input_class(self) + def get_input(self, *args, **kwargs): + if self.get_type() in ('file_open', 'file_save'): return FileParam(*args, **kwargs) + return _GUIParam.get_input(self, *args, **kwargs) def get_color(self): """ diff --git a/grc/todo.txt b/grc/todo.txt index 2735ff2af..c675859d1 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -69,7 +69,6 @@ * threads dont die on exit in probe and variable sink * align param titles in properties dialog * weird grid params misbehaving -* properties dialog needs to show connection errors * fix param input stuff for usrp probes ################################################## -- cgit From 6b1d8817a7fc6dd99a770cb11fac7ca48a3c81b0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 6 Sep 2009 01:58:25 -0700 Subject: Fixed the usrp and usrp2 probe scripts to work with the new gui param api. Also fixed the scripts to work since they were broken by previous changes. Get input in param class now pases a param instance (self) into the object. --- grc/gui/Param.py | 14 +++++++++----- grc/gui/PropsDialog.py | 2 +- grc/python/Param.py | 2 +- grc/scripts/usrp2_probe | 13 ++++++++----- grc/scripts/usrp_probe | 13 ++++++++----- grc/todo.txt | 1 - 6 files changed, 27 insertions(+), 18 deletions(-) (limited to 'grc') diff --git a/grc/gui/Param.py b/grc/gui/Param.py index b84598e61..7fabb6671 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -30,7 +30,7 @@ class InputParam(gtk.HBox): gtk.HBox.__init__(self) self.param = param self._callback = callback - self.label = gtk.Label('') #no label, markup is added by set_markup + self.label = gtk.Label() #no label, markup is added by set_markup self.label.set_size_request(150, -1) self.pack_start(self.label, False) self.set_markup = lambda m: self.label.set_markup(m) @@ -66,7 +66,11 @@ class InputParam(gtk.HBox): self.param.set_value(self.get_text()) #call the callback if self._callback: self._callback() - #self.update() #dont update here, parent will update + else: + #no callback mode (used in supporting gui scripts) + #internally re-validate the param and update the gui + self.param.validate() + self.update() class EntryParam(InputParam): """Provide an entry box for strings and numbers.""" @@ -155,9 +159,9 @@ class Param(Element): All others get a standard entry parameter. @return gtk input class """ - if self.is_enum(): return EnumParam(*args, **kwargs) - if self.get_options(): return EnumEntryParam(*args, **kwargs) - return EntryParam(*args, **kwargs) + if self.is_enum(): return EnumParam(self, *args, **kwargs) + if self.get_options(): return EnumEntryParam(self, *args, **kwargs) + return EntryParam(self, *args, **kwargs) def get_layout(self): """ diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index aa86f7214..34fd7ec17 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -123,7 +123,7 @@ class PropsDialog(gtk.Dialog): io_param.destroy() #repopulate the params box for param in self._block.get_params(): - io_param = param.get_input(param, callback=self._update) + io_param = param.get_input(self._update) self._input_object_params.append(io_param) self._params_box.pack_start(io_param, False) #update the gui inputs diff --git a/grc/python/Param.py b/grc/python/Param.py index c64659a08..387fab548 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -154,7 +154,7 @@ class Param(_Param, _GUIParam): return dt_str def get_input(self, *args, **kwargs): - if self.get_type() in ('file_open', 'file_save'): return FileParam(*args, **kwargs) + if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs) return _GUIParam.get_input(self, *args, **kwargs) def get_color(self): diff --git a/grc/scripts/usrp2_probe b/grc/scripts/usrp2_probe index 00d4366dd..689d41ecb 100755 --- a/grc/scripts/usrp2_probe +++ b/grc/scripts/usrp2_probe @@ -32,9 +32,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay from gnuradio.grc.python.Platform import Platform platform = Platform() -from gnuradio.grc.gui.Platform import Platform -platform = Platform(platform) - flow_graph = platform.get_new_flow_graph() block = flow_graph.get_new_block('usrp2_probe') @@ -42,6 +39,12 @@ block = flow_graph.get_new_block('usrp2_probe') usrp_interface_param = block.get_param('interface') usrp_type_param = block.get_param('type') +def get_input(param): + param.validate() + input = param.get_input() + input.update() + return input + class USRP2ProbeWindow(gtk.Window): """ The main window for USRP Dignostics. @@ -69,8 +72,8 @@ class USRP2ProbeWindow(gtk.Window): #create vbox for storage vbox = gtk.VBox() frame.add(vbox) - vbox.pack_start(usrp_interface_param.get_input_object(), False) - vbox.pack_start(usrp_type_param.get_input_object(), False) + vbox.pack_start(get_input(usrp_interface_param), False) + vbox.pack_start(get_input(usrp_type_param), False) #make the tree model for holding mac addrs self.treestore = gtk.TreeStore(gobject.TYPE_STRING) self.treeview = gtk.TreeView(self.treestore) diff --git a/grc/scripts/usrp_probe b/grc/scripts/usrp_probe index 6565612c1..985d481ce 100755 --- a/grc/scripts/usrp_probe +++ b/grc/scripts/usrp_probe @@ -30,9 +30,6 @@ from gnuradio.grc.gui.Dialogs import TextDisplay from gnuradio.grc.python.Platform import Platform platform = Platform() -from gnuradio.grc.gui.Platform import Platform -platform = Platform(platform) - flow_graph = platform.get_new_flow_graph() block = flow_graph.get_new_block('usrp_probe') @@ -40,6 +37,12 @@ block = flow_graph.get_new_block('usrp_probe') usrp_which_param = block.get_param('which') usrp_dboard_param = block.get_param('dboard') +def get_input(param): + param.validate() + input = param.get_input() + input.update() + return input + class USRPProbeWindow(gtk.Window): """ The main window for USRP Dignostics. @@ -66,8 +69,8 @@ class USRPProbeWindow(gtk.Window): #create vbox for storage vbox = gtk.VBox() frame.add(vbox) - vbox.pack_start(usrp_which_param.get_input_object(), False) - vbox.pack_start(usrp_dboard_param.get_input_object(), False) + vbox.pack_start(get_input(usrp_which_param), False) + vbox.pack_start(get_input(usrp_dboard_param), False) self.probe_button = gtk.Button('Probe') self.probe_button.connect('clicked', self._probe_usrp) vbox.pack_start(self.probe_button, False) diff --git a/grc/todo.txt b/grc/todo.txt index c675859d1..b4e3af39d 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -69,7 +69,6 @@ * threads dont die on exit in probe and variable sink * align param titles in properties dialog * weird grid params misbehaving -* fix param input stuff for usrp probes ################################################## # Future -- cgit From b8f69ad7ba49aa85239f6de611ddfd040344f66b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 8 Sep 2009 23:04:38 -0700 Subject: use show signal to perform initial gui update --- grc/gui/Param.py | 14 +++++++------- grc/gui/PropsDialog.py | 34 ++++++++++++++++++++++------------ grc/python/Port.py | 2 +- grc/scripts/usrp2_probe | 1 - grc/scripts/usrp_probe | 1 - 5 files changed, 30 insertions(+), 22 deletions(-) (limited to 'grc') diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 7fabb6671..4464a57ab 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -35,9 +35,11 @@ class InputParam(gtk.HBox): self.pack_start(self.label, False) self.set_markup = lambda m: self.label.set_markup(m) self.tp = None + #connect events + self.connect('show', self._update_gui) def set_color(self, color): pass - def update(self): + def _update_gui(self, *args): """ Set the markup, color, tooltip, show/hide. """ @@ -65,12 +67,10 @@ class InputParam(gtk.HBox): #set the new value self.param.set_value(self.get_text()) #call the callback - if self._callback: self._callback() - else: - #no callback mode (used in supporting gui scripts) - #internally re-validate the param and update the gui - self.param.validate() - self.update() + if self._callback: self._callback(*args) + else: self.param.validate() + #gui update + self._update_gui() class EntryParam(InputParam): """Provide an entry box for strings and numbers.""" diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 34fd7ec17..496500416 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -81,16 +81,16 @@ class PropsDialog(gtk.Dialog): vbox.pack_start(self._params_box, False) vbox.pack_start(self._error_box, False) vbox.pack_start(self._docs_box, False) - #connect key press event + #connect events self.connect('key_press_event', self._handle_key_press) - #initial update to populate the params + self.connect('show', self._update_gui) + #show all (performs initial gui update) self.show_all() - self._update() def _params_changed(self): """ Have the params in this dialog changed? - Ex: Added, removed, type change... + Ex: Added, removed, type change, hide change... Make a hash that uniquely represents the params state. @return true if changed """ @@ -99,9 +99,20 @@ class PropsDialog(gtk.Dialog): for param in self._block.get_params(): self._hash ^= hash(param) self._hash ^= hash(param.get_type()) + self._hash ^= hash(param.get_hide()) return self._hash != old_hash - def _update(self): + def _handle_changed(self, *args): + """ + A change occured within a param: + Rewrite/validate the block and update the gui. + """ + #update for the block + self._block.rewrite() + self._block.validate() + self._update_gui() + + def _update_gui(self, *args): """ Repopulate the parameters box (if changed). Update all the input parameters. @@ -110,24 +121,23 @@ class PropsDialog(gtk.Dialog): Update the documentation block. Hide the box if there are no docs. """ - #update for the block - self._block.rewrite() - self._block.validate() #update the params box if self._params_changed(): + #hide params box before changing + self._params_box.hide_all() #empty the params box for io_param in list(self._input_object_params): - io_param.hide_all() self._params_box.remove(io_param) self._input_object_params.remove(io_param) io_param.destroy() #repopulate the params box for param in self._block.get_params(): - io_param = param.get_input(self._update) + if param.get_hide() == 'all': continue + io_param = param.get_input(self._handle_changed) self._input_object_params.append(io_param) self._params_box.pack_start(io_param, False) - #update the gui inputs - for io_param in self._input_object_params: io_param.update() + #show params box with new params + self._params_box.show_all() #update the errors box if self._block.is_valid(): self._error_box.hide() else: self._error_box.show() diff --git a/grc/python/Port.py b/grc/python/Port.py index 33426d905..6965371df 100644 --- a/grc/python/Port.py +++ b/grc/python/Port.py @@ -45,7 +45,7 @@ def _get_source_from_virtual_source_port(vsp, traversed=[]): lambda b: b.is_virtual_sink(), vsp.get_parent().get_parent().get_enabled_blocks(), ), - )[0].get_sink(vsp.get_key()) + )[0].get_sinks()[0] ), traversed + [vsp], ) except: raise Exception, 'Could not resolve source for virtual source port %s'%vsp diff --git a/grc/scripts/usrp2_probe b/grc/scripts/usrp2_probe index 689d41ecb..38c8f655c 100755 --- a/grc/scripts/usrp2_probe +++ b/grc/scripts/usrp2_probe @@ -42,7 +42,6 @@ usrp_type_param = block.get_param('type') def get_input(param): param.validate() input = param.get_input() - input.update() return input class USRP2ProbeWindow(gtk.Window): diff --git a/grc/scripts/usrp_probe b/grc/scripts/usrp_probe index 985d481ce..d2e92e753 100755 --- a/grc/scripts/usrp_probe +++ b/grc/scripts/usrp_probe @@ -40,7 +40,6 @@ usrp_dboard_param = block.get_param('dboard') def get_input(param): param.validate() input = param.get_input() - input.update() return input class USRPProbeWindow(gtk.Window): -- cgit From bced51e1fe3694e073bebf053b2c69bc5128e00b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 9 Sep 2009 21:35:58 -0700 Subject: properties dialog with ok/cancel buttons --- grc/gui/ActionHandler.py | 15 +++++++++++---- grc/gui/PropsDialog.py | 18 ++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index f12893579..656f99c37 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -240,10 +240,17 @@ class ActionHandler: ################################################## elif state == Actions.BLOCK_PARAM_MODIFY: selected_block = self.get_flow_graph().get_selected_block() - if selected_block and PropsDialog(selected_block).run(): - self.get_flow_graph().update() - self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) - self.get_page().set_saved(False) + if selected_block: + if PropsDialog(selected_block).run(): + #save the new state + self.get_flow_graph().update() + self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) + self.get_page().set_saved(False) + else: + #restore the current state + n = self.get_page().get_state_cache().get_current_state() + self.get_flow_graph().import_data(n) + self.get_flow_graph().update() ################################################## # Undo/Redo ################################################## diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 496500416..29b3c7b40 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -51,7 +51,7 @@ class PropsDialog(gtk.Dialog): LABEL_SPACING = 7 gtk.Dialog.__init__(self, title='Properties: %s'%block.get_name(), - buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE), + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT), ) self._block = block self.set_size_request(MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT) @@ -155,20 +155,14 @@ class PropsDialog(gtk.Dialog): @return false to forward the keypress """ keyname = gtk.gdk.keyval_name(event.keyval) - if keyname == 'Return': self.response(gtk.RESPONSE_OK) + if keyname == 'Return': self.response(gtk.RESPONSE_ACCEPT) return False #forward the keypress def run(self): """ - Call run(). - @return true if a change occured. + Run the dialog and get its response. + @return true if the response was accept """ - original_data = list() - for param in self._block.get_params(): - original_data.append(param.get_value()) - gtk.Dialog.run(self) + response = gtk.Dialog.run(self) self.destroy() - new_data = list() - for param in self._block.get_params(): - new_data.append(param.get_value()) - return original_data != new_data + return response == gtk.RESPONSE_ACCEPT -- cgit From 417bb0aacf320043994ac1a0a5f49b977d1a9d22 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 10 Sep 2009 14:47:53 -0700 Subject: ignore irrelevant modifiers and events pending --- grc/gui/ActionHandler.py | 2 -- grc/gui/Actions.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 656f99c37..970b731c8 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -79,8 +79,6 @@ class ActionHandler: When not in focus, gtk and the accelerators handle the the key press. @return false to let gtk handle the key action """ - #dont allow key presses to queue up - if gtk.events_pending(): return True #extract action name from this key press key_name = gtk.gdk.keyval_name(event.keyval) mod_mask = event.state diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index c3ef2711a..1d6a2afba 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -97,6 +97,7 @@ _actions_key_list = ( ) _actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list) +_all_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_name, mod_mask in _actions_key_list], 0) def get_action_name_from_key_name(key_name, mod_mask=0): """ Get the action name associated with the key name and mask. @@ -105,6 +106,7 @@ def get_action_name_from_key_name(key_name, mod_mask=0): @param mod_mask the key press mask (shift, ctrl) 0 for none @return the action name or blank string """ + mod_mask &= _all_mods_mask #ignore irrelevant modifiers key_name_mod_mask = (key_name, mod_mask) if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask] return '' -- cgit From ab55c4a6e5f9a21ea743b78ea5a8206cf3d4ffe6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 10 Sep 2009 16:17:25 -0700 Subject: use the keymap's translate_keyboard_state, use the key value rather than name --- grc/gui/ActionHandler.py | 7 ++-- grc/gui/Actions.py | 83 ++++++++++++++++++++++++------------------------ grc/todo.txt | 2 ++ 3 files changed, 48 insertions(+), 44 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 970b731c8..0d39ea5fd 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -79,10 +79,11 @@ class ActionHandler: When not in focus, gtk and the accelerators handle the the key press. @return false to let gtk handle the key action """ + keyval, egroup, level, consumed = \ + gtk.gdk.keymap_get_default().translate_keyboard_state( + event.hardware_keycode, event.state, event.group) #extract action name from this key press - key_name = gtk.gdk.keyval_name(event.keyval) - mod_mask = event.state - action_name = Actions.get_action_name_from_key_name(key_name, mod_mask) + action_name = Actions.get_action_name_from_key_press(keyval, event.state & ~consumed) #handle the action if flow graph is in focus if action_name and self.get_focus_flag(): self.handle_states(action_name) diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 1d6a2afba..d3d63f293 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -62,54 +62,55 @@ TYPES_WINDOW_DISPLAY = 'types window display' ###################################################################################################### # Action Key Map ###################################################################################################### +NO_MODS_MASK = 0 _actions_key_list = ( - #action name, key name, mod mask - (FLOW_GRAPH_NEW, 'n', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_OPEN, 'o', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE, 's', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE_AS, 's', gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), - (FLOW_GRAPH_CLOSE, 'w', gtk.gdk.CONTROL_MASK), - (APPLICATION_QUIT, 'q', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_UNDO, 'z', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_REDO, 'y', gtk.gdk.CONTROL_MASK), - (ELEMENT_DELETE, 'Delete', 0), - (BLOCK_ROTATE_CCW, 'Left', 0), - (BLOCK_ROTATE_CW, 'Right', 0), - (BLOCK_DEC_TYPE, 'Up', 0), - (BLOCK_INC_TYPE, 'Down', 0), - (BLOCK_PARAM_MODIFY, 'Return', 0), - (BLOCK_ENABLE, 'e', 0), - (BLOCK_DISABLE, 'd', 0), - (BLOCK_CUT, 'x', gtk.gdk.CONTROL_MASK), - (BLOCK_COPY, 'c', gtk.gdk.CONTROL_MASK), - (BLOCK_PASTE, 'v', gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_GEN, 'F5', 0), - (FLOW_GRAPH_EXEC, 'F6', 0), - (FLOW_GRAPH_KILL, 'F7', 0), - (FLOW_GRAPH_SCREEN_CAPTURE, 'Print', 0), - (HELP_WINDOW_DISPLAY, 'F1', 0), + #action name, key value, mod mask + (FLOW_GRAPH_NEW, gtk.keysyms.n, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_OPEN, gtk.keysyms.o, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_SAVE, gtk.keysyms.s, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_SAVE_AS, gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), + (FLOW_GRAPH_CLOSE, gtk.keysyms.w, gtk.gdk.CONTROL_MASK), + (APPLICATION_QUIT, gtk.keysyms.q, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_UNDO, gtk.keysyms.z, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_REDO, gtk.keysyms.y, gtk.gdk.CONTROL_MASK), + (ELEMENT_DELETE, gtk.keysyms.Delete, NO_MODS_MASK), + (BLOCK_ROTATE_CCW, gtk.keysyms.Left, NO_MODS_MASK), + (BLOCK_ROTATE_CW, gtk.keysyms.Right, NO_MODS_MASK), + (BLOCK_DEC_TYPE, gtk.keysyms.Up, NO_MODS_MASK), + (BLOCK_INC_TYPE, gtk.keysyms.Down, NO_MODS_MASK), + (BLOCK_PARAM_MODIFY, gtk.keysyms.Return, NO_MODS_MASK), + (BLOCK_ENABLE, gtk.keysyms.e, NO_MODS_MASK), + (BLOCK_DISABLE, gtk.keysyms.d, NO_MODS_MASK), + (BLOCK_CUT, gtk.keysyms.x, gtk.gdk.CONTROL_MASK), + (BLOCK_COPY, gtk.keysyms.c, gtk.gdk.CONTROL_MASK), + (BLOCK_PASTE, gtk.keysyms.v, gtk.gdk.CONTROL_MASK), + (FLOW_GRAPH_GEN, gtk.keysyms.F5, NO_MODS_MASK), + (FLOW_GRAPH_EXEC, gtk.keysyms.F6, NO_MODS_MASK), + (FLOW_GRAPH_KILL, gtk.keysyms.F7, NO_MODS_MASK), + (FLOW_GRAPH_SCREEN_CAPTURE, gtk.keysyms.Print, NO_MODS_MASK), + (HELP_WINDOW_DISPLAY, gtk.keysyms.F1, NO_MODS_MASK), #the following have no associated gtk.Action - (PORT_CONTROLLER_INC, 'equal', 0), - (PORT_CONTROLLER_INC, 'plus', 0), - (PORT_CONTROLLER_INC, 'KP_Add', 0), - (PORT_CONTROLLER_DEC, 'minus', 0), - (PORT_CONTROLLER_DEC, 'KP_Subtract', 0), + (PORT_CONTROLLER_INC, gtk.keysyms.equal, NO_MODS_MASK), + (PORT_CONTROLLER_INC, gtk.keysyms.plus, NO_MODS_MASK), + (PORT_CONTROLLER_INC, gtk.keysyms.KP_Add, NO_MODS_MASK), + (PORT_CONTROLLER_DEC, gtk.keysyms.minus, NO_MODS_MASK), + (PORT_CONTROLLER_DEC, gtk.keysyms.KP_Subtract, NO_MODS_MASK), ) -_actions_key_dict = dict(((key_name, mod_mask), action_name) for action_name, key_name, mod_mask in _actions_key_list) -_all_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_name, mod_mask in _actions_key_list], 0) -def get_action_name_from_key_name(key_name, mod_mask=0): +_actions_key_dict = dict(((key_val, mod_mask), action_name) for action_name, key_val, mod_mask in _actions_key_list) +_all_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_val, mod_mask in _actions_key_list], NO_MODS_MASK) +def get_action_name_from_key_press(key_val, mod_mask=NO_MODS_MASK): """ - Get the action name associated with the key name and mask. - Both keyname and mask have to match. - @param key_name the name of the key + Get the action name associated with the key value and mask. + Both the key value and the mask have to match. + @param key_val the value of the key @param mod_mask the key press mask (shift, ctrl) 0 for none @return the action name or blank string """ mod_mask &= _all_mods_mask #ignore irrelevant modifiers - key_name_mod_mask = (key_name, mod_mask) - if key_name_mod_mask in _actions_key_dict: return _actions_key_dict[key_name_mod_mask] - return '' + key_val_mod_mask = (key_val, mod_mask) + try: return _actions_key_dict[key_val_mod_mask] + except KeyError: return '' ###################################################################################################### # Actions @@ -162,10 +163,10 @@ def get_accel_group(): return _accel_group #set the accelerator group, and accelerator path #register the key name and mod mask with the accelerator path -for action_name, key_name, mod_mask in _actions_key_list: +for action_name, key_val, mod_mask in _actions_key_list: try: accel_path = '
/'+action_name get_action_from_name(action_name).set_accel_group(get_accel_group()) get_action_from_name(action_name).set_accel_path(accel_path) - gtk.accel_map_add_entry(accel_path, gtk.gdk.keyval_from_name(key_name), mod_mask) + gtk.accel_map_add_entry(accel_path, key_val, mod_mask) except KeyError: pass #no action was created for this action name diff --git a/grc/todo.txt b/grc/todo.txt index b4e3af39d..7fa68e523 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -69,6 +69,8 @@ * threads dont die on exit in probe and variable sink * align param titles in properties dialog * weird grid params misbehaving +* the block's import data does not handle variable params + * call rewrite after load, if new params appear, try load again... ################################################## # Future -- cgit From 14ae3c5141e3d39b89a4aac19681ec8ac7cd05ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 10 Sep 2009 17:38:53 -0700 Subject: rename variable, use keysyms in props dialog --- grc/gui/Actions.py | 4 ++-- grc/gui/PropsDialog.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'grc') diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index d3d63f293..cacee22ce 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -98,7 +98,7 @@ _actions_key_list = ( ) _actions_key_dict = dict(((key_val, mod_mask), action_name) for action_name, key_val, mod_mask in _actions_key_list) -_all_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_val, mod_mask in _actions_key_list], NO_MODS_MASK) +_used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_val, mod_mask in _actions_key_list], NO_MODS_MASK) def get_action_name_from_key_press(key_val, mod_mask=NO_MODS_MASK): """ Get the action name associated with the key value and mask. @@ -107,7 +107,7 @@ def get_action_name_from_key_press(key_val, mod_mask=NO_MODS_MASK): @param mod_mask the key press mask (shift, ctrl) 0 for none @return the action name or blank string """ - mod_mask &= _all_mods_mask #ignore irrelevant modifiers + mod_mask &= _used_mods_mask #ignore irrelevant modifiers key_val_mod_mask = (key_val, mod_mask) try: return _actions_key_dict[key_val_mod_mask] except KeyError: return '' diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index 29b3c7b40..b295ba412 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -154,8 +154,9 @@ class PropsDialog(gtk.Dialog): Call the ok response when enter is pressed. @return false to forward the keypress """ - keyname = gtk.gdk.keyval_name(event.keyval) - if keyname == 'Return': self.response(gtk.RESPONSE_ACCEPT) + if event.keyval == gtk.keysyms.Return: + self.response(gtk.RESPONSE_ACCEPT) + return True #handled here return False #forward the keypress def run(self): -- cgit From 9dd47b6732c9d6a94fc0e15717d7332fc6c8270f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Sep 2009 00:04:58 -0700 Subject: Move key press extraction logic into actions module. Replaced xml encode with gtk escape text. Added templates for category and docs tool tips. Other various code tweaks in gui modules. --- grc/gui/ActionHandler.py | 20 ++++++++------------ grc/gui/Actions.py | 35 +++++++++++++++++++---------------- grc/gui/BlockTreeWindow.py | 13 +++++++++++-- grc/gui/Utils.py | 20 ++------------------ 4 files changed, 40 insertions(+), 48 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 0d39ea5fd..901619e69 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -79,16 +79,11 @@ class ActionHandler: When not in focus, gtk and the accelerators handle the the key press. @return false to let gtk handle the key action """ - keyval, egroup, level, consumed = \ - gtk.gdk.keymap_get_default().translate_keyboard_state( - event.hardware_keycode, event.state, event.group) - #extract action name from this key press - action_name = Actions.get_action_name_from_key_press(keyval, event.state & ~consumed) - #handle the action if flow graph is in focus - if action_name and self.get_focus_flag(): - self.handle_states(action_name) - return True #handled by this method - return False #let gtk handle the key press + try: assert self.get_focus_flag() + except AssertionError: return False + try: self.handle_states(Actions.get_action_name_from_key_press(event)) + except KeyError: return False + return True #handled by this method def _quit(self, window, event): """ @@ -100,13 +95,14 @@ class ActionHandler: self.handle_states(Actions.APPLICATION_QUIT) return True - def _handle_actions(self, event): + def _handle_actions(self, action): """ Handle all of the activate signals from the gtk actions. The action signals derive from clicking on a toolbar or menu bar button. Forward the action to the state handler. """ - self.handle_states(event.get_name()) + self.handle_states(action.get_name()) + return True def handle_states(self, state=''): """ diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index cacee22ce..531888ac1 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -97,20 +97,23 @@ _actions_key_list = ( (PORT_CONTROLLER_DEC, gtk.keysyms.KP_Subtract, NO_MODS_MASK), ) -_actions_key_dict = dict(((key_val, mod_mask), action_name) for action_name, key_val, mod_mask in _actions_key_list) -_used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, key_val, mod_mask in _actions_key_list], NO_MODS_MASK) -def get_action_name_from_key_press(key_val, mod_mask=NO_MODS_MASK): +_actions_key_dict = dict(((keyval, mod_mask), action_name) for action_name, keyval, mod_mask in _actions_key_list) +_used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, keyval, mod_mask in _actions_key_list], NO_MODS_MASK) +_keymap = gtk.gdk.keymap_get_default() +def get_action_name_from_key_press(event): """ - Get the action name associated with the key value and mask. - Both the key value and the mask have to match. - @param key_val the value of the key - @param mod_mask the key press mask (shift, ctrl) 0 for none + Get the action name associated with the key press event. + Both the key value and the mask must have a match. + @param event a gtk key press event @return the action name or blank string """ - mod_mask &= _used_mods_mask #ignore irrelevant modifiers - key_val_mod_mask = (key_val, mod_mask) - try: return _actions_key_dict[key_val_mod_mask] - except KeyError: return '' + #extract the key value and the consumed modifiers + keyval, egroup, level, consumed = _keymap.translate_keyboard_state( + event.hardware_keycode, event.state, event.group) + #get the modifier mask and ignore irrelevant modifiers + mod_mask = event.state & ~consumed & _used_mods_mask + try: return _actions_key_dict[(keyval, mod_mask)] + except KeyError: raise KeyError, 'Keypress: "%s, %s" does not have an associated action'%(gtk.gdk.keyval_name(keyval), mod_mask) ###################################################################################################### # Actions @@ -143,7 +146,7 @@ _actions_list = ( ) def get_all_actions(): return _actions_list -_actions_dict = dict((action.get_name(), action) for action in _actions_list) +_actions_dict = dict((action.get_name(), action) for action in get_all_actions()) def get_action_from_name(action_name): """ Retrieve the action from the action list. @@ -152,8 +155,8 @@ def get_action_from_name(action_name): @throw KeyError bad action name @return a gtk action object """ - if action_name in _actions_dict: return _actions_dict[action_name] - raise KeyError('Action Name: "%s" does not exist'%action_name) + try: return _actions_dict[action_name] + except KeyError: raise KeyError, 'Action Name: "%s" does not exist'%action_name ###################################################################################################### # Accelerators @@ -163,10 +166,10 @@ def get_accel_group(): return _accel_group #set the accelerator group, and accelerator path #register the key name and mod mask with the accelerator path -for action_name, key_val, mod_mask in _actions_key_list: +for action_name, keyval, mod_mask in _actions_key_list: try: accel_path = '
/'+action_name get_action_from_name(action_name).set_accel_group(get_accel_group()) get_action_from_name(action_name).set_accel_path(accel_path) - gtk.accel_map_add_entry(accel_path, key_val, mod_mask) + gtk.accel_map_add_entry(accel_path, keyval, mod_mask) except KeyError: pass #no action was created for this action name diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 379c4a6a2..5c5d21b64 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -28,6 +28,15 @@ NAME_INDEX = 0 KEY_INDEX = 1 DOC_INDEX = 2 +DOC_MARKUP_TMPL="""\ +#if $doc +$encode($doc)#slurp +#else +undocumented#slurp +#end if""" + +CAT_MARKUP_TMPL="""Category: $cat""" + class BlockTreeWindow(gtk.VBox): """The block selection panel.""" @@ -97,14 +106,14 @@ class BlockTreeWindow(gtk.VBox): iter = self.treestore.insert_before(self._categories[sub_category[:-1]], None) self.treestore.set_value(iter, NAME_INDEX, '[ %s ]'%cat_name) self.treestore.set_value(iter, KEY_INDEX, '') - self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode('Category: %s'%cat_name)) + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(CAT_MARKUP_TMPL, cat=cat_name)) self._categories[sub_category] = iter #add block if block is None: return iter = self.treestore.insert_before(self._categories[category], None) self.treestore.set_value(iter, NAME_INDEX, block.get_name()) self.treestore.set_value(iter, KEY_INDEX, block.get_key()) - self.treestore.set_value(iter, DOC_INDEX, Utils.xml_encode(block.get_doc() or 'undocumented')) + self.treestore.set_value(iter, DOC_INDEX, Utils.parse_template(DOC_MARKUP_TMPL, doc=block.get_doc())) ############################################################ ## Helper Methods diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index ee6dc6cdc..83036a4b8 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Constants import POSSIBLE_ROTATIONS from Cheetah.Template import Template +import gobject def get_rotated_coordinate(coor, rotation): """ @@ -54,23 +55,6 @@ def get_angle_from_coordinates((x1,y1), (x2,y2)): if y2 > y1: return 270 else: return 90 -def xml_encode(string): - """ - Encode a string into an xml safe string by replacing special characters. - Needed for gtk pango markup in labels. - @param string the input string - @return output string with safe characters - """ - string = str(string) - for char, safe in ( - ('&', '&'), - ('<', '<'), - ('>', '>'), - ('"', '"'), - ("'", '''), - ): string = string.replace(char, safe) - return string - def parse_template(tmpl_str, **kwargs): """ Parse the template string with the given args. @@ -78,5 +62,5 @@ def parse_template(tmpl_str, **kwargs): @param tmpl_str the template as a string @return a string of the parsed template """ - kwargs['encode'] = xml_encode + kwargs['encode'] = gobject.markup_escape_text return str(Template(tmpl_str, kwargs)) -- cgit From 91a83e6f1fda6483bfd4b449a1ef7903a00af0ab Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Sep 2009 02:14:27 -0700 Subject: Reworked actions api and actions objects: Created standardized Action object for all gui actions. Actions module constants are actual Action objects (not strings). Keypresses, labels, tooltips, stock icons, etc all associate in the Action constructor. Usage of the action's signaling call () eliminated the need for a reference to handle_states. --- grc/gui/ActionHandler.py | 151 +++++++++----------- grc/gui/Actions.py | 359 +++++++++++++++++++++++++++++------------------ grc/gui/Bars.py | 12 +- grc/gui/FlowGraph.py | 12 +- grc/gui/MainWindow.py | 20 +-- grc/gui/NotebookPage.py | 5 +- grc/gui/StateCache.py | 6 +- 7 files changed, 319 insertions(+), 246 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 901619e69..59e535bd4 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -52,10 +52,10 @@ class ActionHandler: @param platform platform module """ self.clipboard = None - for action in Actions.get_all_actions(): action.connect('activate', self._handle_actions) + for action in Actions.get_all_actions(): action.connect('activate', self._handle_action) #setup the main window - self.main_window = MainWindow(self.handle_states, platform) - self.main_window.connect('delete_event', self._quit) + self.main_window = MainWindow(platform) + self.main_window.connect('delete-event', self._quit) self.main_window.connect('key-press-event', self._handle_key_press) self.get_page = self.main_window.get_page self.get_flow_graph = self.main_window.get_flow_graph @@ -65,7 +65,7 @@ class ActionHandler: Messages.send_init(platform) #initialize self.init_file_paths = file_paths - self.handle_states(Actions.APPLICATION_INITIALIZE) + Actions.APPLICATION_INITIALIZE() #enter the mainloop gtk.main() @@ -81,7 +81,7 @@ class ActionHandler: """ try: assert self.get_focus_flag() except AssertionError: return False - try: self.handle_states(Actions.get_action_name_from_key_press(event)) + try: Actions.get_action_from_key_press(event)() except KeyError: return False return True #handled by this method @@ -92,42 +92,24 @@ class ActionHandler: This method in turns calls the state handler to quit. @return true """ - self.handle_states(Actions.APPLICATION_QUIT) + Actions.APPLICATION_QUIT() return True - def _handle_actions(self, action): - """ - Handle all of the activate signals from the gtk actions. - The action signals derive from clicking on a toolbar or menu bar button. - Forward the action to the state handler. - """ - self.handle_states(action.get_name()) - return True - - def handle_states(self, state=''): - """ - Handle the state changes in the GUI. - Handle all of the state changes that arise from the action handler or other gui and - inputs in the application. The state passed to the handle_states method is a string descriping - the change. A series of if/elif statements handle the state by greying out action buttons, causing - changes in the flow graph, saving/opening files... The handle_states method is passed to the - contructors of many of the classes used in this application enabling them to report any state change. - @param state a string describing the state change - """ - #print state + def _handle_action(self, action): + #print action ################################################## # Initalize/Quit ################################################## - if state == Actions.APPLICATION_INITIALIZE: + if action == Actions.APPLICATION_INITIALIZE: for action in Actions.get_all_actions(): action.set_sensitive(False) #set all actions disabled - # enable a select few actions + #enable a select few actions for action in ( Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW, Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY, Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, - ): Actions.get_action_from_name(action).set_sensitive(True) + ): action.set_sensitive(True) if not self.init_file_paths: self.init_file_paths = Preferences.files_open() if not self.init_file_paths: self.init_file_paths = [''] @@ -136,26 +118,26 @@ class ActionHandler: if Preferences.file_open() in self.init_file_paths: self.main_window.new_page(Preferences.file_open(), show=True) if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists - elif state == Actions.APPLICATION_QUIT: + elif action == Actions.APPLICATION_QUIT: if self.main_window.close_pages(): gtk.main_quit() exit(0) ################################################## # Selections ################################################## - elif state == Actions.ELEMENT_SELECT: + elif action == Actions.ELEMENT_SELECT: pass #do nothing, update routines below - elif state == Actions.NOTHING_SELECT: + elif action == Actions.NOTHING_SELECT: self.get_flow_graph().unselect() ################################################## # Enable/Disable ################################################## - elif state == Actions.BLOCK_ENABLE: + elif action == Actions.BLOCK_ENABLE: if self.get_flow_graph().enable_selected(True): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_DISABLE: + elif action == Actions.BLOCK_DISABLE: if self.get_flow_graph().enable_selected(False): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) @@ -163,12 +145,12 @@ class ActionHandler: ################################################## # Cut/Copy/Paste ################################################## - elif state == Actions.BLOCK_CUT: - self.handle_states(Actions.BLOCK_COPY) - self.handle_states(Actions.ELEMENT_DELETE) - elif state == Actions.BLOCK_COPY: + elif action == Actions.BLOCK_CUT: + Actions.BLOCK_COPY() + Actions.ELEMENT_DELETE() + elif action == Actions.BLOCK_COPY: self.clipboard = self.get_flow_graph().copy_to_clipboard() - elif state == Actions.BLOCK_PASTE: + elif action == Actions.BLOCK_PASTE: if self.clipboard: self.get_flow_graph().paste_from_clipboard(self.clipboard) self.get_flow_graph().update() @@ -177,46 +159,46 @@ class ActionHandler: ################################################## # Move/Rotate/Delete/Create ################################################## - elif state == Actions.BLOCK_MOVE: + elif action == Actions.BLOCK_MOVE: self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_CCW: + elif action == Actions.BLOCK_ROTATE_CCW: if self.get_flow_graph().rotate_selected(90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_ROTATE_CW: + elif action == Actions.BLOCK_ROTATE_CW: if self.get_flow_graph().rotate_selected(-90): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.ELEMENT_DELETE: + elif action == Actions.ELEMENT_DELETE: if self.get_flow_graph().remove_selected(): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) - self.handle_states(Actions.NOTHING_SELECT) + Actions.NOTHING_SELECT() self.get_page().set_saved(False) - elif state == Actions.ELEMENT_CREATE: + elif action == Actions.ELEMENT_CREATE: self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) - self.handle_states(Actions.NOTHING_SELECT) + Actions.NOTHING_SELECT() self.get_page().set_saved(False) - elif state == Actions.BLOCK_INC_TYPE: + elif action == Actions.BLOCK_INC_TYPE: if self.get_flow_graph().type_controller_modify_selected(1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.BLOCK_DEC_TYPE: + elif action == Actions.BLOCK_DEC_TYPE: if self.get_flow_graph().type_controller_modify_selected(-1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.PORT_CONTROLLER_INC: + elif action == Actions.PORT_CONTROLLER_INC: if self.get_flow_graph().port_controller_modify_selected(1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) self.get_page().set_saved(False) - elif state == Actions.PORT_CONTROLLER_DEC: + elif action == Actions.PORT_CONTROLLER_DEC: if self.get_flow_graph().port_controller_modify_selected(-1): self.get_flow_graph().update() self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data()) @@ -224,16 +206,16 @@ class ActionHandler: ################################################## # Window stuff ################################################## - elif state == Actions.ABOUT_WINDOW_DISPLAY: + elif action == Actions.ABOUT_WINDOW_DISPLAY: Dialogs.AboutDialog(self.get_flow_graph().get_parent()) - elif state == Actions.HELP_WINDOW_DISPLAY: + elif action == Actions.HELP_WINDOW_DISPLAY: Dialogs.HelpDialog() - elif state == Actions.TYPES_WINDOW_DISPLAY: + elif action == Actions.TYPES_WINDOW_DISPLAY: Dialogs.TypesDialog(self.get_flow_graph().get_parent()) ################################################## # Param Modifications ################################################## - elif state == Actions.BLOCK_PARAM_MODIFY: + elif action == Actions.BLOCK_PARAM_MODIFY: selected_block = self.get_flow_graph().get_selected_block() if selected_block: if PropsDialog(selected_block).run(): @@ -249,14 +231,14 @@ class ActionHandler: ################################################## # Undo/Redo ################################################## - elif state == Actions.FLOW_GRAPH_UNDO: + elif action == Actions.FLOW_GRAPH_UNDO: n = self.get_page().get_state_cache().get_prev_state() if n: self.get_flow_graph().unselect() self.get_flow_graph().import_data(n) self.get_flow_graph().update() self.get_page().set_saved(False) - elif state == Actions.FLOW_GRAPH_REDO: + elif action == Actions.FLOW_GRAPH_REDO: n = self.get_page().get_state_cache().get_next_state() if n: self.get_flow_graph().unselect() @@ -266,19 +248,19 @@ class ActionHandler: ################################################## # New/Open/Save/Close ################################################## - elif state == Actions.FLOW_GRAPH_NEW: + elif action == Actions.FLOW_GRAPH_NEW: self.main_window.new_page() - elif state == Actions.FLOW_GRAPH_OPEN: + elif action == Actions.FLOW_GRAPH_OPEN: file_paths = OpenFlowGraphFileDialog(self.get_page().get_file_path()).run() if file_paths: #open a new page for each file, show only the first for i,file_path in enumerate(file_paths): self.main_window.new_page(file_path, show=(i==0)) - elif state == Actions.FLOW_GRAPH_CLOSE: + elif action == Actions.FLOW_GRAPH_CLOSE: self.main_window.close_page() - elif state == Actions.FLOW_GRAPH_SAVE: + elif action == Actions.FLOW_GRAPH_SAVE: #read-only or undefined file path, do save-as if self.get_page().get_read_only() or not self.get_page().get_file_path(): - self.handle_states(Actions.FLOW_GRAPH_SAVE_AS) + Actions.FLOW_GRAPH_SAVE_AS() #otherwise try to save else: try: @@ -287,12 +269,12 @@ class ActionHandler: except IOError: Messages.send_fail_save(self.get_page().get_file_path()) self.get_page().set_saved(False) - elif state == Actions.FLOW_GRAPH_SAVE_AS: + elif action == Actions.FLOW_GRAPH_SAVE_AS: file_path = SaveFlowGraphFileDialog(self.get_page().get_file_path()).run() if file_path is not None: self.get_page().set_file_path(file_path) - self.handle_states(Actions.FLOW_GRAPH_SAVE) - elif state == Actions.FLOW_GRAPH_SCREEN_CAPTURE: + Actions.FLOW_GRAPH_SAVE() + elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE: file_path = SaveImageFileDialog(self.get_page().get_file_path()).run() if file_path is not None: pixbuf = self.get_flow_graph().get_drawing_area().get_pixbuf() @@ -300,10 +282,10 @@ class ActionHandler: ################################################## # Gen/Exec/Stop ################################################## - elif state == Actions.FLOW_GRAPH_GEN: + elif action == Actions.FLOW_GRAPH_GEN: if not self.get_page().get_pid(): if not self.get_page().get_saved() or not self.get_page().get_file_path(): - self.handle_states(Actions.FLOW_GRAPH_SAVE) #only save if file path missing or not saved + Actions.FLOW_GRAPH_SAVE() #only save if file path missing or not saved if self.get_page().get_saved() and self.get_page().get_file_path(): generator = self.get_page().get_generator() try: @@ -311,37 +293,37 @@ class ActionHandler: generator.write() except Exception,e: Messages.send_fail_gen(e) else: self.generator = None - elif state == Actions.FLOW_GRAPH_EXEC: + elif action == Actions.FLOW_GRAPH_EXEC: if not self.get_page().get_pid(): - self.handle_states(Actions.FLOW_GRAPH_GEN) + Actions.FLOW_GRAPH_GEN() if self.get_page().get_saved() and self.get_page().get_file_path(): ExecFlowGraphThread(self) - elif state == Actions.FLOW_GRAPH_KILL: + elif action == Actions.FLOW_GRAPH_KILL: if self.get_page().get_pid(): try: os.kill(self.get_page().get_pid(), signal.SIGKILL) except: print "could not kill pid: %s"%self.get_page().get_pid() - elif state == '': #pass and run the global actions + elif action == Actions.PAGE_CHANGE: #pass and run the global actions pass - else: print '!!! State "%s" not handled !!!'%state + else: print '!!! Action "%s" not handled !!!'%action ################################################## # Global Actions for all States ################################################## #update general buttons - Actions.get_action_from_name(Actions.ELEMENT_DELETE).set_sensitive(bool(self.get_flow_graph().get_selected_elements())) - Actions.get_action_from_name(Actions.BLOCK_PARAM_MODIFY).set_sensitive(bool(self.get_flow_graph().get_selected_block())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_CCW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_ROTATE_CW).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements())) + Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block())) + Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_ROTATE_CW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) #update cut/copy/paste - Actions.get_action_from_name(Actions.BLOCK_CUT).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_COPY).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_PASTE).set_sensitive(bool(self.clipboard)) + Actions.BLOCK_CUT.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_COPY.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard)) #update enable/disable - Actions.get_action_from_name(Actions.BLOCK_ENABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) - Actions.get_action_from_name(Actions.BLOCK_DISABLE).set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_ENABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) + Actions.BLOCK_DISABLE.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) #set the exec and stop buttons self.update_exec_stop() #saved status - Actions.get_action_from_name(Actions.FLOW_GRAPH_SAVE).set_sensitive(not self.get_page().get_saved()) + Actions.FLOW_GRAPH_SAVE.set_sensitive(not self.get_page().get_saved()) self.main_window.update() try: #set the size of the flow graph area (if changed) new_size = self.get_flow_graph().get_option('window_size') @@ -351,6 +333,7 @@ class ActionHandler: #draw the flow graph self.get_flow_graph().update_selected() self.get_flow_graph().queue_draw() + return True #action was handled def update_exec_stop(self): """ @@ -358,9 +341,9 @@ class ActionHandler: Lock and unlock the mutex for race conditions with exec flow graph threads. """ sensitive = self.get_flow_graph().is_valid() and not self.get_page().get_pid() - Actions.get_action_from_name(Actions.FLOW_GRAPH_GEN).set_sensitive(sensitive) - Actions.get_action_from_name(Actions.FLOW_GRAPH_EXEC).set_sensitive(sensitive) - Actions.get_action_from_name(Actions.FLOW_GRAPH_KILL).set_sensitive(self.get_page().get_pid() != None) + Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive) + Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive) + Actions.FLOW_GRAPH_KILL.set_sensitive(self.get_page().get_pid() != None) class ExecFlowGraphThread(Thread): """Execute the flow graph as a new process and wait on it to finish.""" diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 531888ac1..90017987f 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -21,155 +21,248 @@ import pygtk pygtk.require('2.0') import gtk -###################################################################################################### -# Action Names -###################################################################################################### -APPLICATION_INITIALIZE = 'app init' -APPLICATION_QUIT = 'app quit' -PARAM_MODIFY = 'param modify' -BLOCK_MOVE = 'block move' -BLOCK_ROTATE_CCW = 'block rotate ccw' -BLOCK_ROTATE_CW = 'block rotate cw' -BLOCK_PARAM_MODIFY = 'block param modify' -BLOCK_INC_TYPE = 'block increment type' -BLOCK_DEC_TYPE = 'block decrement type' -BLOCK_ENABLE = 'block enable' -BLOCK_DISABLE = 'block disable' -BLOCK_CUT = 'block cut' -BLOCK_COPY = 'block copy' -BLOCK_PASTE = 'block paste' -PORT_CONTROLLER_INC = 'port controller increment' -PORT_CONTROLLER_DEC = 'port controller decrement' -ELEMENT_CREATE = 'element create' -ELEMENT_DELETE = 'element delete' -ELEMENT_SELECT = 'element select' -NOTHING_SELECT = 'nothing select' -FLOW_GRAPH_OPEN = 'flow graph open' -FLOW_GRAPH_UNDO = 'flow graph undo' -FLOW_GRAPH_REDO = 'flow graph redo' -FLOW_GRAPH_SAVE = 'flow graph save' -FLOW_GRAPH_SAVE_AS = 'flow graph save as' -FLOW_GRAPH_CLOSE = 'flow graph close' -FLOW_GRAPH_NEW = 'flow graph new' -FLOW_GRAPH_GEN = 'flow graph gen' -FLOW_GRAPH_EXEC = 'flow graph exec' -FLOW_GRAPH_KILL = 'flow graph kill' -FLOW_GRAPH_SCREEN_CAPTURE = 'flow graph screen capture' -ABOUT_WINDOW_DISPLAY = 'about window display' -HELP_WINDOW_DISPLAY = 'help window display' -TYPES_WINDOW_DISPLAY = 'types window display' - -###################################################################################################### -# Action Key Map -###################################################################################################### NO_MODS_MASK = 0 -_actions_key_list = ( - #action name, key value, mod mask - (FLOW_GRAPH_NEW, gtk.keysyms.n, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_OPEN, gtk.keysyms.o, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE, gtk.keysyms.s, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_SAVE_AS, gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), - (FLOW_GRAPH_CLOSE, gtk.keysyms.w, gtk.gdk.CONTROL_MASK), - (APPLICATION_QUIT, gtk.keysyms.q, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_UNDO, gtk.keysyms.z, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_REDO, gtk.keysyms.y, gtk.gdk.CONTROL_MASK), - (ELEMENT_DELETE, gtk.keysyms.Delete, NO_MODS_MASK), - (BLOCK_ROTATE_CCW, gtk.keysyms.Left, NO_MODS_MASK), - (BLOCK_ROTATE_CW, gtk.keysyms.Right, NO_MODS_MASK), - (BLOCK_DEC_TYPE, gtk.keysyms.Up, NO_MODS_MASK), - (BLOCK_INC_TYPE, gtk.keysyms.Down, NO_MODS_MASK), - (BLOCK_PARAM_MODIFY, gtk.keysyms.Return, NO_MODS_MASK), - (BLOCK_ENABLE, gtk.keysyms.e, NO_MODS_MASK), - (BLOCK_DISABLE, gtk.keysyms.d, NO_MODS_MASK), - (BLOCK_CUT, gtk.keysyms.x, gtk.gdk.CONTROL_MASK), - (BLOCK_COPY, gtk.keysyms.c, gtk.gdk.CONTROL_MASK), - (BLOCK_PASTE, gtk.keysyms.v, gtk.gdk.CONTROL_MASK), - (FLOW_GRAPH_GEN, gtk.keysyms.F5, NO_MODS_MASK), - (FLOW_GRAPH_EXEC, gtk.keysyms.F6, NO_MODS_MASK), - (FLOW_GRAPH_KILL, gtk.keysyms.F7, NO_MODS_MASK), - (FLOW_GRAPH_SCREEN_CAPTURE, gtk.keysyms.Print, NO_MODS_MASK), - (HELP_WINDOW_DISPLAY, gtk.keysyms.F1, NO_MODS_MASK), - #the following have no associated gtk.Action - (PORT_CONTROLLER_INC, gtk.keysyms.equal, NO_MODS_MASK), - (PORT_CONTROLLER_INC, gtk.keysyms.plus, NO_MODS_MASK), - (PORT_CONTROLLER_INC, gtk.keysyms.KP_Add, NO_MODS_MASK), - (PORT_CONTROLLER_DEC, gtk.keysyms.minus, NO_MODS_MASK), - (PORT_CONTROLLER_DEC, gtk.keysyms.KP_Subtract, NO_MODS_MASK), -) -_actions_key_dict = dict(((keyval, mod_mask), action_name) for action_name, keyval, mod_mask in _actions_key_list) -_used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for action_name, keyval, mod_mask in _actions_key_list], NO_MODS_MASK) +######################################################################## +# Actions API +######################################################################## +_actions_keypress_dict = dict() _keymap = gtk.gdk.keymap_get_default() -def get_action_name_from_key_press(event): +_used_mods_mask = NO_MODS_MASK +def get_action_from_key_press(event): """ - Get the action name associated with the key press event. + Get the action associated with the key press event. Both the key value and the mask must have a match. @param event a gtk key press event - @return the action name or blank string + @throws a key error when no action matches + @return the action object """ + _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) #extract the key value and the consumed modifiers keyval, egroup, level, consumed = _keymap.translate_keyboard_state( event.hardware_keycode, event.state, event.group) #get the modifier mask and ignore irrelevant modifiers mod_mask = event.state & ~consumed & _used_mods_mask - try: return _actions_key_dict[(keyval, mod_mask)] + try: return _actions_keypress_dict[(keyval, mod_mask)] except KeyError: raise KeyError, 'Keypress: "%s, %s" does not have an associated action'%(gtk.gdk.keyval_name(keyval), mod_mask) -###################################################################################################### -# Actions -###################################################################################################### -_actions_list = ( - gtk.Action(FLOW_GRAPH_NEW, '_New', 'Create a new flow graph', gtk.STOCK_NEW), - gtk.Action(FLOW_GRAPH_OPEN, '_Open', 'Open an existing flow graph', gtk.STOCK_OPEN), - gtk.Action(FLOW_GRAPH_SAVE, '_Save', 'Save the current flow graph', gtk.STOCK_SAVE), - gtk.Action(FLOW_GRAPH_SAVE_AS, 'Save _As', 'Save the current flow graph as...', gtk.STOCK_SAVE_AS), - gtk.Action(FLOW_GRAPH_CLOSE, '_Close', 'Close the current flow graph', gtk.STOCK_CLOSE), - gtk.Action(APPLICATION_QUIT, '_Quit', 'Quit program', gtk.STOCK_QUIT), - gtk.Action(FLOW_GRAPH_UNDO, '_Undo', 'Undo a change to the flow graph', gtk.STOCK_UNDO), - gtk.Action(FLOW_GRAPH_REDO, '_Redo', 'Redo a change to the flow graph', gtk.STOCK_REDO), - gtk.Action(ELEMENT_DELETE, '_Delete', 'Delete the selected blocks', gtk.STOCK_DELETE), - gtk.Action(BLOCK_ROTATE_CCW, 'Rotate Counterclockwise', 'Rotate the selected blocks 90 degrees to the left', gtk.STOCK_GO_BACK), - gtk.Action(BLOCK_ROTATE_CW, 'Rotate Clockwise', 'Rotate the selected blocks 90 degrees to the right', gtk.STOCK_GO_FORWARD), - gtk.Action(BLOCK_PARAM_MODIFY, '_Properties', 'Modify params for the selected block', gtk.STOCK_PROPERTIES), - gtk.Action(BLOCK_ENABLE, 'E_nable', 'Enable the selected blocks', gtk.STOCK_CONNECT), - gtk.Action(BLOCK_DISABLE, 'D_isable', 'Disable the selected blocks', gtk.STOCK_DISCONNECT), - gtk.Action(BLOCK_CUT, 'Cu_t', 'Cut', gtk.STOCK_CUT), - gtk.Action(BLOCK_COPY, '_Copy', 'Copy', gtk.STOCK_COPY), - gtk.Action(BLOCK_PASTE, '_Paste', 'Paste', gtk.STOCK_PASTE), - gtk.Action(ABOUT_WINDOW_DISPLAY, '_About', 'About this program', gtk.STOCK_ABOUT), - gtk.Action(HELP_WINDOW_DISPLAY, '_Help', 'Usage Tips', gtk.STOCK_HELP), - gtk.Action(TYPES_WINDOW_DISPLAY, '_Types', 'Types Color Mapping', gtk.STOCK_DIALOG_INFO), - gtk.Action(FLOW_GRAPH_GEN, '_Generate', 'Generate the flow graph', gtk.STOCK_CONVERT), - gtk.Action(FLOW_GRAPH_EXEC, '_Execute', 'Execute the flow graph', gtk.STOCK_EXECUTE), - gtk.Action(FLOW_GRAPH_KILL, '_Kill', 'Kill the flow graph', gtk.STOCK_STOP), - gtk.Action(FLOW_GRAPH_SCREEN_CAPTURE, 'S_creen Capture', 'Create a screen capture of the flow graph', gtk.STOCK_PRINT), -) -def get_all_actions(): return _actions_list +_all_actions_list = list() +def get_all_actions(): return _all_actions_list + +_accel_group = gtk.AccelGroup() +def get_accel_group(): return _accel_group -_actions_dict = dict((action.get_name(), action) for action in get_all_actions()) -def get_action_from_name(action_name): +class Action(gtk.Action): """ - Retrieve the action from the action list. - Search the list and find an action with said name. - @param action_name the action name(string) - @throw KeyError bad action name - @return a gtk action object + A custom Action class based on gtk.Action. + Pass additional arguments such as keypresses. + Register actions and keypresses with this module. """ - try: return _actions_dict[action_name] - except KeyError: raise KeyError, 'Action Name: "%s" does not exist'%action_name -###################################################################################################### -# Accelerators -###################################################################################################### -_accel_group = gtk.AccelGroup() -def get_accel_group(): return _accel_group + def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None): + """ + Create a new Action instance. + @param key_presses a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...) + @param the regular gtk.Action parameters (defaults to None) + """ + if name is None: name = label + gtk.Action.__init__(self, + name=name, label=label, + tooltip=tooltip, stock_id=stock_id, + ) + #register this action + _all_actions_list.append(self) + for i in range(len(keypresses)/2): + keyval, mod_mask = keypresses[i*2:(i+1)*2] + #register this keypress + assert not _actions_keypress_dict.has_key((keyval, mod_mask)) + _actions_keypress_dict[(keyval, mod_mask)] = self + #set the accelerator group, and accelerator path + #register the key name and mod mask with the accelerator path + if label is None: continue #dont register accel + accel_path = '
/'+self.get_name() + self.set_accel_group(get_accel_group()) + self.set_accel_path(accel_path) + gtk.accel_map_add_entry(accel_path, keyval, mod_mask) + + def __str__(self): + """ + The string representation should be the name of the action id. + Try to find the action id for this action by searching this module. + """ + try: + import Actions + return filter(lambda attr: getattr(Actions, attr) == self, dir(Actions))[0] + except: return self.get_name() + + def __repr__(self): return str(self) -#set the accelerator group, and accelerator path -#register the key name and mod mask with the accelerator path -for action_name, keyval, mod_mask in _actions_key_list: - try: - accel_path = '
/'+action_name - get_action_from_name(action_name).set_accel_group(get_accel_group()) - get_action_from_name(action_name).set_accel_path(accel_path) - gtk.accel_map_add_entry(accel_path, keyval, mod_mask) - except KeyError: pass #no action was created for this action name + def __call__(self): + """ + Emit the activate signal when called with (). + """ + self.emit('activate') + +######################################################################## +# Actions +######################################################################## +PAGE_CHANGE = Action() +FLOW_GRAPH_NEW = Action( + label='_New', + tooltip='Create a new flow graph', + stock_id=gtk.STOCK_NEW, + keypresses=(gtk.keysyms.n, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_OPEN = Action( + label='_Open', + tooltip='Open an existing flow graph', + stock_id=gtk.STOCK_OPEN, + keypresses=(gtk.keysyms.o, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE = Action( + label='_Save', + tooltip='Save the current flow graph', + stock_id=gtk.STOCK_SAVE, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_SAVE_AS = Action( + label='Save _As', + tooltip='Save the current flow graph as...', + stock_id=gtk.STOCK_SAVE_AS, + keypresses=(gtk.keysyms.s, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK), +) +FLOW_GRAPH_CLOSE = Action( + label='_Close', + tooltip='Close the current flow graph', + stock_id=gtk.STOCK_CLOSE, + keypresses=(gtk.keysyms.w, gtk.gdk.CONTROL_MASK), +) +APPLICATION_INITIALIZE = Action() +APPLICATION_QUIT = Action( + label='_Quit', + tooltip='Quit program', + stock_id=gtk.STOCK_QUIT, + keypresses=(gtk.keysyms.q, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_UNDO = Action( + label='_Undo', + tooltip='Undo a change to the flow graph', + stock_id=gtk.STOCK_UNDO, + keypresses=(gtk.keysyms.z, gtk.gdk.CONTROL_MASK), +) +FLOW_GRAPH_REDO = Action( + label='_Redo', + tooltip='Redo a change to the flow graph', + stock_id=gtk.STOCK_REDO, + keypresses=(gtk.keysyms.y, gtk.gdk.CONTROL_MASK), +) +NOTHING_SELECT = Action() +ELEMENT_SELECT = Action() +ELEMENT_CREATE = Action() +ELEMENT_DELETE = Action( + label='_Delete', + tooltip='Delete the selected blocks', + stock_id=gtk.STOCK_DELETE, + keypresses=(gtk.keysyms.Delete, NO_MODS_MASK), +) +BLOCK_MOVE = Action() +BLOCK_ROTATE_CCW = Action( + label='Rotate Counterclockwise', + tooltip='Rotate the selected blocks 90 degrees to the left', + stock_id=gtk.STOCK_GO_BACK, + keypresses=(gtk.keysyms.Left, NO_MODS_MASK), +) +BLOCK_ROTATE_CW = Action( + label='Rotate Clockwise', + tooltip='Rotate the selected blocks 90 degrees to the right', + stock_id=gtk.STOCK_GO_FORWARD, + keypresses=(gtk.keysyms.Right, NO_MODS_MASK), +) +BLOCK_PARAM_MODIFY = Action( + label='_Properties', + tooltip='Modify params for the selected block', + stock_id=gtk.STOCK_PROPERTIES, + keypresses=(gtk.keysyms.Return, NO_MODS_MASK), +) +BLOCK_ENABLE = Action( + label='E_nable', + tooltip='Enable the selected blocks', + stock_id=gtk.STOCK_CONNECT, + keypresses=(gtk.keysyms.e, NO_MODS_MASK), +) +BLOCK_DISABLE = Action( + label='D_isable', + tooltip='Disable the selected blocks', + stock_id=gtk.STOCK_DISCONNECT, + keypresses=(gtk.keysyms.d, NO_MODS_MASK), +) +BLOCK_CUT = Action( + label='Cu_t', + tooltip='Cut', + stock_id=gtk.STOCK_CUT, + keypresses=(gtk.keysyms.x, gtk.gdk.CONTROL_MASK), +) +BLOCK_COPY = Action( + label='_Copy', + tooltip='Copy', + stock_id=gtk.STOCK_COPY, + keypresses=(gtk.keysyms.c, gtk.gdk.CONTROL_MASK), +) +BLOCK_PASTE = Action( + label='_Paste', + tooltip='Paste', + stock_id=gtk.STOCK_PASTE, + keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK), +) +ABOUT_WINDOW_DISPLAY = Action( + label='_About', + tooltip='About this program', + stock_id=gtk.STOCK_ABOUT, +) +HELP_WINDOW_DISPLAY = Action( + label='_Help', + tooltip='Usage Tips', + stock_id=gtk.STOCK_HELP, + keypresses=(gtk.keysyms.F1, NO_MODS_MASK), +) +TYPES_WINDOW_DISPLAY = Action( + label='_Types', + tooltip='Types Color Mapping', + stock_id=gtk.STOCK_DIALOG_INFO, +) +FLOW_GRAPH_GEN = Action( + label='_Generate', + tooltip='Generate the flow graph', + stock_id=gtk.STOCK_CONVERT, + keypresses=(gtk.keysyms.F5, NO_MODS_MASK), +) +FLOW_GRAPH_EXEC = Action( + label='_Execute', + tooltip='Execute the flow graph', + stock_id=gtk.STOCK_EXECUTE, + keypresses=(gtk.keysyms.F6, NO_MODS_MASK), +) +FLOW_GRAPH_KILL = Action( + label='_Kill', + tooltip='Kill the flow graph', + stock_id=gtk.STOCK_STOP, + keypresses=(gtk.keysyms.F7, NO_MODS_MASK), +) +FLOW_GRAPH_SCREEN_CAPTURE = Action( + label='S_creen Capture', + tooltip='Create a screen capture of the flow graph', + stock_id=gtk.STOCK_PRINT, + keypresses=(gtk.keysyms.Print, NO_MODS_MASK), +) +PORT_CONTROLLER_DEC = Action( + keypresses=(gtk.keysyms.minus, NO_MODS_MASK, gtk.keysyms.KP_Subtract, NO_MODS_MASK), +) +PORT_CONTROLLER_INC = Action( + keypresses=(gtk.keysyms.plus, NO_MODS_MASK, gtk.keysyms.KP_Add, NO_MODS_MASK), +) +BLOCK_INC_TYPE = Action( + keypresses=(gtk.keysyms.Down, NO_MODS_MASK), +) +BLOCK_DEC_TYPE = Action( + keypresses=(gtk.keysyms.Up, NO_MODS_MASK), +) diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 697d48a3c..fff5ebc08 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -104,9 +104,8 @@ class Toolbar(gtk.Toolbar): """ gtk.Toolbar.__init__(self) self.set_style(gtk.TOOLBAR_ICONS) - for action_name in TOOLBAR_LIST: - if action_name: #add a tool item - action = Actions.get_action_from_name(action_name) + for action in TOOLBAR_LIST: + if action: #add a tool item self.add(action.create_tool_item()) #this reset of the tooltip property is required (after creating the tool item) for the tooltip to show action.set_property('tooltip', action.get_property('tooltip')) @@ -123,16 +122,15 @@ class MenuBar(gtk.MenuBar): Add the submenu to the menu bar. """ gtk.MenuBar.__init__(self) - for main_action,action_names in MENU_BAR_LIST: + for main_action, actions in MENU_BAR_LIST: #create the main menu item main_menu_item = main_action.create_menu_item() self.append(main_menu_item) #create the menu main_menu = gtk.Menu() main_menu_item.set_submenu(main_menu) - for action_name in action_names: - if action_name: #append a menu item - action = Actions.get_action_from_name(action_name) + for action in actions: + if action: #append a menu item main_menu.append(action.create_menu_item()) else: main_menu.append(gtk.SeparatorMenuItem()) main_menu.show_all() #this show all is required for the separators to show diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 35ccf5e27..c90071f23 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -86,7 +86,7 @@ class FlowGraph(Element): block.set_coordinate(coor) block.set_rotation(0) block.get_param('id').set_value(id) - self.handle_states(ELEMENT_CREATE) + ELEMENT_CREATE() ########################################################################### # Copy Paste @@ -409,7 +409,7 @@ class FlowGraph(Element): self._old_selected_port is not self._new_selected_port: try: self.connect(self._old_selected_port, self._new_selected_port) - self.handle_states(ELEMENT_CREATE) + ELEMENT_CREATE() except: Messages.send_fail_connection() self._old_selected_port = None self._new_selected_port = None @@ -424,7 +424,7 @@ class FlowGraph(Element): self._selected_elements = list( set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements) ) - self.handle_states(ELEMENT_SELECT) + ELEMENT_SELECT() ########################################################################## ## Event Handlers @@ -446,7 +446,7 @@ class FlowGraph(Element): #double click detected, bring up params dialog if possible if double_click and self.get_selected_block(): self.mouse_pressed = False - self.handle_states(BLOCK_PARAM_MODIFY) + BLOCK_PARAM_MODIFY() def handle_mouse_button_release(self, left_click, coordinate): """ @@ -457,7 +457,7 @@ class FlowGraph(Element): self.time = 0 self.mouse_pressed = False if self.element_moved: - self.handle_states(BLOCK_MOVE) + BLOCK_MOVE() self.element_moved = False self.update_selected_elements() @@ -487,7 +487,7 @@ class FlowGraph(Element): adj.emit('changed') #remove the connection if selected in drag event if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection(): - self.handle_states(ELEMENT_DELETE) + ELEMENT_DELETE() #move the selected elements and record the new coordinate X, Y = self.get_coordinate() if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 6d36f4cf7..39cd84da9 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -1,5 +1,5 @@ """ -Copyright 2008 Free Software Foundation, Inc. +Copyright 2008, 2009 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -21,7 +21,8 @@ from Constants import \ NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH from Actions import \ APPLICATION_QUIT, FLOW_GRAPH_KILL, \ - FLOW_GRAPH_SAVE, get_accel_group + FLOW_GRAPH_SAVE, PAGE_CHANGE, \ + get_accel_group import pygtk pygtk.require('2.0') import gtk @@ -67,14 +68,13 @@ PAGE_TITLE_MARKUP_TMPL = """\ class MainWindow(gtk.Window): """The topmost window with menus, the tool bar, and other major windows.""" - def __init__(self, handle_states, platform): + def __init__(self, platform): """ - MainWindow contructor. - @param handle_states the callback function + MainWindow contructor + Setup the menu, toolbar, flowgraph editor notebook, block selection window... """ self._platform = platform #setup window - self.handle_states = handle_states gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL) vbox = gtk.VBox() self.hpaned = gtk.HPaned() @@ -123,7 +123,7 @@ class MainWindow(gtk.Window): This method in turns calls the state handler to quit. @return true """ - self.handle_states(APPLICATION_QUIT) + APPLICATION_QUIT() return True def _handle_page_change(self, notebook, page, page_num): @@ -137,7 +137,7 @@ class MainWindow(gtk.Window): """ self.current_page = self.notebook.get_nth_page(page_num) Messages.send_page_switch(self.current_page.get_file_path()) - self.handle_states() + PAGE_CHANGE() ############################################################ # Report Window @@ -223,12 +223,12 @@ class MainWindow(gtk.Window): self._set_page(self.page_to_be_closed) #unsaved? ask the user if not self.page_to_be_closed.get_saved() and self._save_changes(): - self.handle_states(FLOW_GRAPH_SAVE) #try to save + FLOW_GRAPH_SAVE() #try to save if not self.page_to_be_closed.get_saved(): #still unsaved? self.page_to_be_closed = None #set the page to be closed back to None return #stop the flow graph if executing - if self.page_to_be_closed.get_pid(): self.handle_states(FLOW_GRAPH_KILL) + if self.page_to_be_closed.get_pid(): FLOW_GRAPH_KILL() #remove the page self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed)) if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index cb6b7ed30..645af3f7f 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -80,9 +80,8 @@ class NotebookPage(gtk.HBox): self.drawing_area = DrawingArea(self.get_flow_graph()) self.scrolled_window.add_with_viewport(self.get_drawing_area()) self.pack_start(self.scrolled_window) - #inject drawing area and handle states into flow graph + #inject drawing area into flow graph self.get_flow_graph().drawing_area = self.get_drawing_area() - self.get_flow_graph().handle_states = main_window.handle_states self.show_all() def get_drawing_area(self): return self.drawing_area @@ -104,7 +103,7 @@ class NotebookPage(gtk.HBox): @param the button """ self.main_window.page_to_be_closed = self - self.main_window.handle_states(FLOW_GRAPH_CLOSE) + FLOW_GRAPH_CLOSE() def set_markup(self, markup): """ diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py index 04b18b18a..60ab3a6b4 100644 --- a/grc/gui/StateCache.py +++ b/grc/gui/StateCache.py @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO, get_action_from_name +from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO from Constants import STATE_CACHE_SIZE class StateCache(object): @@ -88,5 +88,5 @@ class StateCache(object): """ Update the undo and redo actions based on the number of next and prev states. """ - get_action_from_name(FLOW_GRAPH_REDO).set_sensitive(self.num_next_states != 0) - get_action_from_name(FLOW_GRAPH_UNDO).set_sensitive(self.num_prev_states != 0) + FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) + FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) -- cgit From 8442dfc877a89de00e5fd0fd1b4b1890a91af630 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Sep 2009 02:29:26 -0700 Subject: Simply Actions module imports, using module prefix. --- grc/gui/FlowGraph.py | 17 +++++++---------- grc/gui/MainWindow.py | 15 ++++++--------- grc/gui/NotebookPage.py | 4 ++-- grc/gui/StateCache.py | 6 +++--- 4 files changed, 18 insertions(+), 24 deletions(-) (limited to 'grc') diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index c90071f23..8feb171f1 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -18,10 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE -from Actions import \ - ELEMENT_CREATE, ELEMENT_SELECT, \ - BLOCK_PARAM_MODIFY, BLOCK_MOVE, \ - ELEMENT_DELETE +import Actions import Colors import Utils from Element import Element @@ -86,7 +83,7 @@ class FlowGraph(Element): block.set_coordinate(coor) block.set_rotation(0) block.get_param('id').set_value(id) - ELEMENT_CREATE() + Actions.ELEMENT_CREATE() ########################################################################### # Copy Paste @@ -409,7 +406,7 @@ class FlowGraph(Element): self._old_selected_port is not self._new_selected_port: try: self.connect(self._old_selected_port, self._new_selected_port) - ELEMENT_CREATE() + Actions.ELEMENT_CREATE() except: Messages.send_fail_connection() self._old_selected_port = None self._new_selected_port = None @@ -424,7 +421,7 @@ class FlowGraph(Element): self._selected_elements = list( set.union(old_elements, new_elements) - set.intersection(old_elements, new_elements) ) - ELEMENT_SELECT() + Actions.ELEMENT_SELECT() ########################################################################## ## Event Handlers @@ -446,7 +443,7 @@ class FlowGraph(Element): #double click detected, bring up params dialog if possible if double_click and self.get_selected_block(): self.mouse_pressed = False - BLOCK_PARAM_MODIFY() + Actions.BLOCK_PARAM_MODIFY() def handle_mouse_button_release(self, left_click, coordinate): """ @@ -457,7 +454,7 @@ class FlowGraph(Element): self.time = 0 self.mouse_pressed = False if self.element_moved: - BLOCK_MOVE() + Actions.BLOCK_MOVE() self.element_moved = False self.update_selected_elements() @@ -487,7 +484,7 @@ class FlowGraph(Element): adj.emit('changed') #remove the connection if selected in drag event if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection(): - ELEMENT_DELETE() + Actions.ELEMENT_DELETE() #move the selected elements and record the new coordinate X, Y = self.get_coordinate() if not self.get_ctrl_mask(): self.move_selected((int(x - X), int(y - Y))) diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 39cd84da9..9fcbe2a6c 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -19,10 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from Constants import \ NEW_FLOGRAPH_TITLE, DEFAULT_REPORTS_WINDOW_WIDTH -from Actions import \ - APPLICATION_QUIT, FLOW_GRAPH_KILL, \ - FLOW_GRAPH_SAVE, PAGE_CHANGE, \ - get_accel_group +import Actions import pygtk pygtk.require('2.0') import gtk @@ -80,7 +77,7 @@ class MainWindow(gtk.Window): self.hpaned = gtk.HPaned() self.add(vbox) #create the menu bar and toolbar - self.add_accel_group(get_accel_group()) + self.add_accel_group(Actions.get_accel_group()) vbox.pack_start(Bars.MenuBar(), False) vbox.pack_start(Bars.Toolbar(), False) vbox.pack_start(self.hpaned) @@ -123,7 +120,7 @@ class MainWindow(gtk.Window): This method in turns calls the state handler to quit. @return true """ - APPLICATION_QUIT() + Actions.APPLICATION_QUIT() return True def _handle_page_change(self, notebook, page, page_num): @@ -137,7 +134,7 @@ class MainWindow(gtk.Window): """ self.current_page = self.notebook.get_nth_page(page_num) Messages.send_page_switch(self.current_page.get_file_path()) - PAGE_CHANGE() + Actions.PAGE_CHANGE() ############################################################ # Report Window @@ -223,12 +220,12 @@ class MainWindow(gtk.Window): self._set_page(self.page_to_be_closed) #unsaved? ask the user if not self.page_to_be_closed.get_saved() and self._save_changes(): - FLOW_GRAPH_SAVE() #try to save + Actions.FLOW_GRAPH_SAVE() #try to save if not self.page_to_be_closed.get_saved(): #still unsaved? self.page_to_be_closed = None #set the page to be closed back to None return #stop the flow graph if executing - if self.page_to_be_closed.get_pid(): FLOW_GRAPH_KILL() + if self.page_to_be_closed.get_pid(): Actions.FLOW_GRAPH_KILL() #remove the page self.notebook.remove_page(self.notebook.page_num(self.page_to_be_closed)) if ensure and self.notebook.get_n_pages() == 0: self.new_page() #no pages, make a new one diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index 645af3f7f..fddfeaf5f 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -17,10 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Actions import FLOW_GRAPH_CLOSE import pygtk pygtk.require('2.0') import gtk +import Actions from StateCache import StateCache from Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT from DrawingArea import DrawingArea @@ -103,7 +103,7 @@ class NotebookPage(gtk.HBox): @param the button """ self.main_window.page_to_be_closed = self - FLOW_GRAPH_CLOSE() + Actions.FLOW_GRAPH_CLOSE() def set_markup(self, markup): """ diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py index 60ab3a6b4..3f6b79224 100644 --- a/grc/gui/StateCache.py +++ b/grc/gui/StateCache.py @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Actions import FLOW_GRAPH_UNDO, FLOW_GRAPH_REDO +import Actions from Constants import STATE_CACHE_SIZE class StateCache(object): @@ -88,5 +88,5 @@ class StateCache(object): """ Update the undo and redo actions based on the number of next and prev states. """ - FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) - FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) + Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) + Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) -- cgit From 6bd669d6e2fbe4b0ba5f74b697e532cf909c9e1d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Sep 2009 02:39:40 -0700 Subject: fix for uniformity convention with gtk signal name strings --- grc/gui/BlockTreeWindow.py | 2 +- grc/gui/PropsDialog.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'grc') diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 5c5d21b64..07b8ea7e0 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -57,7 +57,7 @@ class BlockTreeWindow(gtk.VBox): self.treeview = gtk.TreeView(self.treestore) self.treeview.set_enable_search(False) #disable pop up search box self.treeview.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self.treeview.connect('button_press_event', self._handle_mouse_button_press) + self.treeview.connect('button-press-event', self._handle_mouse_button_press) selection = self.treeview.get_selection() selection.set_mode('single') selection.connect('changed', self._handle_selection_change) diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index b295ba412..e3cd3a06f 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -82,7 +82,7 @@ class PropsDialog(gtk.Dialog): vbox.pack_start(self._error_box, False) vbox.pack_start(self._docs_box, False) #connect events - self.connect('key_press_event', self._handle_key_press) + self.connect('key-press-event', self._handle_key_press) self.connect('show', self._update_gui) #show all (performs initial gui update) self.show_all() -- cgit From ae3c009666f2bba0e10e054b0747d8f82a29515f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Sun, 13 Sep 2009 03:25:56 -0700 Subject: tweaked key handling callbacks --- grc/gui/ActionHandler.py | 4 +--- grc/gui/Actions.py | 13 +++++++------ 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 59e535bd4..361be1cf8 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -81,9 +81,7 @@ class ActionHandler: """ try: assert self.get_focus_flag() except AssertionError: return False - try: Actions.get_action_from_key_press(event)() - except KeyError: return False - return True #handled by this method + return Actions.handle_key_press(event) def _quit(self, window, event): """ diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 90017987f..b22279c1d 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -29,13 +29,12 @@ NO_MODS_MASK = 0 _actions_keypress_dict = dict() _keymap = gtk.gdk.keymap_get_default() _used_mods_mask = NO_MODS_MASK -def get_action_from_key_press(event): +def handle_key_press(event): """ - Get the action associated with the key press event. + Call the action associated with the key press event. Both the key value and the mask must have a match. @param event a gtk key press event - @throws a key error when no action matches - @return the action object + @return true if handled """ _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) #extract the key value and the consumed modifiers @@ -43,8 +42,10 @@ def get_action_from_key_press(event): event.hardware_keycode, event.state, event.group) #get the modifier mask and ignore irrelevant modifiers mod_mask = event.state & ~consumed & _used_mods_mask - try: return _actions_keypress_dict[(keyval, mod_mask)] - except KeyError: raise KeyError, 'Keypress: "%s, %s" does not have an associated action'%(gtk.gdk.keyval_name(keyval), mod_mask) + #look up the keypress and call the action + try: _actions_keypress_dict[(keyval, mod_mask)]() + except KeyError: return False #not handled + return True #handled here _all_actions_list = list() def get_all_actions(): return _all_actions_list -- cgit From 3fb876217316bb8ac9a59fffc75bb3c523ae1704 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 14 Sep 2009 22:37:55 -0700 Subject: fixed issue where entry boxes lost focus (mishandling of hide changing) --- grc/gui/PropsDialog.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index e3cd3a06f..a7822b228 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -91,6 +91,8 @@ class PropsDialog(gtk.Dialog): """ Have the params in this dialog changed? Ex: Added, removed, type change, hide change... + To the props dialog, the hide setting of 'none' and 'part' are identical. + Therfore, the props dialog only cares if the hide setting is/not 'all'. Make a hash that uniquely represents the params state. @return true if changed """ @@ -99,7 +101,7 @@ class PropsDialog(gtk.Dialog): for param in self._block.get_params(): self._hash ^= hash(param) self._hash ^= hash(param.get_type()) - self._hash ^= hash(param.get_hide()) + self._hash ^= hash(param.get_hide() == 'all') return self._hash != old_hash def _handle_changed(self, *args): -- cgit From 3f16d0acf93bbe8da7690f209782783ae8afb1c6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 17 Sep 2009 22:58:26 -0700 Subject: bugfix: exclude disabled children from consideration in valid condition --- grc/base/Element.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/base/Element.py b/grc/base/Element.py index e77e7ce08..a57090f3b 100644 --- a/grc/base/Element.py +++ b/grc/base/Element.py @@ -50,11 +50,12 @@ class Element(object): def get_error_messages(self): """ Get the list of error messages from this element and all of its children. + Do not include the error messages from disabled children. Cleverly indent the children error messages for printing purposes. @return a list of error message strings """ error_messages = list(self._error_messages) #make a copy - for child in self.get_children(): + for child in filter(lambda c: c.get_enabled(), self.get_children()): for msg in child.get_error_messages(): error_messages.append("%s:\n\t%s"%(child, msg.replace("\n", "\n\t"))) return error_messages -- cgit From 14895064d7345c2223ff2b8ff3b9cbcdf69dd8c9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 18 Sep 2009 02:10:13 -0700 Subject: added errors dialog to show all error messages in flow graph --- grc/gui/ActionHandler.py | 3 +++ grc/gui/Actions.py | 5 +++++ grc/gui/Bars.py | 3 +++ grc/gui/Dialogs.py | 14 ++++++++++++++ grc/python/Param.py | 2 +- 5 files changed, 26 insertions(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 361be1cf8..ee3e19a6c 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -210,6 +210,8 @@ class ActionHandler: Dialogs.HelpDialog() elif action == Actions.TYPES_WINDOW_DISPLAY: Dialogs.TypesDialog(self.get_flow_graph().get_parent()) + elif action == Actions.ERRORS_WINDOW_DISPLAY: + Dialogs.ErrorsDialog(self.get_flow_graph()) ################################################## # Param Modifications ################################################## @@ -307,6 +309,7 @@ class ActionHandler: # Global Actions for all States ################################################## #update general buttons + Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not self.get_flow_graph().is_valid()) Actions.ELEMENT_DELETE.set_sensitive(bool(self.get_flow_graph().get_selected_elements())) Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(self.get_flow_graph().get_selected_block())) Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(self.get_flow_graph().get_selected_blocks())) diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index b22279c1d..1cc12a819 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -215,6 +215,11 @@ BLOCK_PASTE = Action( stock_id=gtk.STOCK_PASTE, keypresses=(gtk.keysyms.v, gtk.gdk.CONTROL_MASK), ) +ERRORS_WINDOW_DISPLAY = Action( + label='_Errors', + tooltip='Flowgraph error messages', + stock_id=gtk.STOCK_DIALOG_ERROR, +) ABOUT_WINDOW_DISPLAY = Action( label='_About', tooltip='About this program', diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index fff5ebc08..17835eb00 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -81,6 +81,9 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_PARAM_MODIFY, ]), + (gtk.Action('View', '_View', None, None), [ + Actions.ERRORS_WINDOW_DISPLAY, + ]), (gtk.Action('Build', '_Build', None, None), [ Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index 3cf617b92..a8e7afb05 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -57,6 +57,20 @@ def MessageDialogHelper(type, buttons, title=None, markup=None): message_dialog.destroy() return response + +ERRORS_MARKUP_TMPL="""\ +#for $i, $err_msg in enumerate($errors) +Error $i: +$encode($err_msg.replace('\t', ' ')) + +#end for""" +def ErrorsDialog(flowgraph): MessageDialogHelper( + type=gtk.MESSAGE_ERROR, + buttons=gtk.BUTTONS_CLOSE, + title='Flowgraph Errors', + markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()), +) + class AboutDialog(gtk.AboutDialog): """A cute little about dialog.""" diff --git a/grc/python/Param.py b/grc/python/Param.py index 387fab548..1c1511315 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -254,7 +254,7 @@ class Param(_Param, _GUIParam): elif t in ('raw', 'complex', 'real', 'int', 'complex_vector', 'real_vector', 'int_vector', 'hex', 'bool'): #raise exception if python cannot evaluate this value try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: raise Exception, 'Value "%s" cannot be evaluated: %s'%(v, e) + except Exception, e: raise Exception, 'Value "%s" cannot be evaluated:\n%s'%(v, e) #raise an exception if the data is invalid if t == 'raw': return e elif t == 'complex': -- cgit From d28d40d33dac481296e1f836ec57f1018041d418 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 18 Sep 2009 02:22:43 -0700 Subject: put the flow graph errors button into the toolbar --- grc/gui/Actions.py | 6 +++--- grc/gui/Bars.py | 1 + grc/gui/Dialogs.py | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'grc') diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 1cc12a819..f374efde1 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -217,7 +217,7 @@ BLOCK_PASTE = Action( ) ERRORS_WINDOW_DISPLAY = Action( label='_Errors', - tooltip='Flowgraph error messages', + tooltip='View flow graph errors', stock_id=gtk.STOCK_DIALOG_ERROR, ) ABOUT_WINDOW_DISPLAY = Action( @@ -227,13 +227,13 @@ ABOUT_WINDOW_DISPLAY = Action( ) HELP_WINDOW_DISPLAY = Action( label='_Help', - tooltip='Usage Tips', + tooltip='Usage tips', stock_id=gtk.STOCK_HELP, keypresses=(gtk.keysyms.F1, NO_MODS_MASK), ) TYPES_WINDOW_DISPLAY = Action( label='_Types', - tooltip='Types Color Mapping', + tooltip='Types color mapping', stock_id=gtk.STOCK_DIALOG_INFO, ) FLOW_GRAPH_GEN = Action( diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 17835eb00..8fd167869 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -39,6 +39,7 @@ TOOLBAR_LIST = ( Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO, None, + Actions.ERRORS_WINDOW_DISPLAY, Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL, diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index a8e7afb05..af40f47c0 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -67,7 +67,7 @@ $encode($err_msg.replace('\t', ' ')) def ErrorsDialog(flowgraph): MessageDialogHelper( type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_CLOSE, - title='Flowgraph Errors', + title='Flow Graph Errors', markup=Utils.parse_template(ERRORS_MARKUP_TMPL, errors=flowgraph.get_error_messages()), ) -- cgit From 54f913876e5d92fa66f4bcf3a1c773a503e907f8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 18 Sep 2009 09:51:33 -0700 Subject: Re/evaluate the notebook blocks label because we dont garuntee the evaluation priority. Meaning, we cant garuntee that the notebook block will be evaluated before this param, without explicitly calling evaluate on it when the value is needed. --- grc/python/Param.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/python/Param.py b/grc/python/Param.py index 1c1511315..34d5ab116 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -385,7 +385,7 @@ class Param(_Param, _GUIParam): try: notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] except: raise Exception, 'Notebook id "%s" is not an existing notebook id.'%notebook_id #check that page index exists - try: assert int(page_index) in range(len(notebook_block.get_param('labels').get_evaluated())) + try: assert int(page_index) in range(len(notebook_block.get_param('labels').evaluate())) except: raise Exception, 'Page index "%s" is not a valid index number.'%page_index return notebook_id, page_index ######################### -- cgit From 24b3c103b859737d086d4813d6d345882b926e81 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 18 Sep 2009 20:37:05 -0700 Subject: bug fix for handling loading of dynamic params --- grc/base/Block.py | 24 +++++++++++++++++------- grc/base/FlowGraph.py | 1 - grc/todo.txt | 2 -- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'grc') diff --git a/grc/base/Block.py b/grc/base/Block.py index cb21c3958..43f9ba4e9 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -233,12 +233,22 @@ class Block(Element): """ Import this block's params from nested data. Any param keys that do not exist will be ignored. + Since params can be dynamically created based another param, + call rewrite, and repeat the load until the params stick. + This call to rewrite will also create any dynamic ports + that are needed for the connections creation phase. @param n the nested data odict """ - params_n = n.findall('param') - for param_n in params_n: - key = param_n.find('key') - value = param_n.find('value') - #the key must exist in this block's params - if key in self.get_param_keys(): - self.get_param(key).set_value(value) + get_hash = lambda: reduce(lambda x, y: x | y, [hash(param) for param in self.get_params()], 0) + my_hash = 0 + while get_hash() != my_hash: + params_n = n.findall('param') + for param_n in params_n: + key = param_n.find('key') + value = param_n.find('value') + #the key must exist in this block's params + if key in self.get_param_keys(): + self.get_param(key).set_value(value) + #store hash and call rewrite + my_hash = get_hash() + self.rewrite() diff --git a/grc/base/FlowGraph.py b/grc/base/FlowGraph.py index ce370ca24..7c51ef42a 100644 --- a/grc/base/FlowGraph.py +++ b/grc/base/FlowGraph.py @@ -184,7 +184,6 @@ class FlowGraph(Element): #only load the block when the block key was valid if block: block.import_data(block_n) else: Messages.send_error_load('Block key "%s" not found in %s'%(key, self.get_parent())) - self.rewrite() #rewrite all blocks before connections are made (ex: nports) #build the connections for connection_n in connections_n: #try to make the connection diff --git a/grc/todo.txt b/grc/todo.txt index 7fa68e523..b4e3af39d 100644 --- a/grc/todo.txt +++ b/grc/todo.txt @@ -69,8 +69,6 @@ * threads dont die on exit in probe and variable sink * align param titles in properties dialog * weird grid params misbehaving -* the block's import data does not handle variable params - * call rewrite after load, if new params appear, try load again... ################################################## # Future -- cgit From 803943020c3d53686f2b65a70cd24a780b46c925 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 18 Sep 2009 23:27:06 -0700 Subject: xor that hash --- grc/base/Block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'grc') diff --git a/grc/base/Block.py b/grc/base/Block.py index 43f9ba4e9..203e878e4 100644 --- a/grc/base/Block.py +++ b/grc/base/Block.py @@ -239,7 +239,7 @@ class Block(Element): that are needed for the connections creation phase. @param n the nested data odict """ - get_hash = lambda: reduce(lambda x, y: x | y, [hash(param) for param in self.get_params()], 0) + get_hash = lambda: reduce(lambda x, y: x ^ y, [hash(param) for param in self.get_params()], 0) my_hash = 0 while get_hash() != my_hash: params_n = n.findall('param') -- cgit From 7d8dd5e122e0201d96410eec6549b903881f8b3a Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Sat, 19 Sep 2009 20:38:24 -0700 Subject: Added CVSD encoder/decoder to GRC, example app Used blks2.cvsd* wrappers, not bare gnuradio.vocoder.cvsd* Example application sweeps 0-4KHz through encoder/decoder pair configured as Bluetooth standard --- grc/blocks/Makefile.am | 2 + grc/blocks/blks2_cvsd_decode.xml | 32 ++ grc/blocks/blks2_cvsd_encode.xml | 32 ++ grc/blocks/block_tree.xml | 5 + grc/examples/Makefile.am | 3 +- grc/examples/audio/cvsd_sweep.grc | 918 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 991 insertions(+), 1 deletion(-) create mode 100644 grc/blocks/blks2_cvsd_decode.xml create mode 100644 grc/blocks/blks2_cvsd_encode.xml create mode 100644 grc/examples/audio/cvsd_sweep.grc (limited to 'grc') diff --git a/grc/blocks/Makefile.am b/grc/blocks/Makefile.am index 32ddc6567..617a3bf60 100644 --- a/grc/blocks/Makefile.am +++ b/grc/blocks/Makefile.am @@ -30,6 +30,8 @@ dist_ourdata_DATA = \ band_reject_filter.xml \ blks2_am_demod_cf.xml \ blks2_analysis_filterbank.xml \ + blks2_cvsd_encode.xml \ + blks2_cvsd_decode.xml \ blks2_dxpsk_demod.xml \ blks2_dxpsk_mod.xml \ blks2_error_rate.xml \ diff --git a/grc/blocks/blks2_cvsd_decode.xml b/grc/blocks/blks2_cvsd_decode.xml new file mode 100644 index 000000000..6be7daa22 --- /dev/null +++ b/grc/blocks/blks2_cvsd_decode.xml @@ -0,0 +1,32 @@ + + + + CVSD Decoder + blks2_cvsd_decode + from gnuradio import blks2 + blks2.cvsd_decode($resample,$bw) + + Resample + resample + 8 + int + + + Frac. Bandwidth + bw + 0.5 + real + + + in + byte + + + out + float + + diff --git a/grc/blocks/blks2_cvsd_encode.xml b/grc/blocks/blks2_cvsd_encode.xml new file mode 100644 index 000000000..3123b1aa9 --- /dev/null +++ b/grc/blocks/blks2_cvsd_encode.xml @@ -0,0 +1,32 @@ + + + + CVSD Encoder + blks2_cvsd_encode + from gnuradio import blks2 + blks2.cvsd_encode($resample,$bw) + + Resample + resample + 8 + int + + + Frac. Bandwidth + bw + 0.5 + real + + + in + float + + + out + byte + + diff --git a/grc/blocks/block_tree.xml b/grc/blocks/block_tree.xml index 5a989cc01..296f0ee91 100644 --- a/grc/blocks/block_tree.xml +++ b/grc/blocks/block_tree.xml @@ -251,6 +251,11 @@ gr_scrambler_bb gr_descrambler_bb + + Vocoders + blks2_cvsd_encode + blks2_cvsd_decode + Probes gr_probe_avg_mag_sqrd_x diff --git a/grc/examples/Makefile.am b/grc/examples/Makefile.am index 969485c0d..78321ce0a 100644 --- a/grc/examples/Makefile.am +++ b/grc/examples/Makefile.am @@ -25,7 +25,8 @@ grc_examples_prefix = $(exampledir)/grc audiodatadir = $(grc_examples_prefix)/audio dist_audiodata_DATA = \ - audio/dial_tone.grc + audio/dial_tone.grc \ + audio/cvsd_sweep.grc simpledatadir = $(grc_examples_prefix)/simple dist_simpledata_DATA = \ diff --git a/grc/examples/audio/cvsd_sweep.grc b/grc/examples/audio/cvsd_sweep.grc new file mode 100644 index 000000000..8d0b385ce --- /dev/null +++ b/grc/examples/audio/cvsd_sweep.grc @@ -0,0 +1,918 @@ + + + Sat Sep 19 20:30:08 2009 + + import + + id + import_0 + + + _enabled + True + + + import + import math + + + _coordinate + (157, 11) + + + _rotation + 0 + + + + blks2_cvsd_decode + + id + blks2_cvsd_decode_0 + + + _enabled + True + + + resample + resample + + + bw + bw + + + _coordinate + (887, 340) + + + _rotation + 0 + + + + gr_sig_source_x + + id + tri_source + + + _enabled + True + + + type + float + + + samp_rate + audio_rate + + + waveform + gr.GR_TRI_WAVE + + + freq + 0.05 + + + amp + 0.5 + + + offset + 0 + + + _coordinate + (44, 316) + + + _rotation + 0 + + + + gr_throttle + + id + throttle + + + _enabled + True + + + type + float + + + samples_per_second + audio_rate + + + vlen + 1 + + + _coordinate + (238, 348) + + + _rotation + 0 + + + + gr_vco_f + + id + vco + + + _enabled + True + + + samp_rate + audio_rate + + + sensitivity + audio_rate*2*math.pi + + + amplitude + 0.9 + + + _coordinate + (427, 332) + + + _rotation + 0 + + + + blks2_cvsd_encode + + id + enc + + + _enabled + True + + + resample + resample + + + bw + bw + + + _coordinate + (655, 340) + + + _rotation + 0 + + + + gr_packed_to_unpacked_xx + + id + p2u + + + _enabled + True + + + type + byte + + + bits_per_chunk + 1 + + + endianness + gr.GR_MSB_FIRST + + + _coordinate + (648, 415) + + + _rotation + 180 + + + + gr_char_to_float + + id + c2f + + + _enabled + True + + + _coordinate + (676, 483) + + + _rotation + 0 + + + + audio_sink + + id + audio_sink + + + _enabled + True + + + samp_rate + audio_rate + + + device_name + plughw:0,0 + + + ok_to_block + True + + + num_inputs + 1 + + + _coordinate + (1127, 340) + + + _rotation + 0 + + + + variable + + id + audio_rate + + + _enabled + True + + + value + 8000 + + + _coordinate + (251, 10) + + + _rotation + 0 + + + + variable + + id + resample + + + _enabled + True + + + value + 8 + + + _coordinate + (344, 11) + + + _rotation + 0 + + + + variable + + id + bw + + + _enabled + True + + + value + 0.5 + + + _coordinate + (431, 11) + + + _rotation + 0 + + + + notebook + + id + displays + + + _enabled + True + + + style + wx.NB_TOP + + + labels + ['Original','Encoded','Decoded'] + + + grid_pos + + + + notebook + + + + _coordinate + (12, 106) + + + _rotation + 0 + + + + wxgui_fftsink2 + + id + orig_fft + + + _enabled + True + + + type + float + + + title + Original Spectrum + + + samp_rate + audio_rate + + + baseband_freq + 0 + + + y_per_div + 10 + + + y_divs + 10 + + + ref_level + 0 + + + ref_scale + 2.0 + + + fft_size + 1024 + + + fft_rate + 30 + + + peak_hold + False + + + average + False + + + avg_alpha + 0 + + + grid_pos + 0, 0, 1, 1 + + + notebook + displays, 0 + + + _coordinate + (415, 97) + + + _rotation + 180 + + + + wxgui_scopesink2 + + id + orig_scope + + + _enabled + True + + + type + float + + + title + Original Waveform + + + samp_rate + audio_rate + + + v_scale + 0 + + + t_scale + 0 + + + ac_couple + False + + + xy_mode + False + + + num_inputs + 1 + + + grid_pos + 1, 0, 1, 1 + + + notebook + displays, 0 + + + _coordinate + (414, 425) + + + _rotation + 180 + + + + wxgui_fftsink2 + + id + enc_fft + + + _enabled + True + + + type + float + + + title + Encoded Spectrum + + + samp_rate + audio_rate*resample + + + baseband_freq + 0 + + + y_per_div + 10 + + + y_divs + 8 + + + ref_level + 10 + + + ref_scale + 2.0 + + + fft_size + 1024 + + + fft_rate + 30 + + + peak_hold + False + + + average + False + + + avg_alpha + 0 + + + grid_pos + 1, 0, 1, 1 + + + notebook + displays, 1 + + + _coordinate + (610, 551) + + + _rotation + 180 + + + + wxgui_scopesink2 + + id + enc_scope + + + _enabled + True + + + type + float + + + title + Encoded Waveform + + + samp_rate + audio_rate*resample + + + v_scale + 0.5 + + + t_scale + 20.0/(audio_rate*resample) + + + ac_couple + False + + + xy_mode + False + + + num_inputs + 1 + + + grid_pos + 0, 0, 1, 1 + + + notebook + displays, 1 + + + _coordinate + (858, 591) + + + _rotation + 0 + + + + wxgui_fftsink2 + + id + dec_fft + + + _enabled + True + + + type + float + + + title + Decoded Spectrum + + + samp_rate + audio_rate + + + baseband_freq + 0 + + + y_per_div + 5 + + + y_divs + 10 + + + ref_level + 10 + + + ref_scale + 0.1 + + + fft_size + 1024 + + + fft_rate + 30 + + + peak_hold + False + + + average + False + + + avg_alpha + 0 + + + grid_pos + 0, 0, 1, 1 + + + notebook + displays, 2 + + + _coordinate + (891, 98) + + + _rotation + 180 + + + + wxgui_scopesink2 + + id + dec_scope + + + _enabled + True + + + type + float + + + title + Decoded Waveform + + + samp_rate + audio_rate + + + v_scale + 0 + + + t_scale + 0 + + + ac_couple + False + + + xy_mode + False + + + num_inputs + 1 + + + grid_pos + 1, 0, 1, 1 + + + notebook + displays, 2 + + + _coordinate + (889, 422) + + + _rotation + 180 + + + + options + + id + cvsd_sweep + + + _enabled + True + + + title + CVSD Vocoder Test + + + author + + + + description + + + + window_size + 1280, 1024 + + + generate_options + wx_gui + + + category + Custom + + + run + True + + + realtime_scheduling + + + + _coordinate + (10, 10) + + + _rotation + 0 + + + + vco + orig_fft + 0 + 0 + + + tri_source + throttle + 0 + 0 + + + throttle + vco + 0 + 0 + + + vco + enc + 0 + 0 + + + enc + blks2_cvsd_decode_0 + 0 + 0 + + + vco + orig_scope + 0 + 0 + + + blks2_cvsd_decode_0 + dec_fft + 0 + 0 + + + blks2_cvsd_decode_0 + dec_scope + 0 + 0 + + + blks2_cvsd_decode_0 + audio_sink + 0 + 0 + + + enc + p2u + 0 + 0 + + + p2u + c2f + 0 + 0 + + + c2f + enc_fft + 0 + 0 + + + c2f + enc_scope + 0 + 0 + + -- cgit From fd37328c778ea8014e9ea9d932e61e5d229dd012 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 25 Sep 2009 00:24:48 -0700 Subject: Added a run options to the "no gui" generate options. The user can select between run to completion and prompt for exit. Also fixed the props dialog is changed function to have better hashes. Now we hash a tuple of all "relevant" items which is "order aware". Since xoring the individual hashes proved faulty when 2 params alternated hiding. --- grc/blocks/options.xml | 29 +++++++++++++++++++++++------ grc/gui/PropsDialog.py | 11 +++++------ grc/python/flow_graph.tmpl | 5 +++++ 3 files changed, 33 insertions(+), 12 deletions(-) (limited to 'grc') diff --git a/grc/blocks/options.xml b/grc/blocks/options.xml index 1798a69f8..4d0dd2899 100644 --- a/grc/blocks/options.xml +++ b/grc/blocks/options.xml @@ -77,20 +77,37 @@ else: self.stop(); self.wait() string #if $generate_options() == 'hb' then 'none' else 'all'# + + Run Options + run_options + prompt + enum + #if $generate_options() == 'no_gui' then 'none' else 'all'# + + + Run run True bool - #if $generate_options() == 'wx_gui' - #if str($run) == 'True' -part#slurp + +#if $generate_options() == 'wx_gui' + #if $run() + part #else -none#slurp + none #end if #else -all#slurp -#end if + all +#end if + - - Run run True bool - -#if $generate_options() == 'wx_gui' - #if $run() - part + #if $generate_options() == 'wx_gui' + #if str($run) == 'True' +part#slurp #else - none +none#slurp #end if #else - all -#end if - +all#slurp +#end if + + Run run True bool - #if $generate_options() == 'wx_gui' - #if str($run) == 'True' -part#slurp + +#if $generate_options() == 'wx_gui' + #if $run() + part #else -none#slurp + none #end if #else -all#slurp -#end if + all +#end if +