Import LinuxCNC source tree
This commit is contained in:
298
lib/python/qtvcp/widgets/user_dro_label.py
Normal file
298
lib/python/qtvcp/widgets/user_dro_label.py
Normal file
@@ -0,0 +1,298 @@
|
||||
#!/usr/bin/env python3
|
||||
# QtVcp Widget - user temporary DRO label widget
|
||||
# This widgets displays linuxcnc axis position information.
|
||||
#
|
||||
# Copyright (c) 2025 Chris Morley
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import linuxcnc
|
||||
from math import isclose
|
||||
|
||||
from qtpy import QtCore
|
||||
from qtpy.QtWidgets import QMenu, QAction
|
||||
from qtpy.QtGui import QIcon, QColor
|
||||
|
||||
from qtvcp.widgets.simple_widgets import ScaledLabel
|
||||
from qtvcp.widgets.widget_baseclass import _HalWidgetBase
|
||||
from qtvcp.core import Status, Info, Action
|
||||
from qtvcp import logger
|
||||
|
||||
# Instantiate the libraries with global reference
|
||||
# INFO holds INI file details
|
||||
# STATUS gives us status messages from linuxcnc
|
||||
# LOG is for running code logging
|
||||
STATUS = Status()
|
||||
INFO = Info()
|
||||
ACTION = Action()
|
||||
LOG = logger.getLogger(__name__)
|
||||
|
||||
# Force the log level for this module
|
||||
# LOG.setLevel(logger.INFO) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL
|
||||
|
||||
|
||||
class UserDROLabel(ScaledLabel, _HalWidgetBase):
|
||||
def __init__(self, parent=None):
|
||||
super(UserDROLabel, self).__init__(parent)
|
||||
# axis index of 9 axis
|
||||
self.axis_index = 0
|
||||
# linuxcnc joint number
|
||||
self._joint_type = 1
|
||||
self.display_units_mm = 0
|
||||
self.metric_text_template = '%10.3f'
|
||||
self.imperial_text_template = '%9.4f'
|
||||
self.angular_text_template = '%9.2f'
|
||||
self._text =' -000.0000'
|
||||
self._offset = [0.0] * 9
|
||||
self._lastOffset = [0.0] * 9
|
||||
self._negativeColor = QColor(0, 0, 100, 150)
|
||||
self._positiveColor = QColor(100, 0, 0, 150)
|
||||
self._zeroColor = QColor(0, 100, 0, 150)
|
||||
self._imperialTolerence = .00005
|
||||
self._metricTolerence = .005
|
||||
self._currentTolerence = .0005
|
||||
self._lastNum = 0.0
|
||||
|
||||
# menu stuff
|
||||
self.dialog_code = 'CALCULATOR'
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
SettingMenu = QMenu(self)
|
||||
self.settingMenu = SettingMenu
|
||||
self.zeroButton = QAction(QIcon('exit24.png'), 'Zero', self)
|
||||
self.zeroButton.triggered.connect(self.Zero)
|
||||
SettingMenu.addAction(self.zeroButton)
|
||||
self.setButton = QAction(QIcon('exit24.png'), 'Set', self)
|
||||
self.setButton.triggered.connect(self.SetOrigin)
|
||||
SettingMenu.addAction(self.setButton)
|
||||
self.lastButton = QAction(QIcon('exit24.png'), 'Set To Last', self)
|
||||
self.lastButton.triggered.connect(self.Last)
|
||||
SettingMenu.addAction(self.lastButton)
|
||||
|
||||
SettingMenu.popup(event.globalPos())
|
||||
|
||||
def _hal_init(self):
|
||||
super(UserDROLabel, self)._hal_init()
|
||||
STATUS.connect('current-position', self.update)
|
||||
STATUS.connect('metric-mode-changed', self._switch_units)
|
||||
STATUS.connect('general',self.return_value)
|
||||
|
||||
if self._joint_type == linuxcnc.ANGULAR:
|
||||
self._current_text_template = self.angular_text_template
|
||||
elif self.display_units_mm:
|
||||
self._current_text_template = self.metric_text_template
|
||||
else:
|
||||
self._current_text_template = self.imperial_text_template
|
||||
|
||||
if INFO.MACHINE_IS_METRIC:
|
||||
self._currentTolerence = self._metricTolerence
|
||||
else:
|
||||
self._currentTolerence = self._imperialTolerence
|
||||
|
||||
def update(self, widget, absolute, relative, dtg, joint):
|
||||
if self.display_units_mm != INFO.MACHINE_IS_METRIC:
|
||||
absolute = INFO.convert_units_9(absolute)
|
||||
|
||||
tmpl = lambda s: self._current_text_template % s
|
||||
|
||||
try:
|
||||
num = absolute[self.axis_index] + self._offset[self.axis_index]
|
||||
self.setColor(num)
|
||||
self.setText(tmpl(num))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
pass
|
||||
|
||||
def setColor(self, data):
|
||||
if not data == self._lastNum:
|
||||
if isclose(data, 0,abs_tol = self._currentTolerence) :
|
||||
self.setStyleSheet("QLabel { background-color :"+self._zeroColor.name()+" ;}");
|
||||
elif data <0:
|
||||
self.setStyleSheet("QLabel { background-color :"+self._negativeColor.name()+" ;}");
|
||||
else:
|
||||
self.setStyleSheet("QLabel { background-color :"+self._positiveColor.name()+" ;}");
|
||||
self._lastNum = data
|
||||
|
||||
def _switch_units(self, widget, data):
|
||||
self.display_units_mm = data
|
||||
self.update_units()
|
||||
|
||||
def update_units(self):
|
||||
if self._joint_type == linuxcnc.ANGULAR:
|
||||
self._current_text_template = self.angular_text_template
|
||||
elif self.display_units_mm:
|
||||
self._current_text_template = self.metric_text_template
|
||||
else:
|
||||
self._current_text_template = self.imperial_text_template
|
||||
|
||||
def set_to_inch(self):
|
||||
self.display_units_mm = 0
|
||||
if self._joint_type == linuxcnc.ANGULAR:
|
||||
self._current_text_template = self.angular_text_template
|
||||
else:
|
||||
self._current_text_template = self.imperial_text_template
|
||||
|
||||
def set_to_mm(self):
|
||||
self.display_units_mm = 1
|
||||
if self._joint_type == linuxcnc.ANGULAR:
|
||||
self._current_text_template = self.angular_text_template
|
||||
else:
|
||||
self._current_text_template = self.metric_text_template
|
||||
|
||||
def get_current_position(self):
|
||||
if STATUS.is_joint_mode():
|
||||
return None
|
||||
p,r,d = STATUS.get_position()
|
||||
if self.display_units_mm != INFO.MACHINE_IS_METRIC:
|
||||
p = INFO.convert_units_9(p)
|
||||
return p[self.axis_index]
|
||||
|
||||
@QtCore.Slot(bool)
|
||||
def zero (self, data=True):
|
||||
p = self.get_current_position()
|
||||
self._lastOffset[self.axis_index] = self._offset[self.axis_index]
|
||||
self._offset[self.axis_index] = - p
|
||||
|
||||
@QtCore.Slot(int)
|
||||
def setAxisIndex(self, num):
|
||||
self.axis_index = num
|
||||
|
||||
@QtCore.Slot(str)
|
||||
def setAxisLetter(self, let):
|
||||
self.axis_index = self.axisToIndex(let)
|
||||
print(let,self.axis_index)
|
||||
|
||||
def axisToIndex(self, let):
|
||||
conversion = {"X":0, "Y":1, "Z":2, "A":3, "B":4, "C":5, "U":6, "V":7, "W":8}
|
||||
return conversion[let]
|
||||
|
||||
def indexToAxis(self, index):
|
||||
conversion = {0:"X", 1:"Y", 2:"Z", 3:"A", 4:"B", 5:"C", 6:"U", 7:"V", 8:"W"}
|
||||
return conversion[index]
|
||||
|
||||
#####################
|
||||
# Menu callback code
|
||||
#####################
|
||||
def Zero(self):
|
||||
self.zero()
|
||||
|
||||
def SetOrigin(self):
|
||||
now = self.get_current_position()
|
||||
axis = self.indexToAxis(self.axis_index)
|
||||
if axis:
|
||||
mess = {'NAME':self.dialog_code,'ID':'%s__' % self.objectName(),
|
||||
'AXIS':axis,'CURRENT':now,
|
||||
'TITLE':'Set %s Reference'% axis,
|
||||
'GEONAME':'UserDROLabelDialog_{}'.format(self.dialog_code),
|
||||
'AXIS':axis}
|
||||
STATUS.emit('dialog-request', mess)
|
||||
LOG.debug('message sent:{}'.format (mess))
|
||||
|
||||
def Last(self):
|
||||
axis = self.indexToAxis(self.axis_index)
|
||||
now = self.get_current_position() + self._offset[self.axis_index]
|
||||
if axis:
|
||||
temp = self._offset[self.axis_index]
|
||||
self._offset[self.axis_index] = self._lastOffset[self.axis_index]
|
||||
self._lastOffset[self.axis_index] = temp
|
||||
text = 'Reset Axis %s from %f to Last Value: %f' %(axis, now, self._lastOffset[self.axis_index] )
|
||||
|
||||
# process the STATUS return message
|
||||
def return_value(self, w, message):
|
||||
num = message['RETURN']
|
||||
code = bool(message.get('ID') == '%s__'% self.objectName())
|
||||
name = bool(message.get('NAME') == self.dialog_code)
|
||||
if code and name and num is not None:
|
||||
LOG.debug('message return:{}'.format (message))
|
||||
axis = message.get('AXIS')
|
||||
# do something
|
||||
|
||||
p = self.get_current_position()
|
||||
self._lastOffset[self.axis_index] = self._offset[self.axis_index]
|
||||
self._offset[self.axis_index] = - (p-num)
|
||||
|
||||
#########################################################################
|
||||
# This is how designer can interact with our widget properties.
|
||||
# designer will show the Property properties in the editor
|
||||
# it will use the get set and reset calls to do those actions
|
||||
########################################################################
|
||||
|
||||
def setmetrictemplate(self, data):
|
||||
self.metric_text_template = data
|
||||
self.update_units()
|
||||
def getmetrictemplate(self):
|
||||
return self.metric_text_template
|
||||
def resetmetrictemplate(self):
|
||||
self.metric_text_template = '%10.3f'
|
||||
metric_template = QtCore.Property(str, getmetrictemplate, setmetrictemplate, resetmetrictemplate)
|
||||
|
||||
def setimperialtexttemplate(self, data):
|
||||
self.imperial_text_template = data
|
||||
self.update_units()
|
||||
def getimperialtexttemplate(self):
|
||||
return self.imperial_text_template
|
||||
def resetimperialtexttemplate(self):
|
||||
self.imperial_text_template = '%9.4f'
|
||||
imperial_template = QtCore.Property(str, getimperialtexttemplate, setimperialtexttemplate, resetimperialtexttemplate)
|
||||
|
||||
def setangulartexttemplate(self, data):
|
||||
self.angular_text_template = data
|
||||
self.update_units()
|
||||
def getangulartexttemplate(self):
|
||||
return self.angular_text_template
|
||||
def resetangulartexttemplate(self):
|
||||
self.angular_text_template = '%9.2f'
|
||||
angularTemplate = QtCore.Property(str, getangulartexttemplate, setangulartexttemplate, resetangulartexttemplate)
|
||||
|
||||
def getNegativeColor(self):
|
||||
return self._negativeColor
|
||||
def setNegativeColor(self, value):
|
||||
self._negativeColor = value
|
||||
negativeColor = QtCore.Property(QColor, getNegativeColor, setNegativeColor)
|
||||
|
||||
def getPositiveColor(self):
|
||||
return self._positiveColor
|
||||
def setPositiveColor(self, value):
|
||||
self._positiveColor = value
|
||||
positiveColor = QtCore.Property(QColor, getPositiveColor, setPositiveColor)
|
||||
|
||||
####################
|
||||
## menu properties
|
||||
####################
|
||||
|
||||
def set_dialog_code(self, data):
|
||||
self.dialog_code = data
|
||||
def get_dialog_code(self):
|
||||
return self.dialog_code
|
||||
def reset_dialog_code(self):
|
||||
self.dialog_code = 'CALCULATOR'
|
||||
dialogName = QtCore.Property(str, get_dialog_code, set_dialog_code, reset_dialog_code)
|
||||
|
||||
##############################
|
||||
# required class boiler code #
|
||||
##############################
|
||||
|
||||
def __getitem__(self, item):
|
||||
return getattr(self, item)
|
||||
def __setitem__(self, item, value):
|
||||
return setattr(self, item, value)
|
||||
|
||||
# for testing without editor:
|
||||
def main():
|
||||
import sys
|
||||
from qtpy.QtWidgets import QApplication
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
widget = UserDROLabel()
|
||||
widget.show()
|
||||
sys.exit(app.exec())
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user