diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index fe261376..887901f2 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -124,8 +124,8 @@ class App(QtCore.QObject):
# ##########################################################################
# ################## Version and VERSION DATE ##############################
# ##########################################################################
- version = 8.97
- version_date = "2019/09/27"
+ version = 8.98
+ version_date = "2019/10/7"
beta = True
engine = '3D'
@@ -492,6 +492,8 @@ class App(QtCore.QObject):
"global_project_autohide": self.ui.general_defaults_form.general_gui_set_group.project_autohide_cb,
"global_toggle_tooltips": self.ui.general_defaults_form.general_gui_set_group.toggle_tooltips_cb,
"global_delete_confirmation": self.ui.general_defaults_form.general_gui_set_group.delete_conf_cb,
+ "global_cursor_type": self.ui.general_defaults_form.general_gui_set_group.cursor_radio,
+ "global_cursor_size": self.ui.general_defaults_form.general_gui_set_group.cursor_size_entry,
# Gerber General
"gerber_plot": self.ui.gerber_defaults_form.gerber_gen_group.plot_cb,
@@ -911,6 +913,8 @@ class App(QtCore.QObject):
"global_hover": False,
"global_selection_shape": True,
"global_layout": "compact",
+ "global_cursor_type": "small",
+ "global_cursor_size": 20,
# Gerber General
"gerber_plot": True,
@@ -1957,6 +1961,12 @@ class App(QtCore.QObject):
self.ui.general_defaults_form.general_gui_set_group.layout_combo.activated.connect(self.on_layout)
+ # #################################################
+ # ############ GUI SETTINGS SIGNALS ###############
+ # #################################################
+
+ self.ui.general_defaults_form.general_gui_set_group.cursor_radio.activated_custom.connect(self.on_cursor_type)
+
# ########## CNC Job related signals #############
self.ui.cncjob_defaults_form.cncjob_adv_opt_group.tc_variable_combo.currentIndexChanged[str].connect(
self.on_cnc_custom_parameters)
@@ -6265,6 +6275,13 @@ class App(QtCore.QObject):
self.on_workspace()
def on_layout(self, index=None, lay=None):
+ """
+ Set the toolbars layout (location)
+
+ :param index:
+ :param lay: type of layout to be set on the toolbard
+ :return: None
+ """
self.report_usage("on_layout()")
if lay:
current_layout = lay
@@ -6397,6 +6414,20 @@ class App(QtCore.QObject):
self.ui.snap_max_dist_entry.setText(str(self.defaults["global_snap_max"]))
self.ui.grid_gap_link_cb.setChecked(True)
+ def on_cursor_type(self, val):
+ """
+
+ :param val: type of mouse cursor, set in Preferences ('small' or 'big')
+ :return: None
+ """
+
+ if val == 'small':
+ self.ui.general_defaults_form.general_gui_set_group.cursor_size_entry.setDisabled(False)
+ self.ui.general_defaults_form.general_gui_set_group.cursor_size_lbl.setDisabled(False)
+ else:
+ self.ui.general_defaults_form.general_gui_set_group.cursor_size_entry.setDisabled(True)
+ self.ui.general_defaults_form.general_gui_set_group.cursor_size_lbl.setDisabled(True)
+
def on_cnc_custom_parameters(self, signal_text):
if signal_text == 'Parameters':
return
@@ -7826,7 +7857,7 @@ class App(QtCore.QObject):
# Update cursor
self.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
- symbol='++', edge_color='black', size=20)
+ symbol='++', edge_color='black', size=self.defaults["global_cursor_size"])
else:
pos = (pos_canvas[0], pos_canvas[1])
@@ -11172,7 +11203,10 @@ class App(QtCore.QObject):
# Keys over plot enabled
self.kp = self.plotcanvas.graph_event_connect('key_press', self.ui.keyPressEvent)
- self.app_cursor = self.plotcanvas.new_cursor()
+ if self.defaults['global_cursor_type'] == 'small':
+ self.app_cursor = self.plotcanvas.new_cursor()
+ else:
+ self.app_cursor = self.plotcanvas.new_cursor(big=True)
if self.ui.grid_snap_btn.isChecked():
self.app_cursor.enabled = True
diff --git a/README.md b/README.md
index 3d1b575c..e2d7194b 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,9 @@ CAD program, and create G-Code for Isolation routing.
27.09.2019
-- optimized the toggle grid command
-
+- optimized the toggle axis command
+- added posibility of using a big mouse cursor or a small mouse cursor. The big mouse cursor is made from 2 infinite lines. This was implemented for both graphic engines
+- added ability to change the cursor size when the small mouse cursor is selected in Preferences -> General
27.09.2019
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 65f66ebd..4dc33d23 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -3657,7 +3657,8 @@ class FlatCAMExcEditor(QtCore.QObject):
x, y = self.app.geo_editor.snap(x, y)
# Update cursor
- self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black', size=20)
+ self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+ size=self.app.defaults["global_cursor_size"])
self.snap_x = x
self.snap_y = y
@@ -3705,7 +3706,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.app.selection_type = None
# Update cursor
- self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black', size=20)
+ self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+ size=self.app.defaults["global_cursor_size"])
def on_canvas_key_release(self, event):
self.key = None
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index 276230aa..4a235daa 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3755,7 +3755,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
x, y = self.snap(x, y)
# Update cursor
- self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black', size=20)
+ self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+ size=self.app.defaults["global_cursor_size"])
self.snap_x = x
self.snap_y = y
diff --git a/flatcamEditors/FlatCAMGrbEditor.py b/flatcamEditors/FlatCAMGrbEditor.py
index 0302b410..ee69683f 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -4398,7 +4398,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
x, y = self.app.geo_editor.snap(x, y)
# Update cursor
- self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black', size=20)
+ self.app.app_cursor.set_data(np.asarray([(x, y)]), symbol='++', edge_color='black',
+ size=self.app.defaults["global_cursor_size"])
self.snap_x = x
self.snap_y = y
diff --git a/flatcamGUI/PlotCanvas.py b/flatcamGUI/PlotCanvas.py
index 869ed1a5..42d5dbcc 100644
--- a/flatcamGUI/PlotCanvas.py
+++ b/flatcamGUI/PlotCanvas.py
@@ -67,6 +67,14 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
self.draw_workspace()
+ self.line_parent = None
+ self.line_color = (0.3, 0.0, 0.0, 1.0)
+ self.cursor_v_line = InfiniteLine(pos=None, color=self.line_color, vertical=True,
+ parent=self.line_parent)
+
+ self.cursor_h_line = InfiniteLine(pos=None, color=self.line_color, vertical=False,
+ parent=self.line_parent)
+
# if self.app.defaults['global_workspace'] is True:
# if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper() == 'MM':
# self.wkspace_t = Line(pos=)
@@ -80,6 +88,8 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
# TODO: Should be setting to show/hide CNC job annotations (global or per object)
self.text_collection.enabled = True
+ self.c = None
+
# Keep VisPy canvas happy by letting it be "frozen" again.
self.freeze()
@@ -185,10 +195,30 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
# return sc
return ShapeCollection(parent=self.view.scene, pool=self.fcapp.pool, **kwargs)
- def new_cursor(self):
- c = Cursor(pos=np.empty((0, 2)), parent=self.view.scene)
- c.antialias = 0
- return c
+ def new_cursor(self, big=None):
+ if big is True:
+ self.c = CursorBig()
+ self.c.mouse_state_updated.connect(self.on_mouse_state)
+ self.c.mouse_position_updated.connect(self.on_mouse_position)
+ else:
+ self.c = Cursor(pos=np.empty((0, 2)), parent=self.view.scene)
+ self.c.antialias = 0
+ return self.c
+
+ def on_mouse_state(self, state):
+ if state:
+ self.cursor_h_line.parent = self.view.scene
+ self.cursor_v_line.parent = self.view.scene
+ else:
+ self.cursor_h_line.parent = None
+ self.cursor_v_line.parent = None
+
+ def on_mouse_position(self, pos):
+ # self.line_color = color
+
+ self.cursor_h_line.set_data(pos=pos[1], color=self.line_color)
+ self.cursor_v_line.set_data(pos=pos[0], color=self.line_color)
+ self.view.scene.update()
def new_text_group(self, collection=None):
if collection:
@@ -247,3 +277,38 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
def on_pool_recreated(self, pool):
self.shape_collection.pool = pool
+
+
+class CursorBig(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 = QtCore.pyqtSignal(bool)
+ mouse_position_updated = QtCore.pyqtSignal(list)
+
+ def __init__(self):
+ super().__init__()
+
+ self._enabled = None
+
+ @property
+ def enabled(self):
+ return True if self._enabled else False
+
+ @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."""
+ if 'edge_color' in kwargs:
+ color = kwargs['edge_color']
+ else:
+ color = (0.0, 0.0, 0.0, 1.0)
+
+ position = [pos[0][0], pos[0][1]]
+ self.mouse_position_updated.emit(position)
diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py
index 3e3d8cd3..96df7e6a 100644
--- a/flatcamGUI/PlotCanvasLegacy.py
+++ b/flatcamGUI/PlotCanvasLegacy.py
@@ -159,6 +159,9 @@ class PlotCanvasLegacy(QtCore.QObject):
self.axes.axhline(color=(0.70, 0.3, 0.3), linewidth=2)
self.axes.axvline(color=(0.70, 0.3, 0.3), linewidth=2)
+ self.ch_line = None
+ self.cv_line = None
+
# The canvas is the top level container (FigureCanvasQTAgg)
self.canvas = FigureCanvas(self.figure)
@@ -207,6 +210,7 @@ class PlotCanvasLegacy(QtCore.QObject):
self.pan_axes = []
self.panning = False
self.mouse = [0, 0]
+ self.big_cursor = False
# signal is the mouse is dragging
self.is_dragging = False
@@ -254,17 +258,19 @@ class PlotCanvasLegacy(QtCore.QObject):
pass
# log.debug("Cache updated the screen!")
- def new_cursor(self, axes=None):
+ def new_cursor(self, axes=None, big=None):
# if axes is None:
# c = MplCursor(axes=self.axes, color='black', linewidth=1)
# else:
# c = MplCursor(axes=axes, color='black', linewidth=1)
+ if big is True:
+ self.big_cursor = True
+ self.ch_line = self.axes.axhline(color=(0.0, 0.0, 0.0), linewidth=1)
+ self.cv_line = self.axes.axvline(color=(0.0, 0.0, 0.0), linewidth=1)
c = FakeCursor()
- try:
- c.mouse_state_updated.connect(self.clear_cursor)
- except Exception as e:
- print(str(e))
+ c.mouse_state_updated.connect(self.clear_cursor)
+
return c
def draw_cursor(self, x_pos, y_pos):
@@ -277,18 +283,26 @@ class PlotCanvasLegacy(QtCore.QObject):
"""
# 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)
+ if self.big_cursor is False:
+ try:
+ x, y = self.app.geo_editor.snap(x_pos, y_pos)
- # Pointer (snapped)
- elements = self.axes.plot(x, y, 'k+', ms=33, mew=1, 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
+ # 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)
+ elements = self.axes.plot(x, y, 'k+', ms=pointer_size, mew=1, 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
+ else:
+ self.ch_line.set_ydata(y_pos)
+ self.cv_line.set_xdata(x_pos)
+ self.canvas.draw_idle()
self.canvas.blit(self.axes.bbox)
@@ -742,7 +756,6 @@ class FakeCursor(QtCore.QObject):
def set_data(self, pos, **kwargs):
"""Internal event handler to draw the cursor when the mouse moves."""
- pass
class ShapeCollectionLegacy:
diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py
index d2a4dce9..baa46091 100644
--- a/flatcamGUI/PreferencesUI.py
+++ b/flatcamGUI/PreferencesUI.py
@@ -754,6 +754,29 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
"when hovering with mouse over items throughout the App.")
)
+ # Mouse Cursor Shape
+ self.cursor_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor'))
+ self.cursor_lbl.setToolTip(
+ _("Choose a mouse cursor shape.\n"
+ "- Small -> with a customizable size.\n"
+ "- Big -> Infinite lines")
+ )
+
+ self.cursor_radio = RadioSet([
+ {"label": _("Small"), "value": "small"},
+ {"label": _("Big"), "value": "big"}
+ ], orientation='horizontal', stretch=False)
+
+ self.cursor_size_lbl = QtWidgets.QLabel('%s:' % _('Mouse Cursor Size'))
+ self.cursor_size_lbl.setToolTip(
+ _("Set the size of the mouse cursor, in pixels.")
+ )
+
+ self.cursor_size_entry = FCSpinner()
+ self.cursor_size_entry.set_range(10, 70)
+ self.cursor_size_entry.setWrapping(True)
+
+
# Add (label - input field) pair to the QFormLayout
self.form_box.addRow(self.spacelabel, self.spacelabel)
@@ -775,6 +798,8 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
self.form_box.addRow(self.project_autohide_label, self.project_autohide_cb)
self.form_box.addRow(QtWidgets.QLabel(''))
self.form_box.addRow(self.toggle_tooltips_label, self.toggle_tooltips_cb)
+ self.form_box.addRow(self.cursor_lbl, self.cursor_radio)
+ self.form_box.addRow(self.cursor_size_lbl, self.cursor_size_entry)
# Add the QFormLayout that holds the Application general defaults
# to the main layout of this TAB
diff --git a/flatcamTools/ToolMeasurement.py b/flatcamTools/ToolMeasurement.py
index 7a38dff1..672dd09a 100644
--- a/flatcamTools/ToolMeasurement.py
+++ b/flatcamTools/ToolMeasurement.py
@@ -346,7 +346,8 @@ class Measurement(FlatCAMTool):
# Update cursor
self.app.app_cursor.set_data(np.asarray([(pos[0], pos[1])]),
- symbol='++', edge_color='black', size=20)
+ symbol='++', edge_color='black',
+ size=self.app.defaults["global_cursor_size"])
else:
pos = (pos_canvas[0], pos_canvas[1])
diff --git a/flatcamTools/ToolNonCopperClear.py b/flatcamTools/ToolNonCopperClear.py
index be3e4283..2e1c2164 100644
--- a/flatcamTools/ToolNonCopperClear.py
+++ b/flatcamTools/ToolNonCopperClear.py
@@ -1282,7 +1282,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
- symbol='++', edge_color='black', size=20)
+ symbol='++', edge_color='black', size=self.app.defaults["global_cursor_size"])
# update the positions on status bar
self.app.ui.position_label.setText(" X: %.4f "
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index cc02d796..49e931f4 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -1185,7 +1185,7 @@ class ToolPaint(FlatCAMTool, Gerber):
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
- symbol='++', edge_color='black', size=20)
+ symbol='++', edge_color='black', size=self.app.defaults["global_cursor_size"])
# update the positions on status bar
self.app.ui.position_label.setText(" X: %.4f "