Files
linuxcncAllWasm/lib/python/qtvcp/widgets/indicatorMixIn.py
2026-08-20 06:17:39 +08:00

1198 lines
47 KiB
Python

from qtpy import QtCore, QtGui, QtWidgets
from qtpy.QtCore import Property, Slot
from qtvcp.widgets.widget_baseclass import (_HalWidgetBase)
from qtvcp.lib.aux_program_loader import Aux_program_loader as _loader
from qtvcp.core import Action, Status, Info
from qtvcp import logger
import hal
AUX_PRGM = _loader()
ACTION = Action()
STATUS = Status()
INFO = Info()
LOG = logger.getLogger(__name__)
# Force the log level for this module
# LOG.setLevel(logger.INFO) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL
# LED indicator on the right corner
class IndicatedMixIn( _HalWidgetBase):
def __init__(self):
super(IndicatedMixIn, self).__init__()
self._indicator_state = False # Current State
self._indicator2_state = False # Current State
# if user want to block their signals
self._external_block_signal = False
# flags
self._watch_command_flag = False
# changing text data
self._state_text = False # use text
self._true_string = 'True'
self._false_string = 'False'
# python commands data
self._python_command = False # use commands
self.true_python_command = '''print("true command")'''
self.false_python_command = '''print("false command")'''
# indicator LED data
self.draw_indicator = False # Show LED
self._doubleIndicator = False # show second ZED
self._HAL_pin = False # control by HAL
self._shape = 0 # 0 triangle, 1 circle
self._size = .3 # triangle
self._diameter = 10 # circle
self._corner_radius = 5
self._h_fraction = .3
self._w_fraction = .9
self._right_edge_offset = 0
self._top_edge_offset = 0
self._on_color = QtGui.QColor("red")
self._off_color = QtGui.QColor("black")
# current flash state
self._flashState = False
# is flashing on?
self._flashing = True
self._flashing2 = True
# should flash?
self._flashOption = False
self._flashRate = 200
self._timer = QtCore.QTimer()
self._timer.timeout.connect(self.toggleFlashState)
#self.setFlashing(True)
# indicator linuxcnc's status options
self._ind_status = False # control by status
self._is_estopped = False
self._is_on = False
self._is_homed = False
self._is_idle = False
self._is_paused = False
self._invert_status = False
self._is_flood = False
self._is_mist = False
self._is_block_delete = False
self._is_optional_stop = False
self._is_joint_homed = False
self._is_limits_overridden = False
self._is_manual = False
self._is_mdi = False
self._is_mdi_command_finished = False
self._is_auto = False
self._is_spindle_stopped = False
self._is_spindle_fwd = False
self._is_spindle_rev = False
self._joint_number = 0
# property data for style sheet dynamic changes
self._isManualProp = False
self._isMDIProp = False
self._isAutoProp = False
self._isEstopProp = False
self._isStateOnProp = False
self._isAllHomed = False
self._isHomed = False
# button enabled states
self._is_all_homed_sensitive = False
self._is_on_sensitive = False
self._is_idle_sensitive = False
self._is_run_sensitive = False
self._is_run_paused_sensitive = False
self._is_auto_pause_sensitive = False
self._is_manual_sensitive = False
self._is_mdi_sensitive = False
self._is_auto_sensitive = False
self._is_spindle_off_sensitive = False
self._is_spindle_fwd_sensitive = False
self._is_spindle_rev_sensitive = False
def _hal_init(self):
if self._HAL_pin:
if self._pin_name_ == '':
pname = self.HAL_NAME_
else:
pname = self._pin_name_
self.hal_pin_led = self.HAL_GCOMP_.newpin(pname + '-led', hal.HAL_BIT, hal.HAL_IN)
self.hal_pin_led.value_changed.connect(lambda data: self.indicator_update(data))
if self._doubleIndicator:
self.hal_pin_led2 = self.HAL_GCOMP_.newpin(pname + '-led2', hal.HAL_BIT, hal.HAL_IN)
self.hal_pin_led2.value_changed.connect(lambda data: self.indicator2_update(data))
elif self._ind_status:
self._init_state_change()
self._globalParameter = {'__builtins__' : None, 'MAIN_INSTANCE':self.QTVCP_INSTANCE_,
'INSTANCE':self.THIS_INSTANCE_,
'PROGRAM_LOADER':AUX_PRGM, 'ACTION':ACTION, 'HAL':hal, 'print':print}
self._localsParameter = {'dir': dir, 'True':True, 'False':False}
if self._is_on_sensitive:
STATUS.connect('state-off', lambda w: self.setEnabled(False))
STATUS.connect('state-on', lambda w: enable_logic_check(True))
if self._is_all_homed_sensitive:
STATUS.connect('all-homed', lambda w: enable_logic_check(True))
STATUS.connect('not-all-homed', lambda w, axis: self.setEnabled(False))
if self._is_idle_sensitive:
STATUS.connect('interp-run', lambda w: self.setEnabled(False))
STATUS.connect('interp-paused', lambda w: self.setEnabled(False))
STATUS.connect('interp-idle', lambda w: enable_logic_check(True))
elif self._is_run_sensitive:
STATUS.connect('interp-run', lambda w: enable_logic_check(True))
STATUS.connect('interp-paused', lambda w: self.setEnabled(False))
STATUS.connect('interp-idle', lambda w: self.setEnabled(False))
elif self._is_run_paused_sensitive:
STATUS.connect('interp-run', lambda w: enable_logic_check(True))
STATUS.connect('interp-paused', lambda w: self.setEnabled(True))
STATUS.connect('interp-idle', lambda w: self.setEnabled(False))
elif self._is_auto_pause_sensitive:
STATUS.connect('interp-run', lambda w: enable_logic_check(False))
STATUS.connect('interp-paused', lambda w: self.setEnabled(True))
STATUS.connect('interp-idle', lambda w: self.setEnabled(False))
if self._is_spindle_off_sensitive or \
self._is_spindle_fwd_sensitive or \
self._is_spindle_rev_sensitive:
STATUS.connect('spindle-control-changed', lambda w, num, state, speed, upto: enable_logic_check(True))
if self._is_manual_sensitive or self._is_mdi_sensitive or self._is_auto_sensitive:
STATUS.connect('mode-manual', lambda w: enable_logic_check(self._is_manual_sensitive))
STATUS.connect('mode-mdi', lambda w: enable_logic_check(self._is_mdi_sensitive))
STATUS.connect('mode-auto', lambda w: enable_logic_check(self._is_auto_sensitive))
# check for multiple selected enabled requests
def enable_logic_check(state):
if state:
temp = True
if self._is_run_sensitive or self._is_run_paused_sensitive:
temp = temp and STATUS.is_interp_running()
if self._is_auto_pause_sensitive:
temp = temp and STATUS.is_auto_paused()
if self._is_on_sensitive:
temp = temp and STATUS.machine_is_on()
if self._is_all_homed_sensitive:
temp = temp and (STATUS.is_all_homed() or INFO.NO_HOME_REQUIRED)
if self._is_manual_sensitive:
temp = temp and STATUS.is_man_mode()
if self._is_mdi_sensitive:
temp = temp and STATUS.is_mdi_mode()
if self._is_auto_sensitive:
temp = temp and STATUS.is_auto_mode()
if self._is_idle_sensitive:
temp = temp and STATUS.is_interp_idle()
on = STATUS.is_spindle_on()
spd = STATUS.get_spindle_speed()
if self._is_spindle_fwd_sensitive and self._is_spindle_rev_sensitive:
temp = temp and on
elif self._is_spindle_fwd_sensitive:
temp = temp and spd > 0
elif self._is_spindle_rev_sensitive:
temp = temp and spd < 0
if self._is_spindle_off_sensitive:
temp = temp and not on
self.setEnabled(temp)
else:
self.setEnabled(False)
self.connectSignals()
# Disconnect our standard signals
def disconnectSignals(self):
try:
self.toggled.disconnect()
except Exception: pass
try:
self.pressed.disconnect()
self.released.disconnect()
except Exception: pass
# done so we can adjust 'checkable' signals at run time
# ie delete all signals an re apply them
def connectSignals(self):
def _update(state):
self.setChecked(state)
# linuxcnc status changes option uses _flip_state()
# hal pins option calls indicator_update() from
# HAL's value_changed callback set in _hal_init() function
# otherwise:
# update indicator to button state if halpin or status won't
if self._HAL_pin is False and self._ind_status is False:
self.indicator_update(state)
self.indicator2_update(not state)
# if using state labels option update the labels
if self._state_text:
self.setText(None)
# if python commands call them
if self._python_command:
if state == None:
state = self._indicator_state
self.python_command(state)
if self.isCheckable():
self.toggled[bool].connect(_update)
else:
self.pressed.connect(lambda: _update(True))
self.released.connect(lambda: _update(False))
_update(self.isChecked())
# for users to indicate they want to block their signals
def _blockSignals(self, state):
self._external_block_signal = bool(state)
def _isSignalsBlocked(self):
return self._external_block_signal
def _init_state_change(self):
def only_false(data):
if data:
return
self._flip_state(False)
if self._is_estopped:
STATUS.connect('state-estop', lambda w: self._flip_state(True, prop='isEstopped'))
STATUS.connect('state-estop-reset', lambda w: self._flip_state(False, prop ='isEstopped'))
elif self._is_on:
STATUS.connect('state-on', lambda w: self._flip_state(True, prop ='isStateOn'))
STATUS.connect('state-off', lambda w: self._flip_state(False, prop ='isStateOn'))
elif self._is_homed:
STATUS.connect('all-homed', lambda w: self._flip_state(True, prop = 'isAllHomed'))
STATUS.connect('not-all-homed', lambda w, axis: self._flip_state(False, prop = 'isAllHomed'))
elif self._is_idle:
STATUS.connect('interp-idle', lambda w: self._flip_state(True))
STATUS.connect('interp-run', lambda w: self._flip_state(False))
elif self._is_mdi_command_finished:
STATUS.connect('interp-idle', lambda w: self._flip_state(False))
STATUS.connect('current-command', lambda w,s: self.update_command_running(s))
elif self._is_paused:
STATUS.connect('program-pause-changed', lambda w, data: self._flip_state(data))
elif self._is_flood:
STATUS.connect('flood-changed', lambda w, data: self._flip_state(data))
elif self._is_mist:
STATUS.connect('mist-changed', lambda w, data: self._flip_state(data))
elif self._is_block_delete:
STATUS.connect('block-delete-changed', lambda w, data: self._flip_state(data))
elif self._is_optional_stop:
STATUS.connect('optional-stop-changed', lambda w, data: self._flip_state(data))
elif self._is_joint_homed:
STATUS.connect('homed', lambda w, data: self._j_homed(data))
STATUS.connect('not-all-homed', lambda w, data: self._j_unhomed(data))
elif self._is_limits_overridden:
STATUS.connect('override-limits-changed', self._check_override_limits)
STATUS.connect('hard-limits-tripped', lambda w, data, group: only_false(data))
elif self._is_manual or self._is_mdi or self._is_auto:
STATUS.connect('mode-manual', lambda w: self._mode_changed(0))
STATUS.connect('mode-mdi', lambda w: self._mode_changed(1))
STATUS.connect('mode-auto', lambda w: self._mode_changed(2))
elif self._is_spindle_stopped or self._is_spindle_fwd or self._is_spindle_rev:
STATUS.connect('spindle-control-changed', lambda w, num, state, speed, upto: self._spindle_changed(speed))
def _flip_state(self, data, prop = None):
if self._invert_status:
data = not data
self.indicator_update(data)
if prop is not None:
self._style_polish(prop, data)
def _j_homed(self, joint):
if int(joint) == self._joint_number:
self._flip_state(True, prop = 'isHomed')
def _j_unhomed(self, jlist):
if str(self._joint_number) in jlist:
self._flip_state(False, prop = 'isHomed')
def _check_override_limits(self, w, state, data):
for i in data:
if i == 1:
self._flip_state(True)
return
self._flip_state(False)
def _mode_changed(self, mode):
state = False
if self._is_manual:
prop ='isManual'
if mode == 0:
state = True
elif self._is_mdi:
prop ='isMDI'
if mode == 1:
state = True
elif self._is_auto:
prop ='isAuto'
if mode == 2:
state = True
self._flip_state(state)
self._style_polish(prop, state)
def _spindle_changed(self, state):
if self._is_spindle_stopped and state == 0:
self._flip_state(True)
elif self._is_spindle_rev and state < 0:
self._flip_state(True)
elif self._is_spindle_fwd and state > 0:
self._flip_state(True)
else:
self._flip_state(False)
# force style sheet to update
def _style_polish(self, prop, state):
# print(prop,state)
self.setProperty(prop, state)
self.style().unpolish(self)
self.style().polish(self)
# arbitraray python commands are possible using 'INSTANCE' in the string
# gives access to widgets and handler functions
# builtin python commands are restricted see self._globalParameter
def python_command(self, state = None):
if self._python_command:
if state:
try:
exec(self.true_python_command, self._globalParameter, self._localsParameter)
except TypeError as e:
LOG.error('({} called exec in error:{}'.format(self.objectName(),e))
LOG.warning(' Command was {}'.format(self.true_python_command))
except AttributeError as e:
LOG.error('({} called exec in error:{}'.format(self.objectName(),e))
LOG.warning(' Command was {}'.format(self.true_python_command))
LOG.verbose(' List of objects:')
LOG.verbose(dir(self.QTVCP_INSTANCE_))
else:
try:
exec(self.false_python_command, self._globalParameter, self._localsParameter)
except TypeError as e:
LOG.error('({} called exec in error:{}'.format(self.objectName(),e))
LOG.warning(' Command was {}'.format(self.false_python_command))
except AttributeError as e:
LOG.error('({} called exec in error:{}'.format(self.objectName(),e))
LOG.warning(' Command was {}'.format(self.false_python_command))
LOG.verbose(' List of objects:')
LOG.verbose(dir(self.QTVCP_INSTANCE_))
# callback to toggle text when button is toggled
def toggle_text(self, state=None):
if not self._state_text:
return
else:
self.setText(None)
@Slot()
def toggleFlashState(self):
self._flashState = not self._flashState
self.update()
def isFlashing(self):
return self._flashing
@Slot(bool)
def setFlashing(self, value):
#self._flashing = value
if self._flashRate > 0 and value:
if self._timer.isActive():
return
self._timer.start(self._flashRate)
else:
self._timer.stop()
self.update()
def indicator_update(self, data):
self._flashing = self._indicator_state = data
self.update()
def indicator2_update(self, data):
self._flashing2 = self._indicator2_state = data
self.update()
# set the indicator that the MDI command is running
# or not
def update_command_running(self, code):
if self._watch_command_flag:
if not code =='':
self._flip_state(True)
if code =='':
self._flip_state(False)
self._watch_command_flag = False
# MDI command done, restore original mode
ACTION.RESTORE_RECORDED_MODE()
# override paint function to first paint the stock button
# then our indicator paint routine
def paintEvent(self, event):
self.paintEvent(event)
if self.draw_indicator:
self.paintIndicator()
# Paint specified size a triangle at the top right
def paintIndicator(self):
p = QtGui.QPainter(self)
if self._flashOption and self._flashing:
if self._flashState:
color = self._on_color
else:
color = self._off_color
else:
if self._indicator_state:
color = self._on_color
else:
color = self._off_color
# second LED
if self._flashOption and self._flashing2:
if self._flashState:
color2 = self._on_color
else:
color2 = self._off_color
else:
if self._indicator2_state:
color2 = self._on_color
else:
color2 = self._off_color
# right triangle
if self._shape == 0:
rect = p.window()
top_right = rect.topRight() - QtCore.QPoint(self._right_edge_offset,-self._top_edge_offset)
if self.width() < self.height():
size = int(self.width() * self._size)
else:
size = int(self.height() * self._size)
gradient = QtGui.QLinearGradient(QtCore.QPointF(top_right - QtCore.QPoint(size, 0)), QtCore.QPointF(top_right))
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color)
triangle = QtGui.QPolygon([top_right, top_right - QtCore.QPoint(size, 0),
top_right + QtCore.QPoint(0, size)])
p.drawLine(triangle.point(1), triangle.point(2))
p.drawPolygon(triangle)
# second LED
if self._doubleIndicator:
bot_right = rect.bottomRight() - QtCore.QPoint(self._right_edge_offset,self._top_edge_offset)
gradient = QtGui.QLinearGradient(QtCore.QPointF(bot_right - QtCore.QPoint(size, 0)), QtCore.QPointF(bot_right))
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color2)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color2)
triangle = QtGui.QPolygon([bot_right, bot_right - QtCore.QPoint(size, 0),
bot_right - QtCore.QPoint(0, size)])
p.drawLine(triangle.point(1), triangle.point(2))
p.drawPolygon(triangle)
# circle
elif self._shape == 1:
x = int(self.width() - self._diameter - self._right_edge_offset)
y = int(0 + self._top_edge_offset)
gradient = QtGui.QRadialGradient(x + self._diameter / 2, y + self._diameter / 2,
self._diameter * 0.4, self._diameter * 0.4, self._diameter * 0.4)
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color)
p.setRenderHint(QtGui.QPainter.Antialiasing, True)
p.drawEllipse(x, y, self._diameter - 1, self._diameter - 1)
# second LED
if self._doubleIndicator:
y = self.height() - self._diameter - self._top_edge_offset
gradient = QtGui.QRadialGradient(x + self._diameter / 2, y + self._diameter / 2,
self._diameter * 0.4, self._diameter * 0.4, self._diameter * 0.4)
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color2)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color2)
p.setRenderHint(QtGui.QPainter.Antialiasing, True)
p.drawEllipse(x, y, self._diameter - 1, self._diameter - 1)
# top bar
elif self._shape == 2:
rect = p.window()
topLeft = rect.topLeft()
#p.setPen(color)
#p.setBrush(QtGui.QBrush(color, QtCore.Qt.SolidPattern))
grad = QtGui.QLinearGradient()
grad.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
grad.setStart(0,0)
grad.setFinalStop(0,.8)
grad.setColorAt(0, color)
grad.setColorAt(.5, QtCore.Qt.white)
grad.setColorAt(.8, color)
p.setBrush(QtGui.QBrush(grad))
p.drawRoundedRect(int(topLeft.x()+(self.width()*((1-self._w_fraction)/2)) + self._top_edge_offset),
int(topLeft.y()+self._right_edge_offset),
int(self.width()*self._w_fraction+2),
int(self.height()*self._h_fraction),
self._corner_radius, self._corner_radius)
# side bar
elif self._shape == 3:
rect = p.window()
topRight = rect.topRight()
#p.setPen(color)
#p.setBrush(QtGui.QBrush(color, QtCore.Qt.SolidPattern))
grad = QtGui.QLinearGradient()
grad.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
grad.setStart(0,0)
grad.setFinalStop(0,.8)
grad.setColorAt(0, color)
grad.setColorAt(.5, QtCore.Qt.white)
grad.setColorAt(.8, color)
p.setBrush(QtGui.QBrush(grad))
p.drawRoundedRect(int(topRight.x()- self.width()*self._w_fraction-self._right_edge_offset),
int(topRight.y()+(self.height()*((1-self._h_fraction)/2)) + self._top_edge_offset),
int(self.width()*self._w_fraction),
int(self.height()*self._h_fraction),
self._corner_radius, self._corner_radius)
# left triangle
if self._shape == 4:
rect = p.window()
top_left = rect.topLeft() - QtCore.QPoint(self._right_edge_offset,-self._top_edge_offset)
if self.width() < self.height():
size = int(self.width() * self._size)
else:
size = int(self.height() * self._size)
gradient = QtGui.QLinearGradient(QtCore.QPointF(top_left + QtCore.QPoint(size, 0)), QtCore.QPointF(top_left))
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color)
triangle = QtGui.QPolygon([top_left, top_left + QtCore.QPoint(size, 0),
top_left + QtCore.QPoint(0, size)])
p.drawLine(triangle.point(1), triangle.point(2))
p.drawPolygon(triangle)
# second LED
if self._doubleIndicator:
top_bot = rect.bottomLeft() - QtCore.QPoint(self._right_edge_offset, self._top_edge_offset)
gradient = QtGui.QLinearGradient(QtCore.QPointF(top_bot + QtCore.QPoint(size, 0)), QtCore.QPointF(top_bot))
gradient.setColorAt(0, QtCore.Qt.white)
gradient.setColorAt(1, color2)
p.setBrush(QtGui.QBrush(gradient))
p.setPen(color2)
triangle = QtGui.QPolygon([top_bot, top_bot + QtCore.QPoint(size, 0),
top_bot - QtCore.QPoint(0, size)])
p.drawLine(triangle.point(1), triangle.point(2))
p.drawPolygon(triangle)
def set_indicator(self, data):
self.draw_indicator = data
self.update()
def get_indicator(self):
return self.draw_indicator
def reset_indicator(self):
self.draw_indicator = False
def set_shape(self, data):
self._shape = data
self.update()
def get_shape(self):
return self._shape
def reset_shape(self):
self._shape = 0
def set_HAL_pin(self, data):
self._HAL_pin = data
if data:
self._ind_status = False
def get_HAL_pin(self):
return self._HAL_pin
def reset_HAL_pin(self):
self._HAL_pin = False
def set_ind_status(self, data):
self._ind_status = data
if data:
self._HAL_pin = False
def get_ind_status(self):
return self._ind_status
def reset_ind_status(self):
self._ind_status = False
def set_state_text(self, data):
self._state_text = data
if data:
self.setText(None)
def get_state_text(self):
return self._state_text
def reset_state_text(self):
self._state_text = False
def set_python_command(self, data):
self._python_command = data
def get_python_command(self):
return self._python_command
def reset_python_command(self):
self._python_command = False
def get_on_color(self):
return self._on_color
def set_on_color(self, value):
self._on_color = value
self.update()
def get_off_color(self):
return self._off_color
def set_off_color(self, value):
self._off_color = value
self.update()
# flash when state on
def setFlashState(self, value):
self._flashOption = value
self.setFlashing(True)
self.update()
def getFlashState(self):
return self._flashOption
def getFlashRate(self):
return self._flashRate
@Slot(int)
def setFlashRate(self, value):
self._flashRate = value
self._timer.setInterval(self._flashRate)
self.update()
def set_indicator_size(self, data):
self._size = data
self.update()
def get_indicator_size(self):
return self._size
def reset_indicator_size(self):
self._size = 0.3
self.update()
def set_doubleIndicator(self, data):
self._doubleIndicator = data
self.update()
def get_doubleIndicator(self):
return self._doubleIndicator
def reset_doubleIndicator(self):
self._doubleIndicator = True
self.update()
def set_circle_diameter(self, data):
self._diameter = data
self.update()
def get_circle_diameter(self):
return self._diameter
def reset_circle_diameter(self):
self._diameter = 10
self.update()
def set_corner_radius(self, data):
self._corner_radius = data
self.update()
def get_corner_radius(self):
return self._corner_radius
def reset_corner_radius(self):
self._corner_radius = 5
self.update()
def set_h_fraction(self, data):
self._h_fraction = data
self.update()
def get_h_fraction(self):
return self._h_fraction
def reset_h_fraction(self):
self._h_fraction = .5
self.update()
def set_w_fraction(self, data):
self._w_fraction = data
self.update()
def get_w_fraction(self):
return self._w_fraction
def reset_w_fraction(self):
self._w_fraction = .5
self.update()
def set_right_edge_offset(self, data):
self._right_edge_offset = int(data)
self.update()
def get_right_edge_offset(self):
return self._right_edge_offset
def reset_right_edge_offset(self):
self._right_edge_offset = 0
self.update()
def set_top_edge_offset(self, data):
self._top_edge_offset = int(data)
self.update()
def get_top_edge_offset(self):
return self._top_edge_offset
def reset_top_edge_offset(self):
self._top_edge_offset = 0
self.update()
def set_true_string(self, data):
data = data.replace('\\n' , '\n')
self._true_string = data
if self._state_text:
self.setText(None)
def get_true_string(self):
return self._true_string
def reset_true_string(self):
self._true_string = 'False'
def set_false_string(self, data):
data = data.replace('\\n' , '\n')
self._false_string = data
if self._state_text:
self.setText(None)
def get_false_string(self):
return self._false_string
def reset_false_string(self):
self._false_string = 'False'
def set_true_python_command(self, data):
self.true_python_command = data
def get_true_python_command(self):
return self.true_python_command
def reset_true_python_command(self):
self.true_python_command = ''
def set_false_python_command(self, data):
self.false_python_command = data
def get_false_python_command(self):
return self.false_python_command
def reset_false_python_command(self):
self.false_python_command = ''
def set_pin_name(self, value):
self._pin_name_ = value
def get_pin_name(self):
return self._pin_name_
def reset_pin_name(self):
self._pin_name_ = ''
pin_name = QtCore.Property(str, get_pin_name, set_pin_name, reset_pin_name)
indicator_option = QtCore.Property(bool, get_indicator, set_indicator, reset_indicator)
doubleIndicator = QtCore.Property(bool, get_doubleIndicator, set_doubleIndicator, reset_doubleIndicator)
indicator_HAL_pin_option = QtCore.Property(bool, get_HAL_pin, set_HAL_pin, reset_HAL_pin)
indicator_status_option = QtCore.Property(bool, get_ind_status, set_ind_status, reset_ind_status)
checked_state_text_option = QtCore.Property(bool, get_state_text, set_state_text, reset_state_text)
python_command_option = QtCore.Property(bool, get_python_command, set_python_command, reset_python_command)
on_color = QtCore.Property(QtGui.QColor, get_on_color, set_on_color)
shape_option = QtCore.Property(int, get_shape, set_shape, reset_shape)
off_color = QtCore.Property(QtGui.QColor, get_off_color, set_off_color)
flashIndicator = Property(bool, getFlashState, setFlashState)
flashRate = Property(int, getFlashRate, setFlashRate)
indicator_size = QtCore.Property(float, get_indicator_size, set_indicator_size, reset_indicator_size)
circle_diameter = QtCore.Property(int, get_circle_diameter, set_circle_diameter, reset_circle_diameter)
right_edge_offset = QtCore.Property(int, get_right_edge_offset, set_right_edge_offset, reset_right_edge_offset)
top_edge_offset = QtCore.Property(int, get_top_edge_offset, set_top_edge_offset, reset_top_edge_offset)
corner_radius = QtCore.Property(float, get_corner_radius, set_corner_radius, reset_corner_radius)
height_fraction = QtCore.Property(float, get_h_fraction, set_h_fraction, reset_h_fraction)
width_fraction = QtCore.Property(float, get_w_fraction, set_w_fraction, reset_w_fraction)
true_state_string = QtCore.Property(str, get_true_string, set_true_string, reset_true_string)
false_state_string = QtCore.Property(str, get_false_string, set_false_string, reset_false_string)
true_python_cmd_string = QtCore.Property(str, get_true_python_command, set_true_python_command, reset_true_python_command)
false_python_cmd_string = QtCore.Property(str, get_false_python_command, set_false_python_command, reset_false_python_command)
#########################################################################
# This is how designer can interact with our widget properties.
# designer will show the QtCore.Property properties in the editor
# it will use the get set and reset calls to do those actions
#
# _toggle_status_properties makes it so we can only select one option
########################################################################
def _toggle_status_properties(self, picked):
data = ('is_paused', 'is_estopped', 'is_on', 'is_idle', 'is_homed',
'is_flood', 'is_mist', 'is_block_delete', 'is_optional_stop',
'is_joint_homed', 'is_limits_overridden','is_manual',
'is_mdi', 'is_auto', 'is_spindle_stopped', 'is_spindle_fwd',
'is_spindle_rev', 'is_mdi_finished')
for i in data:
if not i == picked:
self[i+'_status'] = False
# property getter/setters
# invert status
def set_invert_status(self, data):
self._invert_status = data
def get_invert_status(self):
return self._invert_status
def reset_invert_status(self):
self._invert_status = False
# machine is paused status
def set_is_paused(self, data):
self._is_paused = data
if data:
self._toggle_status_properties('is_paused')
def get_is_paused(self):
return self._is_paused
def reset_is_paused(self):
self._is_paused = False
# machine is estopped status
def set_is_estopped(self, data):
self._is_estopped = data
if data:
self._toggle_status_properties('is_estopped')
def get_is_estopped(self):
return self._is_estopped
def reset_is_estopped(self):
self._is_estopped = False
# machine is on status
def set_is_on(self, data):
self._is_on = data
if data:
self._toggle_status_properties('is_on')
def get_is_on(self):
return self._is_on
def reset_is_on(self):
self._is_on = False
# machine is idle status
def set_is_idle(self, data):
self._is_idle = data
if data:
self._toggle_status_properties('is_idle')
def get_is_idle(self):
return self._is_idle
def reset_is_idle(self):
self._is_idle = False
# machine is mdi finished status
def set_is_mdi_fin(self, data):
self._is_mdi_command_finished = data
if data:
self._toggle_status_properties('is_mdi_finished')
def get_is_mdi_fin(self):
return self._is_mdi_command_finished
def reset_is_mdi_fin(self):
self._is_mdi_command_finished = False
# machine_is_homed status
def set_is_homed(self, data):
self._is_homed = data
if data:
self._toggle_status_properties('is_homed')
def get_is_homed(self):
return self._is_homed
def reset_is_homed(self):
self._is_homed = False
# machine is_flood status
def set_is_flood(self, data):
self._is_flood = data
if data:
self._toggle_status_properties('is_flood')
def get_is_flood(self):
return self._is_flood
def reset_is_flood(self):
self._is_flood = False
# machine is_mist status
def set_is_mist(self, data):
self._is_mist = data
if data:
self._toggle_status_properties('is_mist')
def get_is_mist(self):
return self._is_mist
def reset_is_mist(self):
self._is_mist = False
# machine_is_block_delete status
def set_is_block_delete(self, data):
self._is_block_delete = data
if data:
self._toggle_status_properties('is_block_delete')
def get_is_block_delete(self):
return self._is_block_delete
def reset_is_block_delete(self):
self._is_block_delete = False
# machine_is_optional_stop status
def set_is_optional_stop(self, data):
self._is_optional_stop = data
if data:
self._toggle_status_properties('is_optional_stop')
def get_is_optional_stop(self):
return self._is_optional_stop
def reset_is_optional_stop(self):
self._is_optional_stop = False
# machine_is_joint_homed status
def set_is_joint_homed(self, data):
self._is_joint_homed = data
if data:
self._toggle_status_properties('is_joint_homed')
def get_is_joint_homed(self):
return self._is_joint_homed
def reset_is_joint_homed(self):
self._is_joint_homed = False
# machine_is_limits_overridden status
def set_is_limits_overridden(self, data):
self._is_limits_overridden = data
if data:
self._toggle_status_properties('is_limits_overridden')
def get_is_limits_overridden(self):
return self._is_limits_overridden
def reset_is_limits_overridden(self):
self._is_limits_overridden = False
# machine is manual status
def set_is_manual(self, data):
self._is_manual = data
if data:
self._toggle_status_properties('is_manual')
def get_is_manual(self):
return self._is_manual
def reset_is_manual(self):
self._is_manual = False
# machine is mdi status
def set_is_mdi(self, data):
self._is_mdi = data
if data:
self._toggle_status_properties('is_mdi')
def get_is_mdi(self):
return self._is_mdi
def reset_is_mdi(self):
self._is_mdi = False
# machine is auto status
def set_is_auto(self, data):
self._is_auto = data
if data:
self._toggle_status_properties('is_auto')
def get_is_auto(self):
return self._is_auto
def reset_is_auto(self):
self._is_auto = False
# machine is spindle_stopped status
def set_is_spindle_stopped(self, data):
self._is_spindle_stopped = data
if data:
self._toggle_status_properties('is_spindle_stopped')
def get_is_spindle_stopped(self):
return self._is_spindle_stopped
def reset_is_spindle_stopped(self):
self._is_spindle_stopped = False
# machine is spindle_fwd status
def set_is_spindle_fwd(self, data):
self._is_spindle_fwd = data
if data:
self._toggle_status_properties('is_spindle_fwd')
def get_is_spindle_fwd(self):
return self._is_spindle_fwd
def reset_is_spindle_fwd(self):
self._is_spindle_fwd = False
# machine is spindle_rev status
def set_is_spindle_rev(self, data):
self._is_spindle_rev = data
if data:
self._toggle_status_properties('is_spindle_rev')
def get_is_spindle_rev(self):
return self._is_spindle_rev
def reset_is_spindle_rev(self):
self._is_spindle_rev = False
# Non bool
# machine_joint_number status
def set_joint_number(self, data):
self._joint_number = data
def get_joint_number(self):
return self._joint_number
def reset_joint_number(self):
self._joint_number = 0
# designer will show these properties in this order:
# BOOL
invert_the_status = QtCore.Property(bool, get_invert_status, set_invert_status, reset_invert_status)
is_paused_status = QtCore.Property(bool, get_is_paused, set_is_paused, reset_is_paused)
is_estopped_status = QtCore.Property(bool, get_is_estopped, set_is_estopped, reset_is_estopped)
is_on_status = QtCore.Property(bool, get_is_on, set_is_on, reset_is_on)
is_idle_status = QtCore.Property(bool, get_is_idle, set_is_idle, reset_is_idle)
is_mdi_finished_status = QtCore.Property(bool, get_is_mdi_fin, set_is_mdi_fin, reset_is_mdi_fin)
is_homed_status = QtCore.Property(bool, get_is_homed, set_is_homed, reset_is_homed)
is_flood_status = QtCore.Property(bool, get_is_flood, set_is_flood, reset_is_flood)
is_mist_status = QtCore.Property(bool, get_is_mist, set_is_mist, reset_is_mist)
is_block_delete_status = QtCore.Property(bool, get_is_block_delete, set_is_block_delete, reset_is_block_delete)
is_optional_stop_status = QtCore.Property(bool, get_is_optional_stop, set_is_optional_stop, reset_is_optional_stop)
is_joint_homed_status = QtCore.Property(bool, get_is_joint_homed, set_is_joint_homed, reset_is_joint_homed)
is_limits_overridden_status = QtCore.Property(bool, get_is_limits_overridden, set_is_limits_overridden,
reset_is_limits_overridden)
is_manual_status = QtCore.Property(bool, get_is_manual, set_is_manual, reset_is_manual)
is_mdi_status = QtCore.Property(bool, get_is_mdi, set_is_mdi, reset_is_mdi)
is_auto_status = QtCore.Property(bool, get_is_auto, set_is_auto, reset_is_auto)
is_spindle_stopped_status = QtCore.Property(bool, get_is_spindle_stopped, set_is_spindle_stopped, reset_is_spindle_stopped)
is_spindle_fwd_status = QtCore.Property(bool, get_is_spindle_fwd, set_is_spindle_fwd, reset_is_spindle_fwd)
is_spindle_rev_status = QtCore.Property(bool, get_is_spindle_rev, set_is_spindle_rev, reset_is_spindle_rev)
# NON BOOL
joint_number_status = QtCore.Property(int, get_joint_number, set_joint_number, reset_joint_number)
# properties for stylesheet dynamic changes
def setisManual(self, data):
self._isManualProp = data
def getisManual(self):
return self._isManualProp
isManual = QtCore.Property(bool, getisManual, setisManual)
def setisMDI(self, data):
self._isMDIProp = data
def getisMDI(self):
return self._isMDIProp
isMDI = QtCore.Property(bool, getisMDI, setisMDI)
def setisAuto(self, data):
self._isAutoProp = data
def getisAuto(self):
return self._isAutoProp
isAuto = QtCore.Property(bool, getisAuto, setisAuto)
def setisEstop(self, data):
self._isEstopProp = data
def getisEstop(self):
return self._isEstopProp
isEstop = QtCore.Property(bool, getisEstop, setisEstop)
def setisStateOn(self, data):
self._isStateOnProp = data
def getisStateOn(self):
return self._isStateOnProp
isStateOn = QtCore.Property(bool, getisStateOn, setisStateOn)
def setisHomed(self, data):
self._isHomed = data
def getisHomed(self):
return self._isHomed
isHomed = QtCore.Property(bool, getisHomed, setisHomed)
def setisAllHomed(self, data):
self._isAllHomed = data
def getisAllHomed(self):
return self._isAllHomed
isAllHomed = QtCore.Property(bool, getisAllHomed, setisAllHomed)
# properties for enable/disable button on status state
def setisAllHomedSensitive(self, data):
self._is_all_homed_sensitive = data
def getisAllHomedSensitive(self):
return self._is_all_homed_sensitive
isAllHomedSensitive = QtCore.Property(bool, getisAllHomedSensitive, setisAllHomedSensitive)
def setisOnSensitive(self, data):
self._is_on_sensitive = data
def getisOnSensitive(self):
return self._is_on_sensitive
isOnSensitive = QtCore.Property(bool, getisOnSensitive, setisOnSensitive)
def setisIdleSensitive(self, data):
self._is_idle_sensitive = data
def getisIdleSensitive(self):
return self._is_idle_sensitive
isIdleSensitive = QtCore.Property(bool, getisIdleSensitive, setisIdleSensitive)
def setisRunSensitive(self, data):
self._is_run_sensitive = data
def getisRunSensitive(self):
return self._is_run_sensitive
isRunSensitive = QtCore.Property(bool, getisRunSensitive, setisRunSensitive)
def setisRunPauseSensitive(self, data):
self._is_run_paused_sensitive = data
def getisRunPauseSensitive(self):
return self._is_run_paused_sensitive
isRunPausedSensitive = QtCore.Property(bool, getisRunPauseSensitive, setisRunPauseSensitive)
def setisAutoPauseSensitive(self, data):
self._is_auto_pause_sensitive = data
def getisAutoPauseSensitive(self):
return self._is_auto_pause_sensitive
isAutoPauseSensitive = QtCore.Property(bool, getisAutoPauseSensitive, setisAutoPauseSensitive)
def setisManSensitive(self, data):
self._is_manual_sensitive = data
def getisManSensitive(self):
return self._is_manual_sensitive
isManSensitive = QtCore.Property(bool, getisManSensitive, setisManSensitive)
def setisMDISensitive(self, data):
self._is_mdi_sensitive = data
def getisMDISensitive(self):
return self._is_mdi_sensitive
isMDISensitive = QtCore.Property(bool, getisMDISensitive, setisMDISensitive)
def setisAutoSensitive(self, data):
self._is_auto_sensitive = data
def getisAutoSensitive(self):
return self._is_auto_sensitive
isAutoSensitive = QtCore.Property(bool, getisAutoSensitive, setisAutoSensitive)
def setisSpindleOffSensitive(self, data):
self._is_spindle_off_sensitive = data
def getisSpindleOffSensitive(self):
return self._is_spindle_off_sensitive
isSpindleOffSensitive = QtCore.Property(bool, getisSpindleOffSensitive, setisSpindleOffSensitive)
def setisSpindleFwdSensitive(self, data):
self._is_spindle_fwd_sensitive = data
def getisSpindleFwdSensitive(self):
return self._is_spindle_fwd_sensitive
isSpindleFwdSensitive = QtCore.Property(bool, getisSpindleFwdSensitive, setisSpindleFwdSensitive)
def setisSpindleRevSensitive(self, data):
self._is_spindle_rev_sensitive = data
def getisSpindleRevSensitive(self):
return self._is_spindle_rev_sensitive
isSpindleRevSensitive = QtCore.Property(bool, getisSpindleRevSensitive, setisSpindleRevSensitive)
# boilder code
def __getitem__(self, item):
return getattr(self, item)
def __setitem__(self, item, value):
return setattr(self, item, value)
class IndicatedToolButton(QtWidgets.QToolButton, IndicatedMixIn):
def __init__(self, parent=None):
super(IndicatedToolButton, self).__init__(parent)
# for testing without editor:
def main():
import sys
from qtpy.QtWidgets import QApplication
app = QApplication(sys.argv)
widget = IndicatedToolButton()
widget.setCheckable(True)
widget._shape = 4
# this doesn't get called without qtvcp loading the widget
widget.HAL_NAME_ = 'test'
widget.PREFS_ = None
widget.QTVCP_INSTANCE_ = None
widget.THIS_INSTANCE_ = None
widget.draw_indicator = True
widget._indicator_state = True
widget._hal_init()
widget.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()