diff --git a/README.md b/README.md index d9ed7ed0..943ee0f4 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,10 @@ CAD program, and create G-Code for Isolation routing. 24.09.2019 - fixed the fullscreen method to show the application window in fullscreen wherever the mouse pointer it is therefore on the screen we are working on; before it was showing always on the primary screen +- fixed setup_ubuntu.sh to include the matplotlib package required by the Legacy (2D) graphic engine +- in legacy graphic engine, fixed issue where immediately after changing the mouse cursor snapping the mouse cursor shape was not updated +- in legacy graphic engine, fixed issue where while zooming the mouse cursor shape was not updated +- in legacy graphic engine, fixed issue where immediately after panning finished the mouse cursor shape was not updated 23.09.2019 diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py index 65981b98..a2018692 100644 --- a/flatcamGUI/PlotCanvasLegacy.py +++ b/flatcamGUI/PlotCanvasLegacy.py @@ -8,12 +8,13 @@ ############################################################ from PyQt5 import QtGui, QtCore, QtWidgets +from PyQt5.QtCore import pyqtSignal # Prevent conflict with Qt5 and above. from matplotlib import use as mpl_use mpl_use("Qt5Agg") from matplotlib.figure import Figure -from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.widgets import Cursor @@ -26,6 +27,7 @@ from shapely.geometry import Polygon, LineString, LinearRing, Point, MultiPolygo import FlatCAMApp from copy import deepcopy import logging +import traceback import gettext import FlatCAMTranslation as fcTranslate @@ -113,6 +115,33 @@ class CanvasCache(QtCore.QObject): # log.debug("A new object is available. Should plot it!") +class FigureCanvas(FigureCanvasQTAgg): + """ + Reimplemented this so I can emit a signal when the idle drawing is finished and display the mouse shape + """ + + idle_drawing_finished = pyqtSignal() + + def __init__(self, figure): + super().__init__(figure=figure) + + def _draw_idle(self): + if self.height() < 0 or self.width() < 0: + self._draw_pending = False + if not self._draw_pending: + return + try: + self.draw() + except Exception: + # Uncaught exceptions are fatal for PyQt5, so catch them instead. + traceback.print_exc() + finally: + self._draw_pending = False + + # I reimplemented this class only to launch this signal + self.idle_drawing_finished.emit() + + class PlotCanvasLegacy(QtCore.QObject): """ Class handling the plotting area in the application. @@ -209,6 +238,9 @@ class PlotCanvasLegacy(QtCore.QObject): # signal if there is a doubleclick self.is_dblclk = False + # pay attention, this signal should be connected only after the self.canvas and self.mouse is declared + self.canvas.idle_drawing_finished.connect(lambda: self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1])) + def graph_event_connect(self, event_name, callback): """ Attach an event handler to the canvas through the Matplotlib interface. @@ -256,9 +288,20 @@ class PlotCanvasLegacy(QtCore.QObject): # c = MplCursor(axes=axes, color='black', linewidth=1) c = FakeCursor() - + try: + c.mouse_state_updated.connect(self.clear_cursor) + except Exception as e: + print(str(e)) return c + def clear_cursor(self, state): + + if state is True: + self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1]) + else: + self.canvas.restore_region(self.background) + self.canvas.blit(self.axes.bbox) + def on_key_down(self, event): """ @@ -571,9 +614,12 @@ class PlotCanvasLegacy(QtCore.QObject): # Clear pan flag self.panning = False + # And update the cursor + self.draw_cursor(x_pos=self.mouse[0], y_pos=self.mouse[1]) + def on_mouse_move(self, event): """ - Mouse movement event hadler. Stores the coordinates. Updates view on pan. + Mouse movement event handler. Stores the coordinates. Updates view on pan. :param event: Contains information about the event. :return: None @@ -591,23 +637,44 @@ class PlotCanvasLegacy(QtCore.QObject): # Update pan view on mouse move if self.panning is True: - # x_pan, y_pan = self.app.geo_editor.snap(event.xdata, event.ydata) - # self.app.app_cursor.set_data(event, (x_pan, y_pan)) for a in self.pan_axes: a.drag_pan(1, event.key, event.x, event.y) + # x_pan, y_pan = self.app.geo_editor.snap(event.xdata, event.ydata) + # self.draw_cursor(x_pos=x_pan, y_pos=y_pan) + # Async re-draw (redraws only on thread idle state, uses timer on backend) self.canvas.draw_idle() # #### Temporary place-holder for cached update ##### self.update_screen_request.emit([0, 0, 0, 0, 0]) - x, y = self.app.geo_editor.snap(x, y) - if self.app.app_cursor.enabled is True: - # Pointer (snapped) - elements = self.axes.plot(x, y, 'k+', ms=40, mew=2, animated=True) - for el in elements: - self.axes.draw_artist(el) + self.draw_cursor(x_pos=x, y_pos=y) + + # self.canvas.blit(self.axes.bbox) + + def draw_cursor(self, x_pos, y_pos): + """ + Draw a cursor at the mouse grid snapped position + + :param x_pos: mouse x position + :param y_pos: mouse y position + :return: + """ + # there is no point in drawing mouse cursor when panning as it jumps in a confusing way + if self.app.app_cursor.enabled is True and self.panning is False: + try: + x, y = self.app.geo_editor.snap(x_pos, y_pos) + + # Pointer (snapped) + elements = self.axes.plot(x, y, 'k+', ms=40, mew=2, animated=True) + for el in elements: + self.axes.draw_artist(el) + except Exception as e: + # this happen at app initialization since self.app.geo_editor does not exist yet + # I could reshuffle the object instantiating order but what's the point? I could crash something else + # and that's pythonic, too + pass self.canvas.blit(self.axes.bbox) @@ -656,13 +723,17 @@ class PlotCanvasLegacy(QtCore.QObject): return width / xpx, height / ypx -class FakeCursor: +class FakeCursor(QtCore.QObject): """ This is a fake cursor to ensure compatibility with the OpenGL engine (VisPy). This way I don't have to chane (disable) things related to the cursor all over when using the low performance Matplotlib 2D graphic engine. """ + + mouse_state_updated = pyqtSignal(bool) + def __init__(self): + super().__init__() self._enabled = True @property @@ -672,6 +743,7 @@ class FakeCursor: @enabled.setter def enabled(self, value): self._enabled = value + self.mouse_state_updated.emit(value) def set_data(self, pos, **kwargs): """Internal event handler to draw the cursor when the mouse moves.""" diff --git a/setup_ubuntu.sh b/setup_ubuntu.sh index 0ae427a2..a3711cd3 100644 --- a/setup_ubuntu.sh +++ b/setup_ubuntu.sh @@ -29,4 +29,5 @@ pip3 install --upgrade freetype-py pip3 install --upgrade fontTools pip3 install --upgrade rasterio pip3 install --upgrade lxml -pip3 install --upgrade ezdxf \ No newline at end of file +pip3 install --upgrade ezdxf +pip3 install --upgrade matplotlib \ No newline at end of file