diff options
-rw-r--r-- | grc/gui/ActionHandler.py | 35 | ||||
-rw-r--r-- | grc/gui/Actions.py | 22 | ||||
-rw-r--r-- | grc/gui/Bars.py | 1 | ||||
-rw-r--r-- | grc/gui/Block.py | 18 | ||||
-rw-r--r-- | grc/gui/Constants.py | 5 | ||||
-rw-r--r-- | grc/gui/DrawingArea.py | 4 | ||||
-rw-r--r-- | grc/gui/FlowGraph.py | 13 | ||||
-rw-r--r-- | grc/gui/Port.py | 10 | ||||
-rw-r--r-- | grc/gui/Preferences.py | 29 | ||||
-rw-r--r-- | grc/gui/Utils.py | 10 |
10 files changed, 94 insertions, 53 deletions
diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 18b7c9aee0..dcc3c846eb 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -118,7 +118,7 @@ class ActionHandler: Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW, Actions.TOGGLE_REPORTS_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS, Actions.TOOLS_RUN_FDESIGN, Actions.TOGGLE_SCROLL_LOCK, Actions.CLEAR_REPORTS, - Actions.TOGGLE_AUTO_HIDE_PORT_LABELS + Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID ): action.set_sensitive(True) if ParseXML.xml_failures: Messages.send_xml_errors_if_any(ParseXML.xml_failures) @@ -134,10 +134,13 @@ class ActionHandler: if not self.get_page(): self.main_window.new_page() #ensure that at least a blank page exists self.main_window.btwin.search_entry.hide() - Actions.TOGGLE_REPORTS_WINDOW.set_active(Preferences.reports_window_visibility()) - Actions.TOGGLE_BLOCKS_WINDOW.set_active(Preferences.blocks_window_visibility()) - Actions.TOGGLE_SCROLL_LOCK.set_active(Preferences.scroll_lock()) - Actions.TOGGLE_AUTO_HIDE_PORT_LABELS.set_active(Preferences.auto_hide_port_labels()) + for action in ( + Actions.TOGGLE_REPORTS_WINDOW, + Actions.TOGGLE_BLOCKS_WINDOW, + Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, + Actions.TOGGLE_SCROLL_LOCK, + Actions.TOGGLE_SNAP_TO_GRID + ): action.load_from_preferences() elif action == Actions.APPLICATION_QUIT: if self.main_window.close_pages(): gtk.main_quit() @@ -363,31 +366,32 @@ class ActionHandler: elif action == Actions.ERRORS_WINDOW_DISPLAY: Dialogs.ErrorsDialog(self.get_flow_graph()) elif action == Actions.TOGGLE_REPORTS_WINDOW: - visible = action.get_active() - if visible: + if action.get_active(): self.main_window.reports_scrolled_window.show() else: self.main_window.reports_scrolled_window.hide() - Preferences.reports_window_visibility(visible) + action.save_to_preferences() elif action == Actions.TOGGLE_BLOCKS_WINDOW: - visible = action.get_active() - if visible: + if action.get_active(): self.main_window.btwin.show() else: self.main_window.btwin.hide() - Preferences.blocks_window_visibility(visible) + action.save_to_preferences() elif action == Actions.TOGGLE_SCROLL_LOCK: - visible = action.get_active() - self.main_window.text_display.scroll_lock = visible - if visible: + active = action.get_active() + self.main_window.text_display.scroll_lock = active + if active: self.main_window.text_display.scroll_to_end() + action.save_to_preferences() elif action == Actions.CLEAR_REPORTS: self.main_window.text_display.clear() elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS: Actions.NOTHING_SELECT() elif action == Actions.TOGGLE_AUTO_HIDE_PORT_LABELS: - Preferences.auto_hide_port_labels(action.get_active()) + action.save_to_preferences() self.main_window.get_flow_graph().create_shapes() + elif action == Actions.TOGGLE_SNAP_TO_GRID: + action.save_to_preferences() ################################################## # Param Modifications ################################################## @@ -497,7 +501,6 @@ class ActionHandler: self.main_window.btwin.search_entry.show() self.main_window.btwin.search_entry.grab_focus() elif action == Actions.OPEN_HIER: - bn = []; for b in self.get_flow_graph().get_selected_blocks(): if b._grc_source: self.main_window.new_page(b._grc_source, show=True) diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index cbd41332ab..c41798aab8 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -21,6 +21,8 @@ import pygtk pygtk.require('2.0') import gtk +import Preferences + NO_MODS_MASK = 0 ######################################################################## @@ -127,7 +129,7 @@ class ToggleAction(gtk.ToggleAction, _ActionBase): Pass additional arguments such as keypresses. """ - def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None): + def __init__(self, keypresses=(), name=None, label=None, tooltip=None, stock_id=None, preference_name=None): """ Create a new ToggleAction instance. @@ -142,6 +144,15 @@ class ToggleAction(gtk.ToggleAction, _ActionBase): ) #register this action _ActionBase.__init__(self, label, keypresses) + self.preference_name = preference_name + + def load_from_preferences(self): + if self.preference_name is not None: + self.set_active(Preferences.bool_entry(self.preference_name)) + + def save_to_preferences(self): + if self.preference_name is not None: + Preferences.bool_entry(self.preference_name, self.get_active()) ######################################################################## # Actions @@ -236,6 +247,11 @@ BLOCK_DISABLE = Action( stock_id=gtk.STOCK_DISCONNECT, keypresses=(gtk.keysyms.d, NO_MODS_MASK), ) +TOGGLE_SNAP_TO_GRID = ToggleAction( + label='_Snap to grid', + tooltip='Snap blocks to a grid for an easier connection alignment', + preference_name='snap_to_grid' +) TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction( label='Hide _disabled blocks', tooltip='Toggle visibility of disabled blocks and connections', @@ -245,6 +261,7 @@ TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction( TOGGLE_AUTO_HIDE_PORT_LABELS = ToggleAction( label='Auto-hide port _labels', tooltip='Automatically hide port labels', + preference_name='auto_hide_port_labels' ) BLOCK_CREATE_HIER = Action( label='C_reate Hier', @@ -279,15 +296,18 @@ TOGGLE_REPORTS_WINDOW = ToggleAction( label='Show _Reports', tooltip='Toggle visibility of the Report widget', keypresses=(gtk.keysyms.r, gtk.gdk.CONTROL_MASK), + preference_name='reports_window_visible' ) TOGGLE_BLOCKS_WINDOW = ToggleAction( label='Show _Block Tree', tooltip='Toggle visibility of the block tree widget', keypresses=(gtk.keysyms.b, gtk.gdk.CONTROL_MASK), + preference_name='blocks_window_visible' ) TOGGLE_SCROLL_LOCK = ToggleAction( label='_Reports Scroll Lock', tooltip='Toggle scroll lock for the report window', + preference_name='scroll_lock' ) ABOUT_WINDOW_DISPLAY = Action( label='_About', diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index c3a2839c5c..743345200e 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -99,6 +99,7 @@ MENU_BAR_LIST = ( None, Actions.TOGGLE_HIDE_DISABLED_BLOCKS, Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, + Actions.TOGGLE_SNAP_TO_GRID, None, Actions.ERRORS_WINDOW_DISPLAY, Actions.FIND_BLOCKS, diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 0afb351647..0ae624f94f 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -26,6 +26,7 @@ from Constants import \ BLOCK_LABEL_PADDING, \ PORT_SEPARATION, LABEL_SEPARATION, \ PORT_BORDER_SEPARATION, POSSIBLE_ROTATIONS +import Actions import pygtk pygtk.require('2.0') import gtk @@ -43,6 +44,8 @@ class Block(Element): Block contructor. Add graphics related params to the block. """ + self.W = 0 + self.H = 0 #add the position param self.get_params().append(self.get_parent().get_parent().Param( block=self, @@ -97,6 +100,12 @@ class Block(Element): Args: coor: the coordinate tuple (x, y) """ + if Actions.TOGGLE_SNAP_TO_GRID.get_active(): + offset_x, offset_y = (0, self.H/2) if self.is_horizontal() else (self.H/2, 0) + coor = ( + Utils.align_to_grid(coor[0] + offset_x) - offset_x, + Utils.align_to_grid(coor[1] + offset_y) - offset_y + ) self.get_param('_coordinate').set_value(str(coor)) def get_rotation(self): @@ -174,14 +183,17 @@ class Block(Element): Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) #calculate width and height needed self.W = self.label_width + 2*BLOCK_LABEL_PADDING + def get_min_height_for_ports(): + visible_ports = filter(lambda p: not p.get_hide(), ports) + H = 2*PORT_BORDER_SEPARATION + len(visible_ports) * PORT_SEPARATION + if visible_ports: H -= ports[0].H + return H self.H = max(*( [ # labels self.label_height + 2 * BLOCK_LABEL_PADDING ] + [ # ports - 2 * PORT_BORDER_SEPARATION + - sum([port.H + PORT_SEPARATION for port in ports if not port.get_hide()]) - PORT_SEPARATION - for ports in (self.get_sources_gui(), self.get_sinks_gui()) + get_min_height_for_ports() for ports in (self.get_sources_gui(), self.get_sinks_gui()) ] + [ # bus ports only 4 * PORT_BORDER_SEPARATION + diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 7fabcfc0a0..c82449b6b6 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -53,7 +53,7 @@ BLOCK_LABEL_PADDING = 7 PORT_LABEL_PADDING = 2 #port constraint dimensions -PORT_SEPARATION = 17 +PORT_SEPARATION = 32 PORT_BORDER_SEPARATION = 9 PORT_MIN_WIDTH = 20 @@ -81,3 +81,6 @@ SCROLL_DISTANCE = 15 #How close the mouse click can be to a line and register a connection select. LINE_SELECT_SENSITIVITY = 5 + +# canvas grid size +CANVAS_GRID_SIZE = 8
\ No newline at end of file diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index 448948e7f4..d22a2c6d5f 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -37,6 +37,7 @@ class DrawingArea(gtk.DrawingArea): main_window: the main_window containing all flow graphs """ self.ctrl_mask = False + self.mod1_mask = False self._flow_graph = flow_graph gtk.DrawingArea.__init__(self) self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) @@ -88,6 +89,7 @@ class DrawingArea(gtk.DrawingArea): """ self.grab_focus() self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + self.mod1_mask = event.state & gtk.gdk.MOD1_MASK if event.button == 1: self._flow_graph.handle_mouse_selector_press( double_click=(event.type == gtk.gdk._2BUTTON_PRESS), coordinate=(event.x, event.y), @@ -102,6 +104,7 @@ class DrawingArea(gtk.DrawingArea): Forward button release information to the flow graph. """ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + self.mod1_mask = event.state & gtk.gdk.MOD1_MASK if event.button == 1: self._flow_graph.handle_mouse_selector_release( coordinate=(event.x, event.y), ) @@ -111,6 +114,7 @@ class DrawingArea(gtk.DrawingArea): Forward mouse motion information to the flow graph. """ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK + self.mod1_mask = event.state & gtk.gdk.MOD1_MASK self._flow_graph.handle_mouse_motion( coordinate=(event.x, event.y), ) diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index bfe8fbfa4f..31017a9923 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -84,6 +84,7 @@ class FlowGraph(Element): def set_size(self, *args): self.get_drawing_area().set_size_request(*args) def get_scroll_pane(self): return self.drawing_area.get_parent() def get_ctrl_mask(self): return self.drawing_area.ctrl_mask + def get_mod1_mask(self): return self.drawing_area.mod1_mask def new_pixmap(self, *args): return self.get_drawing_area().new_pixmap(*args) def add_new_block(self, key, coor=None): @@ -574,7 +575,7 @@ class FlowGraph(Element): self.create_shapes() self.queue_draw() else: - #perform autoscrolling + #perform auto-scrolling width, height = self.get_size() x, y = coordinate h_adj = self.get_scroll_pane().get_hadjustment() @@ -594,8 +595,12 @@ class FlowGraph(Element): if len(self.get_selected_elements()) == 1 and self.get_selected_element().is_connection(): 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))) - self.set_coordinate((x, y)) + if not self.get_ctrl_mask(): + X, Y = self.get_coordinate() + dX, dY = int(x - X), int(y - Y) + active = Actions.TOGGLE_SNAP_TO_GRID.get_active() or self.get_mod1_mask() + if not active or abs(dX) >= Utils.CANVAS_GRID_SIZE or abs(dY) >= Utils.CANVAS_GRID_SIZE: + self.move_selected((dX, dY)) + self.set_coordinate((x, y)) #queue draw for animation self.queue_draw() diff --git a/grc/gui/Port.py b/grc/gui/Port.py index b81b162f6e..c56432d2b5 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -70,26 +70,26 @@ class Port(Element): length = len(filter(lambda p: not p.get_hide(), ports)) #reverse the order of ports for these rotations if rotation in (180, 270): index = length-index-1 - offset = (self.get_parent().H - length*self.H - (length-1)*PORT_SEPARATION)/2 + offset = (self.get_parent().H - (length-1)*PORT_SEPARATION - self.H)/2 #create areas and connector coordinates if (self.is_sink() and rotation == 0) or (self.is_source() and rotation == 180): x = -1*W - y = (PORT_SEPARATION+self.H)*index+offset + y = PORT_SEPARATION*index+offset self.add_area((x, y), (W, self.H)) self._connector_coordinate = (x-1, y+self.H/2) elif (self.is_source() and rotation == 0) or (self.is_sink() and rotation == 180): x = self.get_parent().W - y = (PORT_SEPARATION+self.H)*index+offset + y = PORT_SEPARATION*index+offset self.add_area((x, y), (W, self.H)) self._connector_coordinate = (x+1+W, y+self.H/2) elif (self.is_source() and rotation == 90) or (self.is_sink() and rotation == 270): y = -1*W - x = (PORT_SEPARATION+self.H)*index+offset + x = PORT_SEPARATION*index+offset self.add_area((x, y), (self.H, W)) self._connector_coordinate = (x+self.H/2, y-1) elif (self.is_sink() and rotation == 90) or (self.is_source() and rotation == 270): y = self.get_parent().W - x = (PORT_SEPARATION+self.H)*index+offset + x = PORT_SEPARATION*index+offset self.add_area((x, y), (self.H, W)) self._connector_coordinate = (x+self.H/2, y+1+W) #the connector length diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py index d2ffc71410..1d6675da32 100644 --- a/grc/gui/Preferences.py +++ b/grc/gui/Preferences.py @@ -84,26 +84,11 @@ def blocks_window_position(pos=None): try: return _config_parser.getint('main', 'blocks_window_position') or 1 #greater than 0 except: return -1 -def reports_window_visibility(visible=None): - if visible is not None: _config_parser.set('main', 'reports_window_visible', visible) +def bool_entry(key, active=None, default=True): + if active is not None: + _config_parser.set('main', key, active) else: - try: return _config_parser.getboolean('main', 'reports_window_visible') - except: return True - -def blocks_window_visibility(visible=None): - if visible is not None: _config_parser.set('main', 'blocks_window_visible', visible) - else: - try: return _config_parser.getboolean('main', 'blocks_window_visible') - except: return True - -def scroll_lock(visible=None): - if visible is not None: _config_parser.set('main', 'scroll_lock', visible) - else: - try: return _config_parser.getboolean('main', 'scroll_lock') - except: return True - -def auto_hide_port_labels(hide=None): - if hide is not None: _config_parser.set('main', 'auto_hide_port_labels', hide) - else: - try: return _config_parser.getboolean('main', 'auto_hide_port_labels') - except: return True + try: + return _config_parser.getboolean('main', key) + except: + return default
\ No newline at end of file diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index ebd5aefca7..9a0a59cda7 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.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 Constants import POSSIBLE_ROTATIONS +from Constants import POSSIBLE_ROTATIONS, CANVAS_GRID_SIZE from Cheetah.Template import Template import pygtk pygtk.require('2.0') @@ -108,3 +108,11 @@ def parse_template(tmpl_str, **kwargs): # print tmpl_str # print str(kwargs['param'].get_error_messages()) return str(Template(tmpl_str, kwargs)) + +def align_to_grid(coor): + _align = lambda: int(round(x / (1.0 * CANVAS_GRID_SIZE)) * CANVAS_GRID_SIZE) + try: + return [_align() for x in coor] + except TypeError: + x = coor + return _align()
\ No newline at end of file |