- unfortunately the fix for issue where while zooming the mouse cursor shape was not updated braked something in way that Matplotlib work with PyQt5, therefore I removed it
This commit is contained in:
@@ -10,14 +10,6 @@
|
||||
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
|
||||
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||
from matplotlib.widgets import Cursor
|
||||
|
||||
# needed for legacy mode
|
||||
# Used for solid polygons in Matplotlib
|
||||
from descartes.patch import PolygonPatch
|
||||
@@ -25,14 +17,21 @@ from descartes.patch import PolygonPatch
|
||||
from shapely.geometry import Polygon, LineString, LinearRing, Point, MultiPolygon, MultiLineString
|
||||
|
||||
import FlatCAMApp
|
||||
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
# 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.widgets import Cursor
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
@@ -78,7 +77,7 @@ class CanvasCache(QtCore.QObject):
|
||||
self.axes.set_xticks([])
|
||||
self.axes.set_yticks([])
|
||||
|
||||
self.canvas = FigureCanvasAgg(self.figure)
|
||||
self.canvas = FigureCanvas(self.figure)
|
||||
|
||||
self.cache = None
|
||||
|
||||
@@ -115,33 +114,6 @@ 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.
|
||||
@@ -151,6 +123,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
# Request for new bitmap to display. The parameter
|
||||
# is a list with [xmin, xmax, ymin, ymax, zoom(optional)]
|
||||
update_screen_request = QtCore.pyqtSignal(list)
|
||||
|
||||
double_click = QtCore.pyqtSignal(object)
|
||||
|
||||
def __init__(self, container, app):
|
||||
@@ -188,6 +161,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
|
||||
# The canvas is the top level container (FigureCanvasQTAgg)
|
||||
self.canvas = FigureCanvas(self.figure)
|
||||
|
||||
self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
self.canvas.setFocus()
|
||||
self.native = self.canvas
|
||||
@@ -203,15 +177,17 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
# Update every time the canvas is re-drawn.
|
||||
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
|
||||
|
||||
# ################### NOT IMPLEMENTED YET - EXPERIMENTAL #######################
|
||||
# ## Bitmap Cache
|
||||
self.cache = CanvasCache(self, self.app)
|
||||
self.cache_thread = QtCore.QThread()
|
||||
self.cache.moveToThread(self.cache_thread)
|
||||
# super(PlotCanvas, self).connect(self.cache_thread, QtCore.SIGNAL("started()"), self.cache.run)
|
||||
self.cache_thread.started.connect(self.cache.run)
|
||||
|
||||
self.cache_thread.start()
|
||||
self.cache.new_screen.connect(self.on_new_screen)
|
||||
# self.cache = CanvasCache(self, self.app)
|
||||
# self.cache_thread = QtCore.QThread()
|
||||
# self.cache.moveToThread(self.cache_thread)
|
||||
# # super(PlotCanvas, self).connect(self.cache_thread, QtCore.SIGNAL("started()"), self.cache.run)
|
||||
# self.cache_thread.started.connect(self.cache.run)
|
||||
#
|
||||
# self.cache_thread.start()
|
||||
# self.cache.new_screen.connect(self.on_new_screen)
|
||||
# ##############################################################################
|
||||
|
||||
# Events
|
||||
self.mp = self.graph_event_connect('button_press_event', self.on_mouse_press)
|
||||
@@ -226,11 +202,11 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
# self.graph_event_connect('key_release_event', self.on_key_up)
|
||||
self.odr = self.graph_event_connect('draw_event', self.on_draw)
|
||||
|
||||
self.mouse = [0, 0]
|
||||
self.key = None
|
||||
|
||||
self.pan_axes = []
|
||||
self.panning = False
|
||||
self.mouse = [0, 0]
|
||||
|
||||
# signal is the mouse is dragging
|
||||
self.is_dragging = False
|
||||
@@ -238,9 +214,6 @@ 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.
|
||||
@@ -294,6 +267,31 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
print(str(e))
|
||||
return c
|
||||
|
||||
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)
|
||||
|
||||
def clear_cursor(self, state):
|
||||
|
||||
if state is True:
|
||||
@@ -653,31 +651,6 @@ class PlotCanvasLegacy(QtCore.QObject):
|
||||
|
||||
# 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)
|
||||
|
||||
def translate_coords(self, position):
|
||||
"""
|
||||
This does not do much. It's just for code compatibility
|
||||
@@ -750,66 +723,6 @@ class FakeCursor(QtCore.QObject):
|
||||
pass
|
||||
|
||||
|
||||
class MplCursor(Cursor):
|
||||
"""
|
||||
Unfortunately this gets attached to the current axes and if a new axes is added
|
||||
it will not be showed until that axes is deleted.
|
||||
Not the kind of behavior needed here so I don't use it anymore.
|
||||
"""
|
||||
def __init__(self, axes, color='red', linewidth=1):
|
||||
|
||||
super().__init__(ax=axes, useblit=True, color=color, linewidth=linewidth)
|
||||
self._enabled = True
|
||||
|
||||
self.axes = axes
|
||||
self.color = color
|
||||
self.linewidth = linewidth
|
||||
|
||||
self.x = None
|
||||
self.y = None
|
||||
|
||||
@property
|
||||
def enabled(self):
|
||||
return True if self._enabled else False
|
||||
|
||||
@enabled.setter
|
||||
def enabled(self, value):
|
||||
self._enabled = value
|
||||
self.visible = self._enabled
|
||||
self.canvas.draw()
|
||||
|
||||
def onmove(self, event):
|
||||
pass
|
||||
|
||||
def set_data(self, event, pos):
|
||||
"""Internal event handler to draw the cursor when the mouse moves."""
|
||||
self.x = pos[0]
|
||||
self.y = pos[1]
|
||||
|
||||
if self.ignore(event):
|
||||
return
|
||||
if not self.canvas.widgetlock.available(self):
|
||||
return
|
||||
if event.inaxes != self.ax:
|
||||
self.linev.set_visible(False)
|
||||
self.lineh.set_visible(False)
|
||||
|
||||
if self.needclear:
|
||||
self.canvas.draw()
|
||||
self.needclear = False
|
||||
return
|
||||
self.needclear = True
|
||||
if not self.visible:
|
||||
return
|
||||
self.linev.set_xdata((self.x, self.x))
|
||||
|
||||
self.lineh.set_ydata((self.y, self.y))
|
||||
self.linev.set_visible(self.visible and self.vertOn)
|
||||
self.lineh.set_visible(self.visible and self.horizOn)
|
||||
|
||||
self._update()
|
||||
|
||||
|
||||
class ShapeCollectionLegacy:
|
||||
"""
|
||||
This will create the axes for each collection of shapes and will also
|
||||
@@ -930,7 +843,10 @@ class ShapeCollectionLegacy:
|
||||
self.shape_id = 0
|
||||
|
||||
self.axes.cla()
|
||||
self.app.plotcanvas.auto_adjust_axes()
|
||||
try:
|
||||
self.app.plotcanvas.auto_adjust_axes()
|
||||
except Exception as e:
|
||||
log.debug("ShapeCollectionLegacy.clear() --> %s" % str(e))
|
||||
|
||||
if update is True:
|
||||
self.redraw()
|
||||
@@ -1013,12 +929,17 @@ class ShapeCollectionLegacy:
|
||||
self.axes.plot(x, y, linespec, color=linecolor)
|
||||
else:
|
||||
path_num += 1
|
||||
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)
|
||||
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'],
|
||||
@@ -1108,3 +1029,62 @@ class ShapeCollectionLegacy:
|
||||
if self._visible is False:
|
||||
self.redraw()
|
||||
self._visible = value
|
||||
|
||||
# class MplCursor(Cursor):
|
||||
# """
|
||||
# Unfortunately this gets attached to the current axes and if a new axes is added
|
||||
# it will not be showed until that axes is deleted.
|
||||
# Not the kind of behavior needed here so I don't use it anymore.
|
||||
# """
|
||||
# def __init__(self, axes, color='red', linewidth=1):
|
||||
#
|
||||
# super().__init__(ax=axes, useblit=True, color=color, linewidth=linewidth)
|
||||
# self._enabled = True
|
||||
#
|
||||
# self.axes = axes
|
||||
# self.color = color
|
||||
# self.linewidth = linewidth
|
||||
#
|
||||
# self.x = None
|
||||
# self.y = None
|
||||
#
|
||||
# @property
|
||||
# def enabled(self):
|
||||
# return True if self._enabled else False
|
||||
#
|
||||
# @enabled.setter
|
||||
# def enabled(self, value):
|
||||
# self._enabled = value
|
||||
# self.visible = self._enabled
|
||||
# self.canvas.draw()
|
||||
#
|
||||
# def onmove(self, event):
|
||||
# pass
|
||||
#
|
||||
# def set_data(self, event, pos):
|
||||
# """Internal event handler to draw the cursor when the mouse moves."""
|
||||
# self.x = pos[0]
|
||||
# self.y = pos[1]
|
||||
#
|
||||
# if self.ignore(event):
|
||||
# return
|
||||
# if not self.canvas.widgetlock.available(self):
|
||||
# return
|
||||
# if event.inaxes != self.ax:
|
||||
# self.linev.set_visible(False)
|
||||
# self.lineh.set_visible(False)
|
||||
#
|
||||
# if self.needclear:
|
||||
# self.canvas.draw()
|
||||
# self.needclear = False
|
||||
# return
|
||||
# self.needclear = True
|
||||
# if not self.visible:
|
||||
# return
|
||||
# self.linev.set_xdata((self.x, self.x))
|
||||
#
|
||||
# self.lineh.set_ydata((self.y, self.y))
|
||||
# self.linev.set_visible(self.visible and self.vertOn)
|
||||
# self.lineh.set_visible(self.visible and self.horizOn)
|
||||
#
|
||||
# self._update()
|
||||
|
||||
@@ -88,7 +88,7 @@ def apply_patches():
|
||||
def _get_tick_frac_labels(self):
|
||||
"""Get the major ticks, minor ticks, and major labels"""
|
||||
minor_num = 4 # number of minor ticks per major division
|
||||
if (self.axis.scale_type == 'linear'):
|
||||
if self.axis.scale_type == 'linear':
|
||||
domain = self.axis.domain
|
||||
if domain[1] < domain[0]:
|
||||
flip = True
|
||||
|
||||
Reference in New Issue
Block a user