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

297 lines
10 KiB
Python

#!/usr/bin/env python3
# qtvcp
#
# Copyright (c) 2017 Chris Morley <chrisinnanaimo@hotmail.com>
#
# 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 hal
from qtpy import QtWidgets
from qtpy.QtCore import Property, Signal
from qtvcp.widgets.widget_baseclass import _HalWidgetBase
from qtvcp.core import Status, Action, Info
from qtvcp import logger
# Instantiate the libraries with global reference
# STATUS gives us status messages from linuxcnc
# ACTION gives commands to linuxcnc
# INFO is INI file details
# LOG is for running code logging
STATUS = Status()
ACTION = Action()
INFO = Info()
LOG = logger.getLogger(__name__)
# Force the log level for this module
# LOG.setLevel(logger.INFO) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL
# Based on https://stackoverflow.com/questions/42820380/use-float-for-qslider
class DoubleSlider(QtWidgets.QSlider):
# create our our signal that we can connect to if necessary
doubleValueChanged = Signal(float)
def __init__(self, *args, **kargs):
super(DoubleSlider, self).__init__( *args, **kargs)
self._multi = 1 ** 2 # arbitrarily set
# not needed at this time
self.valueChanged.connect(self.emitDoubleValueChanged)
def emitDoubleValueChanged(self):
value = float(super(DoubleSlider, self).value())/self._multi
self.doubleValueChanged.emit(value)
def value(self):
return float(super(DoubleSlider, self).value()) / self._multi
def setMinimum(self, value):
return super(DoubleSlider, self).setMinimum(int(value * self._multi))
def setMaximum(self, value):
return super(DoubleSlider, self).setMaximum(int(value * self._multi))
def setSingleStep(self, value):
return super(DoubleSlider, self).setSingleStep(value * self._multi)
def singleStep(self):
return float(super(DoubleSlider, self).singleStep()) / self._multi
def setValue(self, value):
super(DoubleSlider, self).setValue(int(value * self._multi))
class StatusSlider(DoubleSlider, _HalWidgetBase):
def __init__(self, parent=None):
super(StatusSlider, self).__init__(parent)
self._block_signal = False
self._halpin_option = True
self.rapid = True
self.feed = False
self.spindle = False
self.jograte = False
self.jograte_angular = False
self.max_velocity = False
# for syslesheet dynamic property
self._alertState = ''
self._alertOver = 100.0
self._alertUnder = 50.0
def _hal_init(self):
STATUS.connect('state-estop', lambda w: self.setEnabled(False))
STATUS.connect('state-estop-reset', lambda w: self.setEnabled(True))
if self.rapid:
STATUS.connect('rapid-override-changed', lambda w, data: self.setValue(data))
self.setMaximum(100)
elif self.feed:
STATUS.connect('feed-override-changed', lambda w, data: self.setValue(data))
self.setMaximum(int(INFO.MAX_FEED_OVERRIDE))
elif self.spindle:
STATUS.connect('spindle-override-changed', lambda w, data: self.setValue(data))
self.setMaximum(int(INFO.MAX_SPINDLE_OVERRIDE))
self.setMinimum(int(INFO.MIN_SPINDLE_OVERRIDE))
elif self.jograte:
STATUS.connect('jograte-changed', lambda w, data: self.setValue(data))
self.setMinimum(int(INFO.MIN_LINEAR_JOG_VEL))
self.setMaximum(int(INFO.MAX_LINEAR_JOG_VEL))
elif self.jograte_angular:
STATUS.connect('jograte-angular-changed', lambda w, data: self.setValue(data))
self.setMinimum(int(INFO.MIN_ANGULAR_JOG_VEL))
self.setMaximum(int(INFO.MAX_ANGULAR_JOG_VEL))
elif self.max_velocity:
STATUS.connect('max-velocity-override-changed', lambda w, data: self.setValue(data))
self.setMaximum(int(INFO.MAX_TRAJ_VELOCITY))
else:
LOG.error('{} : no option recognised'.format(self.HAL_NAME_))
if self._halpin_option:
if self._pin_name_ == '':
pname = self.HAL_NAME_
else:
pname = self._pin_name_
self.hal_pin = self.HAL_GCOMP_.newpin(str(pname), hal.HAL_FLOAT, hal.HAL_OUT)
# connect a signal and callback function to the button
self.doubleValueChanged.connect(self._action)
# If the widget uses dynamic properties in stylesheet...
self._style_polish(state= self.get_alert_cmd(self.value()))
# catch any programmed settings and update HAL pin
def setValue(self, v):
super(StatusSlider, self).setValue(v)
if self._halpin_option:
self.hal_pin.set(v)
def _action(self, value):
self._style_polish(state= self.get_alert_cmd(value))
if self._halpin_option:
self.hal_pin.set(value)
if self.rapid:
ACTION.SET_RAPID_RATE(value)
elif self.feed:
ACTION.SET_FEED_RATE(value)
elif self.spindle:
ACTION.SET_SPINDLE_RATE(value)
elif self.jograte:
ACTION.SET_JOG_RATE(value)
elif self.jograte_angular:
ACTION.SET_JOG_RATE_ANGULAR(value)
elif self.max_velocity:
ACTION.SET_MAX_VELOCITY_RATE(value)
else:
LOG.error('{} : no action recognised'.format(self.HAL_NAME_))
# convert numeric value to string command
def get_alert_cmd(self, value):
if value > self._alertOver:
return 'over'
elif value < self._alertUnder:
return 'under'
else:
return'normal'
# polish widget so stylesheet sees the property change
# some stylesheets color the widget based on the arbitrary hi/lo range
def _style_polish(self, prop = 'alertState',state = 'normal'):
if self._alertState != state:
self.setProperty(prop, state)
self.style().unpolish(self)
self.style().polish(self)
#########################################################################
# 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
#
# _toggle_properties makes it so we can only select one option
########################################################################
def _toggle_properties(self, picked):
data = ('rapid', 'feed', 'spindle', 'jograte', 'jograte_angular',
'max-velocity')
for i in data:
if not i == picked:
self[i+'_rate'] = False
def setrapid(self, data):
self.rapid = data
if data:
self._toggle_properties('rapid')
def getrapid(self):
return self.rapid
def resetrapid(self):
self.rapid = False
def setfeed(self, data):
self.feed = data
if data:
self._toggle_properties('feed')
def getfeed(self):
return self.feed
def resetfeed(self):
self.feed = False
def setspindle(self, data):
self.spindle = data
if data:
self._toggle_properties('spindle')
def getspindle(self):
return self.spindle
def resetspindle(self):
self.spindle = False
def setjograte(self, data):
self.jograte = data
if data:
self._toggle_properties('jograte')
def getjograte(self):
return self.jograte
def resetjograte(self):
self.jograte = False
def setjograte_angular(self, data):
self.jograte_angular = data
if data:
self._toggle_properties('jograte_angular')
def getjograte_angular(self):
return self.jograte_angular
def resetjograte_angular(self):
self.jograte_angular = False
def setmax_velocity(self, data):
self.max_velocity = data
if data:
self._toggle_properties('max_velocity')
def getmax_velocity(self):
return self.max_velocity
def resetmax_velocity(self):
self.max_velocity = False
def set_halpin_option(self, value):
self._halpin_option = value
def get_halpin_option(self):
return self._halpin_option
def reset_halpin_option(self):
self._halpin_option = True
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 = Property(str, get_pin_name, set_pin_name, reset_pin_name)
halpin_option = Property(bool, get_halpin_option, set_halpin_option, reset_halpin_option)
rapid_rate = Property(bool, getrapid, setrapid, resetrapid)
feed_rate = Property(bool, getfeed, setfeed, resetfeed)
spindle_rate = Property(bool, getspindle, setspindle, resetspindle)
jograte_rate = Property(bool, getjograte, setjograte, resetjograte)
jograte_angular_rate = Property(bool, getjograte_angular, setjograte_angular, resetjograte_angular)
max_velocity_rate = Property(bool, getmax_velocity, setmax_velocity, resetmax_velocity)
def setAlertState(self, data):
self._alertState = data
def getAlertState(self):
return self._alertState
def setAlertUnder(self, data):
self._alertUnder = data
def getAlertUnder(self):
return self._alertUnder
def resetAlertUnder(self):
self._alertUnder = 50.0
def setAlertOver(self, data):
self._alertOver = data
def getAlertOver(self):
return self._alertOver
def resetAlertOver(self):
self._alertOver = 100.0
alertState = Property(str, getAlertState, setAlertState)
alertUnder = Property(float, getAlertUnder, setAlertUnder, resetAlertUnder)
alertOver = Property(float, getAlertOver, setAlertOver, resetAlertOver)
##############################
# required class boiler code #
##############################
def __getitem__(self, item):
return getattr(self, item)
def __setitem__(self, item, value):
return setattr(self, item, value)