diff options
author | Sebastian Koslowski <koslowski@kit.edu> | 2016-07-07 16:30:33 +0200 |
---|---|---|
committer | Sebastian Koslowski <koslowski@kit.edu> | 2016-07-13 16:35:49 +0200 |
commit | 5cef62d03e3a750bce7f180930ceb777f7dba6b2 (patch) | |
tree | f6f5996cdbe60a497a28ae27226aebb220f31ee7 /grc | |
parent | 74e7af6cd0eb5e2f3892b42f08b0089ed2f2fec0 (diff) |
grc: gtk3: refactor and update draw code WIP
Diffstat (limited to 'grc')
-rw-r--r-- | grc/gui/Block.py | 32 | ||||
-rw-r--r-- | grc/gui/Connection.py | 26 | ||||
-rw-r--r-- | grc/gui/Element.py | 76 | ||||
-rw-r--r-- | grc/gui/FlowGraph.py | 76 | ||||
-rw-r--r-- | grc/gui/Port.py | 26 |
5 files changed, 115 insertions, 121 deletions
diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 225881fec8..a38e4cc59a 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -41,7 +41,7 @@ class Block(Element, _Block): def __init__(self, flow_graph, n): """ - Block contructor. + Block constructor. Add graphics related params to the block. """ _Block.__init__(self, flow_graph, n) @@ -113,8 +113,10 @@ class Block(Element, _Block): def create_shapes(self): """Update the block, parameters, and ports when a change occurs.""" 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)) + 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) def create_labels(self): """Create the labels for the signal block.""" @@ -205,31 +207,30 @@ class Block(Element, _Block): """ Draw the signal block with label and inputs/outputs. """ - # draw ports - for port in self.get_ports_gui(): - port.draw(widget, cr) # draw main block + bg_color = self._bg_color border_color = ( Colors.HIGHLIGHT_COLOR if self.is_highlighted() else Colors.MISSING_BLOCK_BORDER_COLOR if self.is_dummy_block else Colors.BORDER_COLOR ) - Element.draw(self, widget, cr, border_color, self._bg_color) - x, y = self.get_coordinate() - # create the image surface + + for port in self.get_ports_gui(): + cr.save() + port.draw(widget, cr, border_color, bg_color) + cr.restore() + Element.draw(self, widget, cr, border_color, bg_color) + + # create the param label width = self.label_width cr.set_source_rgb(*self._bg_color) - cr.save() if self.is_horizontal(): - cr.translate(x + BLOCK_LABEL_PADDING, y + (self.H - self.label_height) / 2) + cr.translate(BLOCK_LABEL_PADDING, (self.H - self.label_height) / 2) elif self.is_vertical(): - cr.translate(x + (self.H - self.label_height) / 2, y + BLOCK_LABEL_PADDING) + cr.translate((self.H - self.label_height) / 2, BLOCK_LABEL_PADDING) cr.rotate(-90 * math.pi / 180.) cr.translate(-width, 0) - # cr.rectangle(0, 0, width, height) - # cr.fill() - # draw the layouts h_off = 0 for i, layout in enumerate(self._param_layouts): @@ -243,7 +244,6 @@ class Block(Element, _Block): PangoCairo.show_layout(cr, layout) cr.translate(-w_off, -h_off) h_off += h + LABEL_SEPARATION - cr.restore() def what_is_selected(self, coor, coor_m=None): """ diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index b1a22e3949..ce40a3b036 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -42,7 +42,6 @@ class Connection(Element, _Connection): def __init__(self, **kwargs): Element.__init__(self) _Connection.__init__(self, **kwargs) - # can't use Colors.CONNECTION_ENABLED_COLOR here, might not be defined (grcc) self._bg_color = self._arrow_color = self._color = None self._sink_rot = self._source_rot = None @@ -112,16 +111,14 @@ class Connection(Element, _Connection): self.clear() #source connector source = self.source_port - X, Y = source.get_connector_coordinate() - x1, y1 = self.x1 + X, self.y1 + Y - self.add_line((x1, y1), (X, Y)) + x0, y0 = p0 = source.get_connector_coordinate() + x1, y1 = p1 = self.x1 + x0, self.y1 + y0 #sink connector sink = self.sink_port - X, Y = sink.get_connector_coordinate() - x2, y2 = self.x2 + X, self.y2 + Y - self.add_line((x2, y2), (X, Y)) + x3, y3 = p3 = sink.get_connector_coordinate() + x2, y2 = p2 = self.x2 + x3, self.y2 + y3 #adjust arrow - self._arrow = [(x+X, y+Y) for x, y in self.arrow] + self._arrow = [(x + x3, y + y3) for x, y in self.arrow] #add the horizontal and vertical lines in this connection if abs(source.get_connector_direction() - sink.get_connector_direction()) == 180: #2 possible point sets to create a 3-line connector @@ -133,11 +130,9 @@ class Connection(Element, _Connection): if Utils.get_angle_from_coordinates(points[0][0], (x2, y2)) == sink.get_connector_direction(): points.reverse() #points[0][0] -> source connector should not be in the direction of source if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse() - #create 3-line connector - p1, p2 = list(map(int, points[0][0])), list(map(int, points[0][1])) - self.add_line((x1, y1), p1) - self.add_line(p1, p2) - self.add_line((x2, y2), p2) + # create 3-line connector + i1, i2 = list(map(int, points[0][0])), list(map(int, points[0][1])) + self.add_line(p0, p1, i1, i2, p2, p3) else: #2 possible points to create a right-angled connector points = [(x1, y2), (x2, y1)] @@ -148,8 +143,8 @@ class Connection(Element, _Connection): #points[0] -> source connector should not be in the direction of source if Utils.get_angle_from_coordinates(points[0], (x1, y1)) == source.get_connector_direction(): points.reverse() #create right-angled connector - self.add_line((x1, y1), points[0]) - self.add_line((x2, y2), points[0]) + i1 = points[0] + self.add_line(p0, p1, i1, p2, p3) def draw(self, widget, cr): """ @@ -176,6 +171,7 @@ class Connection(Element, _Connection): Colors.CONNECTION_DISABLED_COLOR if not self.get_enabled() else color ) + cr.set_dash([5, 5], 0.0) Element.draw(self, widget, cr, mod_color(self._color), mod_color(self._bg_color)) # draw arrow on sink port cr.set_source_rgb(*self._arrow_color) diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 48fdf62543..c4d5b5e47d 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -42,7 +42,7 @@ class Element(object): self.set_rotation(POSSIBLE_ROTATIONS[0]) self.set_coordinate((0, 0)) self.clear() - self.set_highlighted(False) + self.highlighted = False self.line_attributes = [] """ # No idea where this is in pygobject 0, Gdk.LINE_SOLID, Gdk.CAP_BUTT, Gdk.JOIN_MITER @@ -102,21 +102,22 @@ class Element(object): bg_color: the color for the inside of the rectangle """ X, Y = self.get_coordinate() - # TODO: gc.set_line_attributes(*self.line_attributes) - for (rX, rY), (W, H) in self._areas_list: - aX = X + rX - aY = Y + rY + cr.translate(X, Y) + for area in self._areas_list: + # aX = X + rX + # aY = Y + rY cr.set_source_rgb(*bg_color) - cr.rectangle(aX, aY, W, H) + cr.rectangle(*area) cr.fill() cr.set_source_rgb(*border_color) - cr.rectangle(aX, aY, W, H) + cr.rectangle(*area) cr.stroke() - for (x1, y1), (x2, y2) in self._lines_list: - cr.set_source_rgb(*border_color) - cr.move_to(X + x1, Y + y1) - cr.line_to(X + x2, Y + y2) + cr.set_source_rgb(*border_color) + for line in self._lines_list: + cr.move_to(*line[0]) + for point in line[1:]: + cr.line_to(*point) cr.stroke() def rotate(self, rotation): @@ -142,15 +143,6 @@ class Element(object): """ self.coor = coor - # def get_parent(self): - # """ - # Get the parent of this element. - # - # Returns: - # the parent - # """ - # return self.parent - def set_highlighted(self, highlighted): """ Set the highlight status. @@ -188,7 +180,7 @@ class Element(object): X, Y = self.get_coordinate() self.set_coordinate((X+deltaX, Y+deltaY)) - def add_area(self, rel_coor, area): + def add_area(self, x, y, w, h): """ Add an area to the area list. An area is actually a coordinate relative to the main coordinate @@ -196,25 +188,17 @@ 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. - - Args: - rel_coor: (x,y) offset from this element's coordinate - area: (width,height) tuple """ - self._areas_list.append((rel_coor, area)) + self._areas_list.append([x, y, w, h]) - def add_line(self, rel_coor1, rel_coor2): + def add_line(self, *points): """ Add a line to the line list. - A line is defined by 2 relative coordinates. + A line is defined by 2 or more relative coordinates. Lines must be horizontal or vertical. The line is associated with a rotation. - - Args: - rel_coor1: relative (x1,y1) tuple - rel_coor2: relative (x2,y2) tuple """ - self._lines_list.append((rel_coor1, rel_coor2)) + self._lines_list.append(points) def what_is_selected(self, coor, coor_m=None): """ @@ -239,27 +223,33 @@ 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_list: + 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_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 + for line in self._lines_list: + last_point = line[0] + for x2, y2 in line[1:]: + (x1, y1), last_point = last_point, (x2, y2) + 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_list: + 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_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 + for line in self._lines_list: + last_point = line[0] + for x2, y2 in line[1:]: + (x1, y1), last_point = last_point, (x2, y2) + 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 return None def get_rotation(self): diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 77615f13b0..dc80a4c87e 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -22,14 +22,11 @@ from __future__ import absolute_import import functools import random from distutils.spawn import find_executable -from itertools import chain, count -from operator import methodcaller +from itertools import count import six from six.moves import filter -from gi.repository import GObject - from . import Actions, Colors, Utils, Bars, Dialogs from .Element import Element from .external_editor import ExternalEditor @@ -67,7 +64,9 @@ class FlowGraph(Element, _Flowgraph): #context menu self._context_menu = Bars.ContextMenu() self.get_context_menu = lambda: self._context_menu + self._elements_to_draw = [] + self._elements_to_draw = [] self._external_updaters = {} def _get_unique_id(self, base_id=''): @@ -199,6 +198,7 @@ class FlowGraph(Element, _Flowgraph): Args: clipboard: the nested data of blocks, connections """ + # todo: rewrite this... selected = set() (x_min, y_min), blocks_n, connections_n = clipboard old_id2block = dict() @@ -400,44 +400,58 @@ class FlowGraph(Element, _Flowgraph): changed = True return changed + def update_elements_to_draw(self): + hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() + hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active() + + def draw_order(elem): + return elem.highlighted, elem.is_block, elem.get_enabled() + + elements = sorted(self.get_elements(), key=draw_order) + del self._elements_to_draw[:] + + for element in elements: + 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 + self._elements_to_draw.append(element) + + def _drawables(self): + show_comments = Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active() + for element in self._elements_to_draw: + if element.is_block and show_comments and element.get_enabled(): + yield element.draw_comment + for element in self._elements_to_draw: + yield element.draw + def draw(self, widget, cr): - """ - Draw the background and grid if enabled. - """ - # draw comments first - if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active(): - for block in self.blocks: - if block.get_enabled(): - block.draw_comment(widget, cr) + """Draw blocks connections comment and select rectangle""" + # todo: only update if required, duplicate logic in + self.update_elements_to_draw() + + for draw_element in self._drawables(): + cr.save() + draw_element(widget, cr) + cr.restore() + # draw multi select rectangle - if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): + if self.mouse_pressed and (not self.selected_elements or self.get_ctrl_mask()): x1, y1 = self.press_coor x2, y2 = self.get_coordinate() x, y = int(min(x1, x2)), int(min(y1, y2)) w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) - cr.set_source_rgb(*Colors.HIGHLIGHT_COLOR) + cr.set_source_rgba( + Colors.HIGHLIGHT_COLOR[0], + Colors.HIGHLIGHT_COLOR[1], + Colors.HIGHLIGHT_COLOR[2], + 0.5, + ) 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(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(widget, cr) - def update_selected(self): """ Remove deleted elements from the selected elements list. diff --git a/grc/gui/Port.py b/grc/gui/Port.py index 62086c76e4..8945aa8c28 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -106,22 +106,22 @@ class Port(_Port, Element): if (self.is_sink and rotation == 0) or (self.is_source and rotation == 180): x = -W y = port_separation*index+offset - self.add_area((x, y), (W, self.H)) + 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.parent.W y = port_separation*index+offset - self.add_area((x, y), (W, self.H)) + 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 = -W x = port_separation*index+offset - self.add_area((x, y), (self.H, W)) + 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.parent.W x = port_separation*index+offset - self.add_area((x, y), (self.H, W)) + self.add_area(x, y, self.H, W) self._connector_coordinate = (x+self.H/2, y+1+W) #the connector length self.connector_length = Constants.CONNECTOR_EXTENSION_MINIMAL + Constants.CONNECTOR_EXTENSION_INCREMENT * index @@ -132,32 +132,26 @@ class Port(_Port, Element): name=Utils.encode(self.get_name()), font=Constants.PORT_FONT )) - def draw(self, widget, cr): + def draw(self, widget, cr, border_color, bg_color): """ Draw the socket with a label. """ - border_color = ( - Colors.HIGHLIGHT_COLOR if self.is_highlighted() else - Colors.MISSING_BLOCK_BORDER_COLOR if self.parent.is_dummy_block else - Colors.BORDER_COLOR - ) Element.draw(self, widget, cr, border_color, self._bg_color) if not self._areas_list or self._label_hidden(): return # this port is either hidden (no areas) or folded (no label) - X, Y = self.get_coordinate() - (x, y), _ = self._areas_list[0] + + x, y, _, __ = self._areas_list[0] + cr.set_source_rgb(*self._bg_color) - cr.save() if self.is_horizontal(): - cr.translate(x + X + (self.W - self.w) / 2, y + Y + (self.H - self.h) / 2) + cr.translate(x + (self.W - self.w) / 2, y + (self.H - self.h) / 2) elif self.is_vertical(): - cr.translate(x + X + (self.H - self.h) / 2, y + Y + (self.W - self.w) / 2) + cr.translate(x + (self.H - self.h) / 2, y + (self.W - self.w) / 2) cr.rotate(-90 * math.pi / 180.) cr.translate(-self.w, 0) PangoCairo.update_layout(cr, self.layout) PangoCairo.show_layout(cr, self.layout) - cr.restore() def get_connector_coordinate(self): """ |