diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7770a326..1f6c6b3d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,16 @@ CHANGELOG for FlatCAM beta
=================================================
+11.05.2020
+
+- removed the labels in status bar that display X,Y positions and replaced it with a HUD display on canvas (combo key SHIFT+H) will toggle the display of the HUD
+- made the HUD work in Legacy2D mode
+- fixed situation when the mouse cursor is outside of the canvas and no therefore returning None values
+
+10.05.2020
+
+- fixed the problem with using comma as decimal separator in Grid Snap fields
+
9.05.2020
- modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now).
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 4641420d..5864bb2a 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -285,6 +285,8 @@ class App(QtCore.QObject):
:rtype: App
"""
+ super().__init__()
+
App.log.info("FlatCAM Starting...")
self.main_thread = QtWidgets.QApplication.instance().thread()
@@ -504,8 +506,6 @@ class App(QtCore.QObject):
self.FC_light_blue = '#a5a5ffbf'
self.FC_dark_blue = '#0000ffbf'
- QtCore.QObject.__init__(self)
-
self.ui = FlatCAMGUI(self)
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
@@ -5378,14 +5378,20 @@ class App(QtCore.QObject):
edge_width=self.defaults["global_cursor_width"],
size=self.defaults["global_cursor_size"])
- # Set the position label
- 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.ui.rel_position_label.setText("Dx: %.4f Dy: "
- "%.4f " % (dx, dy))
+ # self.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (location[0], location[1]))
+ # # Set the position label
+ #
+ # self.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (dx, dy))
+
+ units = self.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ dx, units, dy, units, location[0], units, location[1], units)
self.inform.emit('[success] %s' % _("Done."))
return location
@@ -5527,14 +5533,19 @@ class App(QtCore.QObject):
edge_width=self.defaults["global_cursor_width"],
size=self.defaults["global_cursor_size"])
- # Set the position label
- self.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (location[0], location[1]))
# Set the relative position label
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 " % (self.dx, self.dy))
+ # Set the position label
+ # self.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (location[0], location[1]))
+ # self.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.dx, self.dy))
+
+ units = self.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.dx, units, self.dy, units, location[0], units, location[1], units)
self.inform.emit('[success] %s' % _("Done."))
return location
@@ -5843,8 +5854,8 @@ class App(QtCore.QObject):
self.ui.plot_tab_area.addTab(self.ui.preferences_tab, _("Preferences"))
# delete the absolute and relative position and messages in the infobar
- self.ui.position_label.setText("")
- self.ui.rel_position_label.setText("")
+ # self.ui.position_label.setText("")
+ # self.ui.rel_position_label.setText("")
# Switch plot_area to preferences page
self.ui.plot_tab_area.setCurrentWidget(self.ui.preferences_tab)
@@ -6738,6 +6749,9 @@ class App(QtCore.QObject):
try: # May fail in case mouse not within axes
pos_canvas = self.plotcanvas.translate_coords(event_pos)
+ if pos_canvas[0] is None or pos_canvas[1] is None:
+ return
+
if self.grid_status():
pos = self.geo_editor.snap(pos_canvas[0], pos_canvas[1])
@@ -6749,13 +6763,19 @@ class App(QtCore.QObject):
else:
pos = (pos_canvas[0], pos_canvas[1])
- self.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (pos[0], pos[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 " % (self.dx, self.dy))
+
+ # self.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (pos[0], pos[1]))
+ # self.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.dx, self.dy))
+
+ units = self.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.dx, units, self.dy, units, pos[0], units, pos[1], units)
+
self.mouse = [pos[0], pos[1]]
# if the mouse is moved and the LMB is clicked then the action is a selection
@@ -6804,9 +6824,10 @@ class App(QtCore.QObject):
# In this case poly_obj creation (see above) will fail
pass
- except Exception:
- self.ui.position_label.setText("")
- self.ui.rel_position_label.setText("")
+ except Exception as e:
+ log.debug("App.on_mouse_move_over_plot() - rel_point1 is not None -> %s" % str(e))
+ # self.ui.position_label.setText("")
+ # self.ui.rel_position_label.setText("")
self.mouse = None
def on_mouse_click_release_over_plot(self, event):
diff --git a/FlatCAMCommon.py b/FlatCAMCommon.py
index b95091aa..bcd61a98 100644
--- a/FlatCAMCommon.py
+++ b/FlatCAMCommon.py
@@ -466,15 +466,20 @@ class ExclusionAreas(QtCore.QObject):
size=self.app.defaults["global_cursor_size"])
# update the positions on status bar
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (curr_pos[0], curr_pos[1]))
if self.cursor_pos is None:
self.cursor_pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (curr_pos[0], curr_pos[1]))
+ # self.app.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.app.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units)
if self.obj_type == 'excellon':
color = "#FF7400"
diff --git a/Utils/vispy_example.py b/Utils/vispy_example.py
new file mode 100644
index 00000000..a9eaee12
--- /dev/null
+++ b/Utils/vispy_example.py
@@ -0,0 +1,195 @@
+from PyQt5.QtGui import QPalette
+from PyQt5 import QtCore, QtWidgets
+
+import vispy.scene as scene
+from vispy.scene.visuals import Rectangle, Text
+from vispy.color import Color
+
+import sys
+
+
+class VisPyCanvas(scene.SceneCanvas):
+
+ def __init__(self, config=None):
+ super().__init__(config=config, keys=None)
+
+ self.unfreeze()
+
+ # Colors used by the Scene
+ theme_color = Color('#FFFFFF')
+ tick_color = Color('#000000')
+ back_color = str(QPalette().color(QPalette.Window).name())
+
+ # Central Widget Colors
+ self.central_widget.bgcolor = back_color
+ self.central_widget.border_color = back_color
+
+ self.grid_widget = self.central_widget.add_grid(margin=10)
+ self.grid_widget.spacing = 0
+
+ # TOP Padding
+ top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
+ top_padding.height_max = 0
+
+ # RIGHT Padding
+ right_padding = self.grid_widget.add_widget(row=0, col=2, row_span=2)
+ right_padding.width_max = 0
+
+ # X Axis
+ self.xaxis = scene.AxisWidget(
+ orientation='bottom', axis_color=tick_color, text_color=tick_color,
+ font_size=8, axis_width=1,
+ anchors=['center', 'bottom']
+ )
+ self.xaxis.height_max = 30
+ self.grid_widget.add_widget(self.xaxis, row=2, col=1)
+
+ # Y Axis
+ self.yaxis = scene.AxisWidget(
+ orientation='left', axis_color=tick_color, text_color=tick_color,
+ font_size=8, axis_width=1
+ )
+ self.yaxis.width_max = 55
+ self.grid_widget.add_widget(self.yaxis, row=1, col=0)
+
+ # View & Camera
+ self.view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color,
+ bgcolor=theme_color)
+ self.view.camera = scene.PanZoomCamera(aspect=1, rect=(-25, -25, 150, 150))
+
+ self.xaxis.link_view(self.view)
+ self.yaxis.link_view(self.view)
+
+ self.grid = scene.GridLines(parent=self.view.scene, color='dimgray')
+ self.grid.set_gl_state(depth_test=False)
+
+ self.rect = Rectangle(center=(65,30), color=Color('#0000FF10'), border_color=Color('#0000FF10'),
+ width=120, height=50, radius=[5, 5, 5, 5], parent=self.view)
+ self.rect.set_gl_state(depth_test=False)
+
+ self.text = Text('', parent=self.view, color='black', pos=(5, 30), method='gpu', anchor_x='left')
+ self.text.font_size = 8
+ self.text.text = 'Coordinates:\nX: %s\nY: %s' % ('0.0000', '0.0000')
+
+ self.freeze()
+
+ # self.measure_fps()
+
+
+class PlotCanvas(QtCore.QObject):
+
+ def __init__(self, container, my_app):
+ """
+ The constructor configures the VisPy figure that
+ will contain all plots, creates the base axes and connects
+ events to the plotting area.
+
+ :param container: The parent container in which to draw plots.
+ :rtype: PlotCanvas
+ """
+
+ super().__init__()
+
+ # VisPyCanvas instance
+ self.vispy_canvas = VisPyCanvas()
+
+ self.vispy_canvas.unfreeze()
+
+ self.my_app = my_app
+
+ # Parent container
+ self.container = container
+
+ #
+ self.vispy_canvas.create_native()
+ self.vispy_canvas.native.setParent(self.my_app.ui)
+
+ #
+ self.container.addWidget(self.vispy_canvas.native)
+
+ # add two Infinite Lines to act as markers for the X,Y axis
+ self.v_line = scene.visuals.InfiniteLine(
+ pos=0, color=(0.0, 0.0, 1.0, 0.3), vertical=True,
+ parent=self.vispy_canvas.view.scene)
+
+ self.h_line = scene.visuals.InfiniteLine(
+ pos=0, color=(0.00, 0.0, 1.0, 0.3), vertical=False,
+ parent=self.vispy_canvas.view.scene)
+
+ self.vispy_canvas.freeze()
+
+ def event_connect(self, event, callback):
+ getattr(self.vispy_canvas.events, event).connect(callback)
+
+ def event_disconnect(self, event, callback):
+ getattr(self.vispy_canvas.events, event).disconnect(callback)
+
+ def translate_coords(self, pos):
+ """
+ Translate pixels to canvas units.
+ """
+ tr = self.vispy_canvas.grid.get_transform('canvas', 'visual')
+ return tr.map(pos)
+
+
+class MyGui(QtWidgets.QMainWindow):
+
+ def __init__(self):
+ super().__init__()
+
+ self.setWindowTitle("VisPy Test")
+
+ # add Menubar
+ self.menu = self.menuBar()
+ self.menufile = self.menu.addMenu("File")
+ self.menuedit = self.menu.addMenu("Edit")
+ self.menufhelp = self.menu.addMenu("Help")
+
+ # add a Toolbar
+ self.file_toolbar = QtWidgets.QToolBar("File Toolbar")
+ self.addToolBar(self.file_toolbar)
+ self.button = self.file_toolbar.addAction("Open")
+
+ # add Central Widget
+ self.c_widget = QtWidgets.QWidget()
+ self.central_layout = QtWidgets.QVBoxLayout()
+ self.c_widget.setLayout(self.central_layout)
+ self.setCentralWidget(self.c_widget)
+
+ # add InfoBar
+ # self.infobar = self.statusBar()
+ # self.position_label = QtWidgets.QLabel("Position: X: 0.0000\tY: 0.0000")
+ # self.infobar.addWidget(self.position_label)
+
+
+class MyApp(QtCore.QObject):
+
+ def __init__(self):
+ super().__init__()
+
+ self.ui = MyGui()
+ self.plot = PlotCanvas(container=self.ui.central_layout, my_app=self)
+
+ self.ui.show()
+
+ self.plot.event_connect(event="mouse_move", callback=self.on_mouse_move)
+
+ def on_mouse_move(self, event):
+ cursor_pos = event.pos
+
+ pos_canvas = self.plot.translate_coords(cursor_pos)
+
+ # we don't need all the info in the tuple returned by the translate_coords()
+ # only first 2 elements
+ pos_canvas = [pos_canvas[0], pos_canvas[1]]
+ # self.ui.position_label.setText("Position: X: %.4f\tY: %.4f" % (pos_canvas[0], pos_canvas[1]))
+ # pos_text = 'Coordinates: \nX: {:<7.4f}\nY: {:<7.4f}'.format(pos_canvas[0], pos_canvas[1])
+ pos_text = 'Coordinates: \nX: {:<.4f}\nY: {:<.4f}'.format(pos_canvas[0], pos_canvas[1])
+ self.plot.vispy_canvas.text.text = pos_text
+
+
+if __name__ == '__main__':
+ app = QtWidgets.QApplication(sys.argv)
+
+ m_app = MyApp()
+ sys.exit(app.exec_())
diff --git a/defaults.py b/defaults.py
index b446a39a..64f0fa70 100644
--- a/defaults.py
+++ b/defaults.py
@@ -43,6 +43,7 @@ class FlatCAMDefaults:
# General
"global_graphic_engine": '3D',
+ "global_hud": True,
"global_app_level": 'b',
"global_portable": False,
"global_language": 'English',
diff --git a/flatcamEditors/FlatCAMExcEditor.py b/flatcamEditors/FlatCAMExcEditor.py
index 49dc5eb5..7b68f11c 100644
--- a/flatcamEditors/FlatCAMExcEditor.py
+++ b/flatcamEditors/FlatCAMExcEditor.py
@@ -3801,18 +3801,22 @@ class FlatCAMExcEditor(QtCore.QObject):
self.snap_x = x
self.snap_y = y
- # update the position label in the infobar since the APP mouse event handlers are disconnected
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (x, y))
-
if self.pos is None:
self.pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+ # # update the position label in the infobar since the APP mouse event handlers are disconnected
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (x, y))
+ # # 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 " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, x, units, y, units)
# ## Utility geometry (animated)
self.update_utility_geometry(data=(x, y))
diff --git a/flatcamEditors/FlatCAMGeoEditor.py b/flatcamEditors/FlatCAMGeoEditor.py
index ccf67ce4..e8d969cb 100644
--- a/flatcamEditors/FlatCAMGeoEditor.py
+++ b/flatcamEditors/FlatCAMGeoEditor.py
@@ -3467,22 +3467,32 @@ class FlatCAMGeoEditor(QtCore.QObject):
:return:
"""
try:
- self.options[opt] = float(entry.text())
+ text_value = entry.text()
+ if ',' in text_value:
+ text_value = text_value.replace(',', '.')
+ self.options[opt] = float(text_value)
except Exception as e:
+ entry.set_value(self.app.defaults[opt])
log.debug("FlatCAMGeoEditor.__init__().entry2option() --> %s" % str(e))
return
- def gridx_changed(goption, gentry):
+ def grid_changed(goption, gentry):
"""
- :param goption: String. Can be either 'global_gridx' or 'global_gridy'
- :param gentry: A GUI element which text value is read and used
+ :param goption: String. Can be either 'global_gridx' or 'global_gridy'
+ :param gentry: A GUI element which text value is read and used
:return:
"""
+ if goption not in ['global_gridx', 'global_gridy']:
+ return
+
entry2option(opt=goption, entry=gentry)
# if the grid link is checked copy the value in the GridX field to GridY
try:
- val = float(gentry.get_value())
+ text_value = gentry.text()
+ if ',' in text_value:
+ text_value = text_value.replace(',', '.')
+ val = float(text_value)
except ValueError:
return
@@ -3491,7 +3501,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator())
self.app.ui.grid_gap_x_entry.textChanged.connect(
- lambda: gridx_changed("global_gridx", self.app.ui.grid_gap_x_entry))
+ lambda: grid_changed("global_gridx", self.app.ui.grid_gap_x_entry))
self.app.ui.grid_gap_y_entry.setValidator(QtGui.QDoubleValidator())
self.app.ui.grid_gap_y_entry.textChanged.connect(
@@ -4261,18 +4271,23 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.snap_y = y
self.app.mouse = [x, y]
- # update the position label in the infobar since the APP mouse event handlers are disconnected
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (x, y))
-
if self.pos is None:
self.pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+ # # update the position label in the infobar since the APP mouse event handlers are disconnected
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (x, y))
+ #
+ # # 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 " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, x, units, y, units)
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 3362c5ba..d5659fbf 100644
--- a/flatcamEditors/FlatCAMGrbEditor.py
+++ b/flatcamEditors/FlatCAMGrbEditor.py
@@ -4774,18 +4774,23 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.app.mouse = [x, y]
- # update the position label in the infobar since the APP mouse event handlers are disconnected
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (x, y))
-
if self.pos is None:
self.pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+ # # update the position label in the infobar since the APP mouse event handlers are disconnected
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (x, y))
+ #
+ # # 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 " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, x, units, y, units)
self.update_utility_geometry(data=(x, y))
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index 09d7383b..aeb7b86d 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -2306,17 +2306,17 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.snap_infobar_label.setPixmap(QtGui.QPixmap(self.app.resource_location + '/snap_16.png'))
self.infobar.addWidget(self.snap_infobar_label)
- self.rel_position_label = QtWidgets.QLabel(
- "Dx: 0.0000 Dy: 0.0000 ")
- self.rel_position_label.setMinimumWidth(110)
- self.rel_position_label.setToolTip(_("Relative measurement.\nReference is last click position"))
- self.infobar.addWidget(self.rel_position_label)
-
- self.position_label = QtWidgets.QLabel(
- " X: 0.0000 Y: 0.0000")
- self.position_label.setMinimumWidth(110)
- self.position_label.setToolTip(_("Absolute measurement.\nReference is (X=0, Y= 0) position"))
- self.infobar.addWidget(self.position_label)
+ # self.rel_position_label = QtWidgets.QLabel(
+ # "Dx: 0.0000 Dy: 0.0000 ")
+ # self.rel_position_label.setMinimumWidth(110)
+ # self.rel_position_label.setToolTip(_("Relative measurement.\nReference is last click position"))
+ # self.infobar.addWidget(self.rel_position_label)
+ #
+ # self.position_label = QtWidgets.QLabel(
+ # " X: 0.0000 Y: 0.0000")
+ # self.position_label.setMinimumWidth(110)
+ # self.position_label.setToolTip(_("Absolute measurement.\nReference is (X=0, Y= 0) position"))
+ # self.infobar.addWidget(self.position_label)
self.units_label = QtWidgets.QLabel("[in]")
self.units_label.setMargin(2)
@@ -2993,6 +2993,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if key == QtCore.Qt.Key_G:
self.app.on_toggle_axis()
+ # Toggle HUD (Heads-Up Display)
+ if key == QtCore.Qt.Key_H:
+ state = False if self.app.plotcanvas.hud_enabled else True
+ self.app.plotcanvas.on_toggle_hud(state=state)
+
# Locate in Object
if key == QtCore.Qt.Key_J:
self.app.on_locate(obj=self.app.collection.get_active())
diff --git a/flatcamGUI/PlotCanvas.py b/flatcamGUI/PlotCanvas.py
index 44af74d0..a1be6099 100644
--- a/flatcamGUI/PlotCanvas.py
+++ b/flatcamGUI/PlotCanvas.py
@@ -10,7 +10,7 @@ from PyQt5 import QtCore
import logging
from flatcamGUI.VisPyCanvas import VisPyCanvas, Color
from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
-from vispy.scene.visuals import InfiniteLine, Line
+from vispy.scene.visuals import InfiniteLine, Line, Rectangle, Text
import numpy as np
from vispy.geometry import Rect
@@ -54,8 +54,12 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
if theme == 'white':
self.line_color = (0.3, 0.0, 0.0, 1.0)
+ self.rect_hud_color = Color('#0000FF10')
+ self.text_hud_color = 'black'
else:
self.line_color = (0.4, 0.4, 0.4, 1.0)
+ self.rect_hud_color = Color('#0000FF10')
+ self.text_hud_color = 'white'
# workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
# which might decrease performance
@@ -146,13 +150,28 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
self.cursor_h_line = InfiniteLine(pos=None, color=c_color, vertical=False,
parent=self.line_parent)
+ self.rect_hud = Rectangle(center=(90,45), color=self.rect_hud_color, border_color=self.rect_hud_color,
+ width=170, height=80, radius=[5, 5, 5, 5], parent=None)
+ self.rect_hud.set_gl_state(depth_test=False)
+
+ # HUD Display
+ self.hud_enabled = False
+
+ self.text_hud = Text('', color=self.text_hud_color, pos=(8, 45), method='gpu', anchor_x='left', parent=None)
+ self.text_hud.font_size = 8
+ units = self.fcapp.defaults["units"].lower()
+ self.text_hud.text = 'Dx:\t%s [%s]\nDy:\t%s [%s]\nX: \t%s [%s]\nY: \t%s [%s]' % \
+ ('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units)
+
+ if self.fcapp.defaults['global_hud'] is True:
+ self.on_toggle_hud(state=True)
+
self.shape_collections = []
self.shape_collection = self.new_shape_collection()
self.fcapp.pool_recreated.connect(self.on_pool_recreated)
self.text_collection = self.new_text_collection()
- # TODO: Should be setting to show/hide CNC job annotations (global or per object)
self.text_collection.enabled = True
self.c = None
@@ -163,6 +182,16 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
self.graph_event_connect('mouse_wheel', self.on_mouse_scroll)
+ def on_toggle_hud(self, state):
+ if state:
+ self.hud_enabled = True
+ self.rect_hud.parent = self.view
+ self.text_hud.parent = self.view
+ else:
+ self.hud_enabled = False
+ self.rect_hud.parent = None
+ self.text_hud.parent = None
+
def draw_workspace(self, workspace_size):
"""
Draw a rectangular shape on canvas to specify our valid workspace.
diff --git a/flatcamGUI/PlotCanvasLegacy.py b/flatcamGUI/PlotCanvasLegacy.py
index a9a6216f..7856bb8f 100644
--- a/flatcamGUI/PlotCanvasLegacy.py
+++ b/flatcamGUI/PlotCanvasLegacy.py
@@ -29,6 +29,7 @@ mpl_use("Qt5Agg")
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.lines import Line2D
+from matplotlib.offsetbox import AnchoredText
# from matplotlib.widgets import Cursor
fcTranslate.apply_language('strings')
@@ -147,9 +148,13 @@ class PlotCanvasLegacy(QtCore.QObject):
if self.app.defaults['global_theme'] == 'white':
theme_color = '#FFFFFF'
tick_color = '#000000'
+ self.rect_hud_color = '#0000FF10'
+ self.text_hud_color = '#000000'
else:
theme_color = '#000000'
tick_color = '#FFFFFF'
+ self.rect_hud_color = '#0000FF10'
+ self.text_hud_color = '#000000'
# workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
# which might decrease performance
@@ -298,11 +303,79 @@ class PlotCanvasLegacy(QtCore.QObject):
# signal if there is a doubleclick
self.is_dblclk = False
+ self.hud_enabled = False
+ self.text_hud = self.Thud(plotcanvas=self)
+
+ # bbox_props = dict(boxstyle="round,pad=0.3", fc="blue", ec="b", lw=0)
+ # self.text_hud = self.figure.text(0, 0, "Direction", ha="left", va="center", rotation=0,
+ # size=15,
+ # bbox=bbox_props)
+
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
# all CNC have a limited workspace
if self.app.defaults['global_workspace'] is True:
self.draw_workspace(workspace_size=self.app.defaults["global_workspaceT"])
+ if self.app.defaults['global_hud'] is True:
+ self.on_toggle_hud(state=True)
+
+ def on_toggle_hud(self, state):
+ if state:
+ self.hud_enabled = True
+ self.text_hud.add_artist()
+ else:
+ self.hud_enabled = False
+ self.text_hud.remove_artist()
+ self.canvas.draw()
+
+ class Thud(QtCore.QObject):
+ text_changed = QtCore.pyqtSignal(str)
+
+ def __init__(self, plotcanvas):
+ super().__init__()
+
+ self.p = plotcanvas
+ units = self.p.app.defaults['units']
+ self._text = 'Dx: %s [%s]\nDy: %s [%s]\nX: %s [%s]\nY: %s [%s]' % \
+ ('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units)
+
+ self.hud_holder = AnchoredText(self._text,
+ prop=dict(size=20), frameon=True,
+ loc='upper left',
+ )
+ self.hud_holder.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
+
+ self.hud_holder.patch.set_facecolor('blue')
+ self.hud_holder.patch.set_alpha(0.3)
+ self.hud_holder.patch.set_edgecolor((0, 0, 0, 0))
+
+ self.text_changed.connect(self.on_text_changed)
+
+ @property
+ def text(self):
+ return self._text
+
+ @text.setter
+ def text(self, val):
+ self.text_changed.emit(val)
+ self._text = val
+
+ def on_text_changed(self, txt):
+ try:
+ txt = txt.replace('\t', ' ')
+ self.hud_holder.txt.set_text(txt)
+ self.p.canvas.draw()
+ except Exception:
+ pass
+
+ def add_artist(self):
+ if self.hud_holder not in self.p.axes.artists:
+ self.p.axes.add_artist(self.hud_holder)
+
+ def remove_artist(self):
+ if self.hud_holder in self.p.axes.artists:
+ self.p.axes.artists.remove(self.hud_holder)
+
def draw_workspace(self, workspace_size):
"""
Draw a rectangular shape on canvas to specify our valid workspace.
diff --git a/flatcamGUI/VisPyCanvas.py b/flatcamGUI/VisPyCanvas.py
index 7d7efe13..aa55675f 100644
--- a/flatcamGUI/VisPyCanvas.py
+++ b/flatcamGUI/VisPyCanvas.py
@@ -13,6 +13,7 @@ import numpy as np
import vispy.scene as scene
from vispy.scene.cameras.base_camera import BaseCamera
+# from vispy.scene.widgets import Widget as VisPyWidget
from vispy.color import Color
import time
diff --git a/flatcamTools/ToolCopperThieving.py b/flatcamTools/ToolCopperThieving.py
index d6fd310a..f6c85731 100644
--- a/flatcamTools/ToolCopperThieving.py
+++ b/flatcamTools/ToolCopperThieving.py
@@ -910,16 +910,22 @@ class ToolCopperThieving(FlatCAMTool):
edge_width=self.app.defaults["global_cursor_width"],
size=self.app.defaults["global_cursor_size"])
- # update the positions on status bar
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (curr_pos[0], curr_pos[1]))
if self.cursor_pos is None:
self.cursor_pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+
+ # # update the positions on status bar
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (curr_pos[0], curr_pos[1]))
+ # self.app.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units)
# draw the utility geometry
if self.first_click:
diff --git a/flatcamTools/ToolDistance.py b/flatcamTools/ToolDistance.py
index ea62c64e..bcc506fb 100644
--- a/flatcamTools/ToolDistance.py
+++ b/flatcamTools/ToolDistance.py
@@ -544,11 +544,16 @@ class Distance(FlatCAMTool):
else:
pos = (pos_canvas[0], pos_canvas[1])
- self.app.ui.position_label.setText(
- " X: {} Y: {}".format(
- '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1])
- )
- )
+ # self.app.ui.position_label.setText(
+ # " X: {} Y: {}".format(
+ # '%.*f' % (self.decimals, pos[0]), '%.*f' % (self.decimals, pos[1])
+ # )
+ # )
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ 0.0000, units, 0.0000, units, pos[0], units, pos[1], units)
if self.rel_point1 is not None:
dx = pos[0] - float(self.rel_point1[0])
diff --git a/flatcamTools/ToolNCC.py b/flatcamTools/ToolNCC.py
index 0b80c735..d01f02de 100644
--- a/flatcamTools/ToolNCC.py
+++ b/flatcamTools/ToolNCC.py
@@ -1825,16 +1825,22 @@ class NonCopperClear(FlatCAMTool, Gerber):
edge_width=self.app.defaults["global_cursor_width"],
size=self.app.defaults["global_cursor_size"])
- # update the positions on status bar
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (curr_pos[0], curr_pos[1]))
if self.cursor_pos is None:
self.cursor_pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+
+ # # update the positions on status bar
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (curr_pos[0], curr_pos[1]))
+ # self.app.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units)
# draw the utility geometry
if shape_type == "square":
diff --git a/flatcamTools/ToolPaint.py b/flatcamTools/ToolPaint.py
index 4dda2d36..ae1b23cc 100644
--- a/flatcamTools/ToolPaint.py
+++ b/flatcamTools/ToolPaint.py
@@ -1724,16 +1724,22 @@ class ToolPaint(FlatCAMTool, Gerber):
edge_width=self.app.defaults["global_cursor_width"],
size=self.app.defaults["global_cursor_size"])
- # update the positions on status bar
- self.app.ui.position_label.setText(" X: %.4f "
- "Y: %.4f" % (curr_pos[0], curr_pos[1]))
if self.cursor_pos is None:
self.cursor_pos = (0, 0)
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 " % (self.app.dx, self.app.dy))
+
+ # # update the positions on status bar
+ # self.app.ui.position_label.setText(" X: %.4f "
+ # "Y: %.4f" % (curr_pos[0], curr_pos[1]))
+ # self.app.ui.rel_position_label.setText("Dx: %.4f Dy: "
+ # "%.4f " % (self.app.dx, self.app.dy))
+
+ units = self.app.defaults["units"].lower()
+ self.plotcanvas.text_hud.text = \
+ 'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
+ self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units)
# draw the utility geometry
if shape_type == "square":