diff options
Diffstat (limited to 'grc/gui/FlowGraph.py')
-rw-r--r-- | grc/gui/FlowGraph.py | 232 |
1 files changed, 113 insertions, 119 deletions
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index f98aec41d5..d7745a529d 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -17,16 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import functools import random from distutils.spawn import find_executable from itertools import chain, count from operator import methodcaller -import gobject +import six +from six.moves import filter + +from gi.repository import GObject -from . import Actions, Colors, Constants, Utils, Bars, Dialogs -from .Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE +from . import Actions, Colors, Utils, Bars, Dialogs from .Element import Element from .external_editor import ExternalEditor @@ -76,19 +80,20 @@ class FlowGraph(Element, _Flowgraph): Returns: a unique id """ + block_ids = set(b.get_id() for b in self.blocks) for index in count(): block_id = '{}_{}'.format(base_id, index) - if block_id not in (b.get_id() for b in self.blocks): + if block_id not in block_ids: break return block_id def install_external_editor(self, param): - target = (param.get_parent().get_id(), param.get_key()) + target = (param.parent_block.get_id(), param.get_key()) if target in self._external_updaters: editor = self._external_updaters[target] else: - config = self.get_parent().config + config = self.parent_platform.config editor = (find_executable(config.editor) or Dialogs.ChooseEditorDialog(config)) if not editor: @@ -98,7 +103,7 @@ class FlowGraph(Element, _Flowgraph): editor = self._external_updaters[target] = ExternalEditor( editor=editor, name=target[0], value=param.get_value(), - callback=functools.partial(gobject.idle_add, updater) + callback=functools.partial(GObject.idle_add, updater) ) editor.start() try: @@ -107,7 +112,7 @@ class FlowGraph(Element, _Flowgraph): # Problem launching the editor. Need to select a new editor. Messages.send('>>> Error opening an external editor. Please select a different editor.\n') # Reset the editor to force the user to select a new one. - self.get_parent().config.editor = '' + self.parent_platform.config.editor = '' def handle_external_editor_change(self, new_value, target): try: @@ -126,9 +131,7 @@ class FlowGraph(Element, _Flowgraph): ########################################################################### def get_drawing_area(self): return self.drawing_area def queue_draw(self): self.get_drawing_area().queue_draw() - def get_size(self): return self.get_drawing_area().get_size_request() - 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_scroll_pane(self): return self.drawing_area.get_parent().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) @@ -143,14 +146,11 @@ class FlowGraph(Element, _Flowgraph): """ id = self._get_unique_id(key) #calculate the position coordinate - W, H = self.get_size() h_adj = self.get_scroll_pane().get_hadjustment() v_adj = self.get_scroll_pane().get_vadjustment() if coor is None: coor = ( - int(random.uniform(.25, .75) * min(h_adj.page_size, W) + - h_adj.get_value()), - int(random.uniform(.25, .75) * min(v_adj.page_size, H) + - v_adj.get_value()), + int(random.uniform(.25, .75)*h_adj.get_page_size() + h_adj.get_value()), + int(random.uniform(.25, .75)*v_adj.get_page_size() + v_adj.get_value()), ) #get the new block block = self.new_block(key) @@ -172,7 +172,8 @@ class FlowGraph(Element, _Flowgraph): """ #get selected blocks blocks = self.get_selected_blocks() - if not blocks: return None + if not blocks: + return None #calc x and y min x_min, y_min = blocks[0].get_coordinate() for block in blocks: @@ -180,10 +181,10 @@ class FlowGraph(Element, _Flowgraph): x_min = min(x, x_min) y_min = min(y, y_min) #get connections between selected blocks - connections = filter( - lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks, + connections = list(filter( + lambda c: c.source_block in blocks and c.sink_block in blocks, self.connections, - ) + )) clipboard = ( (x_min, y_min), [block.export_data() for block in blocks], @@ -204,26 +205,26 @@ class FlowGraph(Element, _Flowgraph): #recalc the position h_adj = self.get_scroll_pane().get_hadjustment() v_adj = self.get_scroll_pane().get_vadjustment() - x_off = h_adj.get_value() - x_min + h_adj.page_size/4 - y_off = v_adj.get_value() - y_min + v_adj.page_size/4 + x_off = h_adj.get_value() - x_min + h_adj.get_page_size() / 4 + y_off = v_adj.get_value() - y_min + v_adj.get_page_size() / 4 if len(self.get_elements()) <= 1: x_off, y_off = 0, 0 #create blocks for block_n in blocks_n: - block_key = block_n.find('key') - if block_key == 'options': continue + block_key = block_n.get('key') + if block_key == 'options': + continue block = self.new_block(block_key) if not block: continue # unknown block was pasted (e.g. dummy block) selected.add(block) #set params - params = dict((n.find('key'), n.find('value')) - for n in block_n.findall('param')) + params = {n['key']: n['value'] for n in block_n.get('param', [])} if block_key == 'epy_block': block.get_param('_io_cache').set_value(params.pop('_io_cache')) block.get_param('_source_code').set_value(params.pop('_source_code')) block.rewrite() # this creates the other params - for param_key, param_value in params.iteritems(): + for param_key, param_value in six.iteritems(params): #setup id parameter if param_key == 'id': old_id2block[param_value] = block @@ -238,8 +239,8 @@ class FlowGraph(Element, _Flowgraph): self.update() #create connections for connection_n in connections_n: - source = old_id2block[connection_n.find('source_block_id')].get_source(connection_n.find('source_key')) - sink = old_id2block[connection_n.find('sink_block_id')].get_sink(connection_n.find('sink_key')) + source = old_id2block[connection_n.get('source_block_id')].get_source(connection_n.get('source_key')) + sink = old_id2block[connection_n.get('sink_block_id')].get_sink(connection_n.get('sink_key')) self.connect(source, sink) #set all pasted elements selected for block in selected: selected = selected.union(set(block.get_connections())) @@ -284,7 +285,8 @@ class FlowGraph(Element, _Flowgraph): """ changed = False for selected_block in self.get_selected_blocks(): - if selected_block.set_enabled(enable): changed = True + if selected_block.set_enabled(enable): + changed = True return changed def bypass_selected(self): @@ -298,7 +300,8 @@ class FlowGraph(Element, _Flowgraph): """ changed = False for selected_block in self.get_selected_blocks(): - if selected_block.set_bypassed(): changed = True + if selected_block.set_bypassed(): + changed = True return changed def move_selected(self, delta_coordinate): @@ -309,9 +312,6 @@ class FlowGraph(Element, _Flowgraph): delta_coordinate: the change in coordinates """ for selected_block in self.get_selected_blocks(): - delta_coordinate = selected_block.bound_move_delta(delta_coordinate) - - for selected_block in self.get_selected_blocks(): selected_block.move(delta_coordinate) self.element_moved = True @@ -400,52 +400,44 @@ class FlowGraph(Element, _Flowgraph): changed = True return changed - def draw(self, gc, window): + def draw(self, widget, cr): """ Draw the background and grid if enabled. - Draw all of the elements in this flow graph onto the pixmap. - Draw the pixmap to the drawable window of this flow graph. """ - - W,H = self.get_size() - hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() - hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active() - - #draw the background - gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR) - window.draw_rectangle(gc, True, 0, 0, W, H) - # draw comments first if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active(): for block in self.blocks: - if hide_variables and (block.is_variable or block.is_import): - continue # skip hidden disabled blocks and connections if block.get_enabled(): - block.draw_comment(gc, window) - #draw multi select rectangle + # block.draw_comment(widget, cr) + pass + # draw multi select rectangle if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): - #coordinates x1, y1 = self.press_coor x2, y2 = self.get_coordinate() - #calculate top-left coordinate and width/height x, y = int(min(x1, x2)), int(min(y1, y2)) w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) - #draw - gc.set_foreground(Colors.HIGHLIGHT_COLOR) - window.draw_rectangle(gc, True, x, y, w, h) - gc.set_foreground(Colors.BORDER_COLOR) - window.draw_rectangle(gc, False, x, y, w, h) - #draw blocks on top of connections + cr.set_source_rgb(*Colors.HIGHLIGHT_COLOR) + cr.rectangle(x, y, w, h) + cr.fill() + cr.set_source_rgb(*Colors.BORDER_COLOR) + cr.rectangle(x, y, w, h) + cr.stroke() + + # draw blocks on top of connections + hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() + hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active() blocks = sorted(self.blocks, key=methodcaller('get_enabled')) + for element in chain(self.connections, blocks): if hide_disabled_blocks and not element.get_enabled(): continue # skip hidden disabled blocks and connections if hide_variables and (element.is_variable or element.is_import): continue # skip hidden disabled blocks and connections - element.draw(gc, window) - #draw selected blocks on top of selected connections + element.draw(widget, cr) + + # draw selected blocks on top of selected connections for selected_element in self.get_selected_connections() + self.get_selected_blocks(): - selected_element.draw(gc, window) + selected_element.draw(widget, cr) def update_selected(self): """ @@ -458,9 +450,9 @@ class FlowGraph(Element, _Flowgraph): for selected in selected_elements: if selected in elements: continue selected_elements.remove(selected) - if self._old_selected_port and self._old_selected_port.get_parent() not in elements: + if self._old_selected_port and self._old_selected_port.parent not in elements: self._old_selected_port = None - if self._new_selected_port and self._new_selected_port.get_parent() not in elements: + if self._new_selected_port and self._new_selected_port.parent not in elements: self._new_selected_port = None #update highlighting for element in elements: @@ -538,7 +530,7 @@ class FlowGraph(Element, _Flowgraph): #update the selected port information if selected_element.is_port: if not coor_m: selected_port = selected_element - selected_element = selected_element.get_parent() + selected_element = selected_element.parent_block selected.add(selected_element) #place at the end of the list self.get_elements().remove(element) @@ -670,7 +662,7 @@ class FlowGraph(Element, _Flowgraph): self.mouse_pressed = True self.update_selected_elements() self.mouse_pressed = False - self._context_menu.popup(None, None, None, event.button, event.time) + self._context_menu.popup(None, None, None, None, event.button, event.time) def handle_mouse_selector_press(self, double_click, coordinate): """ @@ -681,11 +673,12 @@ class FlowGraph(Element, _Flowgraph): """ self.press_coor = coordinate self.set_coordinate(coordinate) - self.time = 0 self.mouse_pressed = True - if double_click: self.unselect() + + if double_click: + self.unselect() self.update_selected_elements() - #double click detected, bring up params dialog if possible + if double_click and self.get_selected_block(): self.mouse_pressed = False Actions.BLOCK_PARAM_MODIFY() @@ -697,69 +690,70 @@ class FlowGraph(Element, _Flowgraph): And update the selected flowgraph elements. """ self.set_coordinate(coordinate) - self.time = 0 self.mouse_pressed = False if self.element_moved: Actions.BLOCK_MOVE() self.element_moved = False self.update_selected_elements() - def handle_mouse_motion(self, coordinate): + def handle_mouse_motion(self, coordinate, button1_pressed): """ The mouse has moved, respond to mouse dragging or notify elements Move a selected element to the new coordinate. Auto-scroll the scroll bars at the boundaries. """ - #to perform a movement, the mouse must be pressed - # (no longer checking pending events via gtk.events_pending() - always true in Windows) - if not self.mouse_pressed: - # only continue if mouse-over stuff is enabled (just the auto-hide port label stuff for now) - if not Actions.TOGGLE_AUTO_HIDE_PORT_LABELS.get_active(): return - redraw = False - for element in reversed(self.get_elements()): - over_element = element.what_is_selected(coordinate) - if not over_element: continue - if over_element != self.element_under_mouse: # over sth new - if self.element_under_mouse: - redraw |= self.element_under_mouse.mouse_out() or False - self.element_under_mouse = over_element - redraw |= over_element.mouse_over() or False - break - else: + # to perform a movement, the mouse must be pressed + # (no longer checking pending events via Gtk.events_pending() - always true in Windows) + if not button1_pressed: + self._handle_mouse_motion_move(coordinate) + else: + self._handle_mouse_motion_drag(coordinate) + + def _handle_mouse_motion_move(self, coordinate): + # only continue if mouse-over stuff is enabled (just the auto-hide port label stuff for now) + if not Actions.TOGGLE_AUTO_HIDE_PORT_LABELS.get_active(): + return + redraw = False + for element in reversed(self.get_elements()): + over_element = element.what_is_selected(coordinate) + if not over_element: + continue + if over_element != self.element_under_mouse: # over sth new if self.element_under_mouse: redraw |= self.element_under_mouse.mouse_out() or False - self.element_under_mouse = None - if redraw: - #self.create_labels() - self.create_shapes() - self.queue_draw() + self.element_under_mouse = over_element + redraw |= over_element.mouse_over() or False + break else: - #perform auto-scrolling - width, height = self.get_size() - x, y = coordinate - h_adj = self.get_scroll_pane().get_hadjustment() - v_adj = self.get_scroll_pane().get_vadjustment() - for pos, length, adj, adj_val, adj_len in ( - (x, width, h_adj, h_adj.get_value(), h_adj.page_size), - (y, height, v_adj, v_adj.get_value(), v_adj.page_size), - ): - #scroll if we moved near the border - if pos-adj_val > adj_len-SCROLL_PROXIMITY_SENSITIVITY and adj_val+SCROLL_DISTANCE < length-adj_len: - adj.set_value(adj_val+SCROLL_DISTANCE) - adj.emit('changed') - elif pos-adj_val < SCROLL_PROXIMITY_SENSITIVITY: - adj.set_value(adj_val-SCROLL_DISTANCE) - 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: - Actions.ELEMENT_DELETE() - #move the selected elements and record the new coordinate - 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 + if self.element_under_mouse: + redraw |= self.element_under_mouse.mouse_out() or False + self.element_under_mouse = None + if redraw: + # self.create_labels() + self.create_shapes() self.queue_draw() + + def _handle_mouse_motion_drag(self, coordinate): + # remove the connection if selected in drag event + 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 = coordinate + 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() + + def get_max_coords(self, initial=(0, 0)): + w, h = initial + for block in self.blocks: + x, y = block.get_coordinate() + w = max(w, x + block.W) + h = max(h, y + block.H) + return w, h |