Source code for qtpyvcp.widgets.hal_widgets.hal_button
from PySide6.QtCore import Property, QTimer
from PySide6.QtWidgets import QPushButton
from qtpyvcp import hal
from qtpyvcp.widgets import HALWidget, VCPWidget
from qtpyvcp.utilities.logger import getLogger
from qtpyvcp.plugins import getPlugin
LOG = getLogger(__name__)
STATUS = getPlugin('status')
[docs]
class HalButton(QPushButton, HALWidget, VCPWidget):
"""HAL Button
Button for setting `bit` HAL pin values.
.. table:: Generated HAL Pins
========================= ===== =========
HAL Pin Name Type Direction
========================= ===== =========
qtpyvcp.button.enable bit in
qtpyvcp.button.out bit out
qtpyvcp.button.check bit in
qtpyvcp.button.checked bit out
qtpyvcp.button.io bit io
========================= ===== =========
.. note::
The `qtpyvcp.button.check` and `qtpyvcp.button.checked` halpins are
only present if the :class:`.checkable` property is set to true.
`check` sets the checked state from HAL, and `checked` reports it.
"""
def __init__(self, parent=None):
super(HalButton, self).__init__(parent)
self.setText("HAL Button")
self._enable_pin = None
self._pressed_pin = None
self._checked_pin = None
self._activated_pin = None
self._pulse = False
self._pulse_duration = 100
self.pulse_timer = None
# Flash-while-checked. The mechanism is on VCPBaseWidget; this is
# only the trigger. The checked state itself is never toggled --
# that would fight the .check HAL pin and re-emit toggled.
self._flash_on_checked = False
self.pressed.connect(self.onPress)
self.released.connect(self.onRelease)
self.toggled.connect(self.onCheckedStateChanged)
self.toggled.connect(self._updateFlashing)
def mousePressEvent(self, event):
# Test for UI LOCK and consume event but do nothing if LOCK in place
if STATUS.isLocked():
LOG.debug('Accept mouse Press Event')
event.accept()
return
super().mousePressEvent(event)
def mouseReleaseEvent(self, event):
if STATUS.isLocked():
LOG.debug('Accept mouse Release Event')
event.accept()
return
super().mouseReleaseEvent(event)
def keyPressEvent(self, event):
# Test for UI LOCK and consume event but do nothing if LOCK in place
if STATUS.isLocked():
LOG.debug('Accept keyPressEvent Event')
event.accept()
return
super().keyPressEvent(event)
def keyReleaseEvent(self, event):
# Test for UI LOCK and consume event but do nothing if LOCK in place
if STATUS.isLocked():
LOG.debug('Accept keyReleaseEvent Event')
event.accept()
return
super().keyReleaseEvent(event)
def onPress(self):
if self._pressed_pin is not None:
self._pressed_pin.value = True
if self._activated_pin is not None:
self._activated_pin.value = True
if self._pulse:
self.pulse_timer.start(self._pulse_duration)
def onRelease(self):
if self._pressed_pin is not None:
self._pressed_pin.value = False
if self._activated_pin is not None:
self._activated_pin.value = False
def onCheckedStateChanged(self, checked):
if STATUS.isLocked():
LOG.debug('Skip HAL onCheckedStateChanged')
return
if self._checked_pin is not None:
self._checked_pin.value = checked
# ------------------------------------------------------------ flashing
#
# The flash mechanism itself lives on VCPBaseWidget so every widget can
# use it, driven either by a rule or directly. This only adds the
# checked-state trigger, which is specific to a button.
def _updateFlashing(self, checked=None):
if checked is None:
checked = self.isChecked()
self.setFlashing(bool(checked) and self._flash_on_checked)
@Property(bool)
def flashOnChecked(self):
"""Flash the button while it is checked.
Alternates the `flashState` dynamic property between `true` and
`false`. Style both, e.g.::
QPushButton:checked[flashState="true"] { background: red; }
QPushButton:checked[flashState="false"] { background: yellow; }
Returns:
bool
"""
return self._flash_on_checked
@flashOnChecked.setter
def flashOnChecked(self, flash):
self._flash_on_checked = bool(flash)
self._updateFlashing()
@Property(bool)
def pulseOnPress(self):
"""If active, when the button is pressed the ``out`` pin will be `True`
for :class:`.pulseDuration` ms, otherwise the ``out`` pin will
be `True` for the duration of the button press.
"""
return self._pulse
@pulseOnPress.setter
def pulseOnPress(self, pulse):
self._pulse = pulse
@Property(int)
def pulseDuration(self):
"""Pulse duration in ms used when :class:`.pulseOnPress` is active."""
return self._pulse_duration
@pulseDuration.setter
def pulseDuration(self, duration):
self._pulse_duration = duration
[docs]
def initialize(self):
comp = hal.getComponent()
obj_name = self.getPinBaseName()
# add button.enable HAL pin
self._enable_pin = comp.addPin(obj_name + ".enable", "bit", "in")
self._enable_pin.value = self.isEnabled()
self._enable_pin.valueChanged.connect(self.setEnabled)
# add button.out HAL pin
self._pressed_pin = comp.addPin(obj_name + ".out", "bit", "out")
# add button.activated HAL pin
self._activated_pin = comp.addPin(obj_name + ".io", "bit", "io")
self._activated_pin.value = self.isDown()
self._activated_pin.valueChanged.connect(self.setDown)
if self.isCheckable():
# add button.check HAL pin -- lets HAL drive the checked state,
# matching HalCheckBox and HalGroupBox. .checked is an output and
# cannot be written to, so without this nothing in HAL can set the
# button's appearance.
self._check_pin = comp.addPin(obj_name + ".check", "bit", "in")
self._check_pin.value = self.isChecked()
self._check_pin.valueChanged.connect(self.setChecked)
# add button.checked HAL pin
self._checked_pin = comp.addPin(obj_name + ".checked", "bit", "out")
self._checked_pin.value = self.isChecked()
if self._pulse:
self.pulse_timer = QTimer()
self.pulse_timer.setSingleShot(True)
self.pulse_timer.timeout.connect(self.onRelease)