diff --git a/FlatCAMApp.py b/FlatCAMApp.py index e0c904f9..e7d1d430 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -2670,6 +2670,10 @@ class App(QtCore.QObject): # variable to store mouse coordinates self.mouse = [0, 0] + # variable to store the delta positions on cavnas + self.dx = 0 + self.dy = 0 + # decide if we have a double click or single click self.doubleclick = False @@ -7635,10 +7639,10 @@ class App(QtCore.QObject): self.ui.position_label.setText("    X: %.4f   " "Y: %.4f" % (location[0], location[1])) # Set the relative position label - dx = location[0] - float(self.rel_point1[0]) - dy = location[1] - float(self.rel_point1[1]) + self.dx = location[0] - float(self.rel_point1[0]) + self.dy = location[1] - float(self.rel_point1[1]) self.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.dx, self.dy)) self.inform.emit('[success] %s' % _("Done.")) return location @@ -8823,24 +8827,26 @@ class App(QtCore.QObject): self.ui.position_label.setText("    X: %.4f   " "Y: %.4f" % (pos[0], pos[1])) - dx = pos[0] - float(self.rel_point1[0]) - dy = pos[1] - float(self.rel_point1[1]) + self.dx = pos[0] - float(self.rel_point1[0]) + self.dy = pos[1] - float(self.rel_point1[1]) self.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.dx, self.dy)) self.mouse = [pos[0], pos[1]] # if the mouse is moved and the LMB is clicked then the action is a selection if self.event_is_dragging == 1 and event.button == 1: self.delete_selection_shape() - if dx < 0: + if self.dx < 0: self.draw_moving_selection_shape(self.pos, pos, color=self.defaults['global_alt_sel_line'], face_color=self.defaults['global_alt_sel_fill']) self.selection_type = False - elif dx >= 0: + elif self.dx >= 0: self.draw_moving_selection_shape(self.pos, pos) self.selection_type = True else: self.selection_type = None + else: + self.selection_type = None # hover effect - enabled in Preferences -> General -> GUI Settings if self.defaults['global_hover']: @@ -8940,6 +8946,12 @@ class App(QtCore.QObject): log.warning("FlatCAMApp.on_mouse_click_release_over_plot() double click --> Error: %s" % str(e)) return else: + # WORKAROUND for LEGACY MODE + if self.is_legacy is True: + # if there is no move on canvas then we have no dragging selection + if self.dx == 0 or self.dy == 0: + self.selection_type = None + if self.selection_type is not None: try: self.selection_area_handler(self.pos, pos, self.selection_type) @@ -8948,6 +8960,7 @@ class App(QtCore.QObject): log.warning("FlatCAMApp.on_mouse_click_release_over_plot() select area --> Error: %s" % str(e)) return else: + key_modifier = QtWidgets.QApplication.keyboardModifiers() if key_modifier == QtCore.Qt.ShiftModifier: diff --git a/README.md b/README.md index c20af0e9..c682b260 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ CAD program, and create G-Code for Isolation routing. - made the Grid icon in the status bar clickable and it will toggle the snap to grid function - some mods in the Distance Tool +- added ability to use line width when adding shapes for both Legacy and OpenGL graphic engines +- added the linewidth=2 parameter for the Tool Distance utility geometry +- fixed a selection issue in Legacy graphic mode for single click 19.04.2020 diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py index 02afac5c..313c59a2 100644 --- a/flatcamEditors/FlatCAMExcEditor.py +++ b/flatcamEditors/FlatCAMExcEditor.py @@ -3807,12 +3807,12 @@ class FlatCAMExcEditor(QtCore.QObject): if self.pos is None: self.pos = (0, 0) - dx = x - self.pos[0] - dy = y - self.pos[1] + self.app.dx = x - self.pos[0] + self.app.dy = y - self.pos[1] # update the reference position label in the infobar since the APP mouse event handlers are disconnected self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) # ## Utility geometry (animated) self.update_utility_geometry(data=(x, y)) diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py index cdea92b5..7601cc24 100644 --- a/flatcamEditors/FlatCAMGeoEditor.py +++ b/flatcamEditors/FlatCAMGeoEditor.py @@ -4267,12 +4267,12 @@ class FlatCAMGeoEditor(QtCore.QObject): if self.pos is None: self.pos = (0, 0) - dx = x - self.pos[0] - dy = y - self.pos[1] + self.app.dx = x - self.pos[0] + self.app.dy = y - self.pos[1] # update the reference position label in the infobar since the APP mouse event handlers are disconnected self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser): pass diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py index 1d797d34..c6cd2ed0 100644 --- a/flatcamEditors/FlatCAMGrbEditor.py +++ b/flatcamEditors/FlatCAMGrbEditor.py @@ -4648,12 +4648,12 @@ class FlatCAMGrbEditor(QtCore.QObject): if self.pos is None: self.pos = (0, 0) - dx = x - self.pos[0] - dy = y - self.pos[1] + self.app.dx = x - self.pos[0] + self.app.dy = y - self.pos[1] # update the reference position label in the infobar since the APP mouse event handlers are disconnected self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) self.update_utility_geometry(data=(x, y)) diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py index ed62d9a0..d2136784 100644 --- a/flatcamGUI/PlotCanvasLegacy.py +++ b/flatcamGUI/PlotCanvasLegacy.py @@ -14,7 +14,7 @@ from PyQt5.QtCore import pyqtSignal # Used for solid polygons in Matplotlib from descartes.patch import PolygonPatch -from shapely.geometry import Polygon, LineString, LinearRing, Point, MultiPolygon, MultiLineString +from shapely.geometry import Polygon, LineString, LinearRing import FlatCAMApp @@ -219,7 +219,7 @@ class PlotCanvasLegacy(QtCore.QObject): self.container = container # Plots go onto a single matplotlib.figure - self.figure = Figure(dpi=50) # TODO: dpi needed? + self.figure = Figure(dpi=50) self.figure.patch.set_visible(True) self.figure.set_facecolor(theme_color) @@ -254,7 +254,7 @@ class PlotCanvasLegacy(QtCore.QObject): # self.canvas.set_can_focus(True) # For key press # Attach to parent - # self.container.attach(self.canvas, 0, 0, 600, 400) # TODO: Height and width are num. columns?? + # self.container.attach(self.canvas, 0, 0, 600, 400) self.container.addWidget(self.canvas) # Qt # Copy a bitmap of the canvas for quick animation. @@ -430,7 +430,7 @@ class PlotCanvasLegacy(QtCore.QObject): # Pointer (snapped) # The size of the cursor is multiplied by 1.65 because that value made the cursor similar with the # one in the OpenGL(3D) graphic engine - pointer_size = int(float(self.app.defaults["global_cursor_size"] ) * 1.65) + pointer_size = int(float(self.app.defaults["global_cursor_size"]) * 1.65) elements = self.axes.plot(x, y, '+', color=color, ms=pointer_size, mew=self.app.defaults["global_cursor_width"], animated=True) for el in elements: @@ -946,14 +946,16 @@ class ShapeCollectionLegacy: hold the collection of shapes into a dict self._shapes. This handles the shapes redraw on canvas. """ - def __init__(self, obj, app, name=None, annotation_job=None): + def __init__(self, obj, app, name=None, annotation_job=None, linewidth=1): """ - :param obj: this is the object to which the shapes collection is attached and for + :param obj: This is the object to which the shapes collection is attached and for which it will have to draw shapes - :param app: this is the FLatCAM.App usually, needed because we have to access attributes there - :param name: this is the name given to the Matplotlib axes; it needs to be unique due of Matplotlib requurements - :param annotation_job: make this True if the job needed is just for annotation + :param app: This is the FLatCAM.App usually, needed because we have to access attributes there + :param name: This is the name given to the Matplotlib axes; it needs to be unique due of + Matplotlib requurements + :param annotation_job: Make this True if the job needed is just for annotation + :param linewidth: THe width of the line (outline where is the case) """ self.obj = obj self.app = app @@ -974,6 +976,8 @@ class ShapeCollectionLegacy: self._obj = None self._gcode_parsed = None + self._linewidth = linewidth + if name is None: axes_name = self.obj.options['name'] else: @@ -1005,14 +1009,21 @@ class ShapeCollectionLegacy: :return: """ self._color = color if color is not None else "#006E20" - self._face_color = face_color if face_color is not None else "#BBF268" + # self._face_color = face_color if face_color is not None else "#BBF268" + self._face_color = face_color + + if linewidth is None: + line_width = self._linewidth + else: + line_width = linewidth if len(self._color) > 7: self._color = self._color[:7] - if len(self._face_color) > 7: - self._face_color = self._face_color[:7] - # self._alpha = int(self._face_color[-2:], 16) / 255 + if self._face_color is not None: + if len(self._face_color) > 7: + self._face_color = self._face_color[:7] + # self._alpha = int(self._face_color[-2:], 16) / 255 self._alpha = 0.75 @@ -1037,7 +1048,7 @@ class ShapeCollectionLegacy: self.shape_dict.update({ 'color': self._color, 'face_color': self._face_color, - 'linewidth': linewidth, + 'linewidth': line_width, 'alpha': self._alpha, 'shape': sh }) @@ -1050,7 +1061,7 @@ class ShapeCollectionLegacy: self.shape_dict.update({ 'color': self._color, 'face_color': self._face_color, - 'linewidth': linewidth, + 'linewidth': line_width, 'alpha': self._alpha, 'shape': shape }) @@ -1112,36 +1123,50 @@ class ShapeCollectionLegacy: if obj_type == 'excellon': # Plot excellon (All polygons?) if self.obj.options["solid"] and isinstance(local_shapes[element]['shape'], Polygon): - patch = PolygonPatch(local_shapes[element]['shape'], - facecolor="#C40000", - edgecolor="#750000", - alpha=local_shapes[element]['alpha'], - zorder=3) - self.axes.add_patch(patch) + try: + patch = PolygonPatch(local_shapes[element]['shape'], + facecolor="#C40000", + edgecolor="#750000", + alpha=local_shapes[element]['alpha'], + zorder=3, + linewidth=local_shapes[element]['linewidth'] + ) + self.axes.add_patch(patch) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() excellon poly --> %s" % str(e)) else: - x, y = local_shapes[element]['shape'].exterior.coords.xy - self.axes.plot(x, y, 'r-') - for ints in local_shapes[element]['shape'].interiors: - x, y = ints.coords.xy - self.axes.plot(x, y, 'o-') + try: + x, y = local_shapes[element]['shape'].exterior.coords.xy + self.axes.plot(x, y, 'r-', linewidth=local_shapes[element]['linewidth']) + for ints in local_shapes[element]['shape'].interiors: + x, y = ints.coords.xy + self.axes.plot(x, y, 'o-', linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() excellon no poly --> %s" % str(e)) elif obj_type == 'geometry': if type(local_shapes[element]['shape']) == Polygon: - x, y = local_shapes[element]['shape'].exterior.coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], - linestyle='-', - linewidth=local_shapes[element]['linewidth']) - for ints in local_shapes[element]['shape'].interiors: - x, y = ints.coords.xy + try: + x, y = local_shapes[element]['shape'].exterior.coords.xy self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-', linewidth=local_shapes[element]['linewidth']) + for ints in local_shapes[element]['shape'].interiors: + x, y = ints.coords.xy + self.axes.plot(x, y, local_shapes[element]['color'], + linestyle='-', + linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() geometry poly --> %s" % str(e)) elif type(local_shapes[element]['shape']) == LineString or \ type(local_shapes[element]['shape']) == LinearRing: - x, y = local_shapes[element]['shape'].coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], - linestyle='-', - linewidth=local_shapes[element]['linewidth']) + try: + x, y = local_shapes[element]['shape'].coords.xy + self.axes.plot(x, y, local_shapes[element]['color'], + linestyle='-', + linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() geometry no poly --> %s" % str(e)) elif obj_type == 'gerber': if self.obj.options["multicolored"]: linespec = '-' @@ -1161,47 +1186,60 @@ class ShapeCollectionLegacy: facecolor=gerber_fill_color, edgecolor=gerber_outline_color, alpha=local_shapes[element]['alpha'], - zorder=2) + zorder=2, + linewidth=local_shapes[element]['linewidth']) self.axes.add_patch(patch) except AssertionError: FlatCAMApp.App.log.warning("A geometry component was not a polygon:") FlatCAMApp.App.log.warning(str(element)) except Exception as e: - FlatCAMApp.App.log.debug("PlotCanvasLegacy.ShepeCollectionLegacy.redraw() --> %s" % str(e)) + FlatCAMApp.App.log.debug( + "PlotCanvasLegacy.ShepeCollectionLegacy.redraw() gerber 'solid' --> %s" % str(e)) else: - x, y = local_shapes[element]['shape'].exterior.xy - self.axes.plot(x, y, linespec) - for ints in local_shapes[element]['shape'].interiors: - x, y = ints.coords.xy - self.axes.plot(x, y, linespec) + try: + x, y = local_shapes[element]['shape'].exterior.xy + self.axes.plot(x, y, linespec, linewidth=local_shapes[element]['linewidth']) + for ints in local_shapes[element]['shape'].interiors: + x, y = ints.coords.xy + self.axes.plot(x, y, linespec, linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() gerber no 'solid' --> %s" % str(e)) elif obj_type == 'cncjob': if local_shapes[element]['face_color'] is None: - linespec = '--' - linecolor = local_shapes[element]['color'] - # if geo['kind'][0] == 'C': - # linespec = 'k-' - x, y = local_shapes[element]['shape'].coords.xy - self.axes.plot(x, y, linespec, color=linecolor) + try: + linespec = '--' + linecolor = local_shapes[element]['color'] + # if geo['kind'][0] == 'C': + # linespec = 'k-' + x, y = local_shapes[element]['shape'].coords.xy + self.axes.plot(x, y, linespec, color=linecolor, + linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() cncjob with face_color --> %s" % str(e)) else: - path_num += 1 - if self.obj.ui.annotation_cb.get_value(): - if isinstance(local_shapes[element]['shape'], Polygon): - self.axes.annotate( - str(path_num), - xy=local_shapes[element]['shape'].exterior.coords[0], - xycoords='data', fontsize=20) - else: - self.axes.annotate( - str(path_num), - xy=local_shapes[element]['shape'].coords[0], - xycoords='data', fontsize=20) + try: + path_num += 1 + if self.obj.ui.annotation_cb.get_value(): + if isinstance(local_shapes[element]['shape'], Polygon): + self.axes.annotate( + str(path_num), + xy=local_shapes[element]['shape'].exterior.coords[0], + xycoords='data', fontsize=20) + else: + self.axes.annotate( + str(path_num), + xy=local_shapes[element]['shape'].coords[0], + xycoords='data', fontsize=20) - patch = PolygonPatch(local_shapes[element]['shape'], - facecolor=local_shapes[element]['face_color'], - edgecolor=local_shapes[element]['color'], - alpha=local_shapes[element]['alpha'], zorder=2) - self.axes.add_patch(patch) + patch = PolygonPatch(local_shapes[element]['shape'], + facecolor=local_shapes[element]['face_color'], + edgecolor=local_shapes[element]['color'], + alpha=local_shapes[element]['alpha'], zorder=2, + linewidth=local_shapes[element]['linewidth']) + self.axes.add_patch(patch) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() cncjob no face_color --> %s" % str(e)) elif obj_type == 'utility': # not a FlatCAM object, must be utility if local_shapes[element]['face_color']: @@ -1210,26 +1248,35 @@ class ShapeCollectionLegacy: facecolor=local_shapes[element]['face_color'], edgecolor=local_shapes[element]['color'], alpha=local_shapes[element]['alpha'], - zorder=2) + zorder=2, + linewidth=local_shapes[element]['linewidth']) self.axes.add_patch(patch) except Exception as e: - log.debug("ShapeCollectionLegacy.redraw() --> %s" % str(e)) + log.debug("ShapeCollectionLegacy.redraw() utility poly with face_color --> %s" % str(e)) else: if isinstance(local_shapes[element]['shape'], Polygon): - ext_shape = local_shapes[element]['shape'].exterior - if ext_shape is not None: - x, y = ext_shape.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') - for ints in local_shapes[element]['shape'].interiors: - if ints is not None: - x, y = ints.coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') + try: + ext_shape = local_shapes[element]['shape'].exterior + if ext_shape is not None: + x, y = ext_shape.xy + self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-', + linewidth=local_shapes[element]['linewidth']) + for ints in local_shapes[element]['shape'].interiors: + if ints is not None: + x, y = ints.coords.xy + self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-', + linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() utility poly no face_color --> %s" % str(e)) else: - if local_shapes[element]['shape'] is not None: - x, y = local_shapes[element]['shape'].coords.xy - self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-') - + try: + if local_shapes[element]['shape'] is not None: + x, y = local_shapes[element]['shape'].coords.xy + self.axes.plot(x, y, local_shapes[element]['color'], linestyle='-', + linewidth=local_shapes[element]['linewidth']) + except Exception as e: + log.debug("ShapeCollectionLegacy.redraw() utility lines no face_color --> %s" % str(e)) self.app.plotcanvas.auto_adjust_axes() def set(self, text, pos, visible=True, font_size=16, color=None): diff --git a/flatcamGUI/VisPyVisuals.py b/flatcamGUI/VisPyVisuals.py index e881e5c9..d6f19d3b 100644 --- a/flatcamGUI/VisPyVisuals.py +++ b/flatcamGUI/VisPyVisuals.py @@ -193,10 +193,10 @@ class ShapeGroup(object): class ShapeCollectionVisual(CompoundVisual): - def __init__(self, line_width=1, triangulation='vispy', layers=3, pool=None, **kwargs): + def __init__(self, linewidth=1, triangulation='vispy', layers=3, pool=None, **kwargs): """ Represents collection of shapes to draw on VisPy scene - :param line_width: float + :param linewidth: float Width of lines/edges :param triangulation: str Triangulation method used for polygons translation @@ -223,7 +223,7 @@ class ShapeCollectionVisual(CompoundVisual): # self._lines = [LineVisual(antialias=True) for _ in range(0, layers)] self._lines = [FlatCAMLineVisual(antialias=True) for _ in range(0, layers)] - self._line_width = line_width + self._line_width = linewidth self._triangulation = triangulation visuals_ = [self._lines[i // 2] if i % 2 else self._meshes[i // 2] for i in range(0, layers * 2)] @@ -262,7 +262,7 @@ class ShapeCollectionVisual(CompoundVisual): :param tolerance: float Geometry simplifying tolerance :param linewidth: int - Not used, for compatibility + Width of the line :return: int Index of shape """ @@ -276,6 +276,9 @@ class ShapeCollectionVisual(CompoundVisual): self.data[key] = {'geometry': shape, 'color': color, 'alpha': alpha, 'face_color': face_color, 'visible': visible, 'layer': layer, 'tolerance': tolerance} + if linewidth: + self._line_width = linewidth + # Add data to process pool if pool exists try: self.results[key] = self.pool.map_async(_update_shape_buffers, [self.data[key]]) @@ -459,7 +462,7 @@ class ShapeCollectionVisual(CompoundVisual): self.update_lock.acquire(True) # Merge shapes buffers - for data in list(self.data.values()): + for data in self.data.values(): if data['visible'] and 'line_pts' in data: try: line_pts[data['layer']] += data['line_pts'] diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py index 9b1bc968..99c2a443 100644 --- a/flatcamTools/ToolCopperThieving.py +++ b/flatcamTools/ToolCopperThieving.py @@ -917,10 +917,10 @@ class ToolCopperThieving(FlatCAMTool): if self.cursor_pos is None: self.cursor_pos = (0, 0) - dx = curr_pos[0] - float(self.cursor_pos[0]) - dy = curr_pos[1] - float(self.cursor_pos[1]) + self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) + self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if self.first_click: diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py index 09c4cce7..61c4df42 100644 --- a/flatcamTools/ToolDistance.py +++ b/flatcamTools/ToolDistance.py @@ -598,7 +598,7 @@ class Distance(FlatCAMTool): else: color = '#FFFFFFFF' - self.sel_shapes.add(meas_line, color=color, update=True, layer=0, tolerance=None) + self.sel_shapes.add(meas_line, color=color, update=True, layer=0, tolerance=None, linewidth=2) if self.app.is_legacy is True: self.sel_shapes.redraw() diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py index 7b44ebdf..ed43f9f3 100644 --- a/flatcamTools/ToolNCC.py +++ b/flatcamTools/ToolNCC.py @@ -1835,10 +1835,10 @@ class NonCopperClear(FlatCAMTool, Gerber): if self.cursor_pos is None: self.cursor_pos = (0, 0) - dx = curr_pos[0] - float(self.cursor_pos[0]) - dy = curr_pos[1] - float(self.cursor_pos[1]) + self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) + self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if shape_type == "square": diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py index 9e955766..f0179501 100644 --- a/flatcamTools/ToolPaint.py +++ b/flatcamTools/ToolPaint.py @@ -1718,10 +1718,10 @@ class ToolPaint(FlatCAMTool, Gerber): if self.cursor_pos is None: self.cursor_pos = (0, 0) - dx = curr_pos[0] - float(self.cursor_pos[0]) - dy = curr_pos[1] - float(self.cursor_pos[1]) + self.app.dx = curr_pos[0] - float(self.cursor_pos[0]) + self.app.dy = curr_pos[1] - float(self.cursor_pos[1]) self.app.ui.rel_position_label.setText("Dx: %.4f   Dy: " - "%.4f    " % (dx, dy)) + "%.4f    " % (self.app.dx, self.app.dy)) # draw the utility geometry if shape_type == "square":