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()