Import LinuxCNC source tree
This commit is contained in:
437
lib/python/qtvcp/widgets/round_gauge.py
Normal file
437
lib/python/qtvcp/widgets/round_gauge.py
Normal file
@@ -0,0 +1,437 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import math
|
||||
from qtpy import QtCore, QtWidgets
|
||||
from qtpy.QtCore import Qt, QPoint, QPointF, QLine, QRect, QSize, Slot, Property
|
||||
from qtpy.QtGui import QPainter, QBrush, QPen, QFont, QColor, QRadialGradient
|
||||
from qtvcp.widgets.widget_baseclass import _HalWidgetBase, hal
|
||||
|
||||
class Gauge(QtWidgets.QWidget, _HalWidgetBase):
|
||||
def __init__(self, parent=None):
|
||||
super(Gauge, self).__init__(parent)
|
||||
self._threshold = 0
|
||||
self._setpoint = QPointF(0, 0)
|
||||
self._num_ticks = 11
|
||||
self._max_value = 100
|
||||
self._max_reading = 100
|
||||
self._gauge_label = "GAUGE"
|
||||
self._dial_font_size = 10
|
||||
self._value_font_size = 10
|
||||
self._label_font_size = 10
|
||||
self._base_gradient_color = QColor(180, 180, 180)
|
||||
self._base_color = QColor(40, 40, 40)
|
||||
self._center_gradient_color = QColor("gray")
|
||||
self._center_color = QColor("#404040")
|
||||
self._zone1_color = QColor("green")
|
||||
self._zone2_color = QColor("red")
|
||||
self._bezel_color = QColor("gray")
|
||||
self._bezel_width = 6
|
||||
self.qpa = list()
|
||||
self.canvas = QRect()
|
||||
self.canvas.setSize(QSize(self.width(), self.height()))
|
||||
self.tick_width = 2
|
||||
self.arc_width = 10
|
||||
self.value = 0
|
||||
self._halpin_option = True
|
||||
self.create_unit_array()
|
||||
|
||||
def _hal_init(self):
|
||||
if (self._halpin_option):
|
||||
self.hal_pin = self.HAL_GCOMP_.newpin(self.HAL_NAME_ + "_value", hal.HAL_FLOAT, hal.HAL_IN)
|
||||
self.hal_pin.value_changed.connect(lambda value: self.update_value(value))
|
||||
self.hal_pin = self.HAL_GCOMP_.newpin(self.HAL_NAME_ + "_setpoint", hal.HAL_FLOAT, hal.HAL_IN)
|
||||
self.hal_pin.value_changed.connect(lambda value: self.set_setpoint(value))
|
||||
|
||||
def create_unit_array(self):
|
||||
self.qpa = list(range(self._num_ticks))
|
||||
inc = 270.0 / (self._num_ticks - 1)
|
||||
for i in range(self._num_ticks):
|
||||
angle = (inc * i) - 225
|
||||
x = math.cos(math.radians(angle))
|
||||
y = math.sin(math.radians(angle))
|
||||
self.qpa[i] = QPointF(x, y)
|
||||
|
||||
def paintEvent(self, event):
|
||||
w = int(min(event.rect().width(), event.rect().height()))
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(painter.Antialiasing)
|
||||
self.draw_background(painter, event, w)
|
||||
self.draw_zones(painter, event, w)
|
||||
self.draw_gauge(painter, event, w)
|
||||
self.draw_digits(painter, event, w)
|
||||
self.draw_setpoint(painter, event, w)
|
||||
self.draw_needle(painter, event, w)
|
||||
self.draw_center(painter, event, w)
|
||||
self.draw_readout(painter, event, w)
|
||||
painter.end()
|
||||
|
||||
def draw_background(self, qp, event, w):
|
||||
w -= 6
|
||||
center = event.rect().center()
|
||||
rect = QRect()
|
||||
rect.setSize(QSize(w, w))
|
||||
rect.moveCenter(center)
|
||||
fp = QPointF(center.x() - w/4, center.y() - w/4)
|
||||
bg = QRadialGradient(QPointF(center), w/2, fp)
|
||||
bg.setColorAt(0, self._base_gradient_color)
|
||||
bg.setColorAt(1, self._base_color)
|
||||
qp.setPen(QPen(self._bezel_color, self._bezel_width))
|
||||
qp.setBrush(QBrush(bg))
|
||||
qp.drawEllipse(rect)
|
||||
qp.drawArc(rect, 0, 360 * 16)
|
||||
|
||||
def draw_zones(self, qp, event, w):
|
||||
segment1 = -45
|
||||
span1 = int(((self._max_value - self._threshold) * 270) / self._max_value)
|
||||
segment2 = span1 - 45
|
||||
span2 = 270 - span1
|
||||
rect = QRect()
|
||||
w = int(w/2)
|
||||
rect.setSize(QSize(w, w))
|
||||
rect.moveCenter(event.rect().center())
|
||||
qp.setPen(QPen(self._zone1_color, self.arc_width, cap = Qt.FlatCap))
|
||||
qp.drawArc(rect, segment1*16, span1*16)
|
||||
qp.setPen(QPen(self._zone2_color, self.arc_width, cap = Qt.FlatCap))
|
||||
qp.drawArc(rect, segment2*16, span2*16)
|
||||
|
||||
def draw_gauge(self, qp, event, w):
|
||||
w *= 0.6
|
||||
w = int(w)
|
||||
rect = QRect()
|
||||
rect.setSize(QSize(w, w))
|
||||
rect.moveCenter(event.rect().center())
|
||||
center = QPointF(rect.center())
|
||||
qp.setPen(QPen(Qt.white, self.tick_width, cap = Qt.FlatCap))
|
||||
qp.drawArc(rect, (-45 * 16), (270 * 16))
|
||||
rad = rect.width()/2
|
||||
inc = 270.0 / (self._num_ticks - 1)
|
||||
for i in range(self._num_ticks):
|
||||
p1 = self.qpa[i] * rad
|
||||
p1 += center
|
||||
p2 = self.qpa[i] * (rad + 10)
|
||||
p2 += center
|
||||
line = QLine(p1.toPoint(), p2.toPoint())
|
||||
qp.drawLine(line)
|
||||
|
||||
def draw_digits(self, qp, event, w):
|
||||
w *= 0.8
|
||||
center = event.rect().center()
|
||||
rect = QRect()
|
||||
rect.setSize(QSize(40,18))
|
||||
qp.setPen(QPen(Qt.white, self.tick_width))
|
||||
qp.setFont(QFont('Lato Heavy', self._dial_font_size))
|
||||
rad = w/2
|
||||
inc = 270.0 / (self._num_ticks - 1)
|
||||
for i in range(self._num_ticks):
|
||||
angle = (inc * i) - 225
|
||||
q, r = divmod(self._max_reading * i, self._num_ticks - 1)
|
||||
text = str(q) if r == 0 else ""
|
||||
if text == "": continue
|
||||
x = int(rad * math.cos(math.radians(angle)) + center.x())
|
||||
y = int(rad * math.sin(math.radians(angle)) + center.y())
|
||||
rect.moveCenter(QPoint(x, y))
|
||||
qp.drawText(rect, Qt.AlignCenter, text)
|
||||
|
||||
def draw_center(self, qp, event, w):
|
||||
w *= 0.2
|
||||
w = int(w)
|
||||
rect = QRect()
|
||||
rect.setSize(QSize(w, w))
|
||||
rect.moveCenter(event.rect().center())
|
||||
rad = rect.width()/2
|
||||
cap = QRadialGradient(QPointF(rect.center()), rad)
|
||||
cap.setColorAt(0, self._center_gradient_color)
|
||||
cap.setColorAt(1, self._center_color)
|
||||
qp.setPen(QPen(self._bezel_color, 1.5))
|
||||
qp.setBrush(QBrush(cap))
|
||||
qp.drawEllipse(rect)
|
||||
|
||||
def draw_setpoint(self, qp, event, w):
|
||||
w *= 0.6
|
||||
center = QPointF(event.rect().center())
|
||||
rad = w/2
|
||||
rect = QRect(0, 0, 8, 8)
|
||||
p = self._setpoint * rad
|
||||
p += center
|
||||
rect.moveCenter(p.toPoint())
|
||||
qp.fillRect(rect, QColor(Qt.yellow))
|
||||
|
||||
def draw_needle(self, qp, event, w):
|
||||
w *= 0.6
|
||||
center = event.rect().center()
|
||||
angle = ((self.value * 270.0) / self._max_value) - 225
|
||||
rad = w/2
|
||||
x = int(rad * math.cos(math.radians(angle)) + center.x())
|
||||
y = int(rad * math.sin(math.radians(angle)) + center.y())
|
||||
line = QLine(center.x(), center.y(), x, y)
|
||||
qp.setPen(QPen(Qt.red, 4))
|
||||
qp.drawLine(line)
|
||||
|
||||
def draw_readout(self, qp, event, w):
|
||||
center = event.rect().center()
|
||||
rect = QRect()
|
||||
rect.setSize(QSize(int(w/4), int(w/8)))
|
||||
rect.moveCenter(QPoint(center.x(), center.y() + int(w/4)))
|
||||
text = "{}".format(self.value)
|
||||
qp.setPen(QPen(Qt.white, 4))
|
||||
qp.setFont(QFont('Lato Heavy', self._value_font_size))
|
||||
qp.drawText(rect, Qt.AlignCenter, text)
|
||||
rect.moveCenter(QPoint(center.x(), center.y() + int(w/3)))
|
||||
text = self._gauge_label
|
||||
qp.setFont(QFont('Lato Heavy', self._label_font_size))
|
||||
qp.drawText(rect, Qt.AlignCenter, text)
|
||||
|
||||
@Slot(float)
|
||||
@Slot(int)
|
||||
def update_value(self, value):
|
||||
if value != self.value:
|
||||
self.value = int(value)
|
||||
self.update()
|
||||
|
||||
def set_setpoint(self, value):
|
||||
if value >= self._max_value:
|
||||
angle = 45
|
||||
elif value <= 0:
|
||||
angle = -225
|
||||
else:
|
||||
angle = ((value * 270) / self._max_value) - 225
|
||||
x = math.cos(math.radians(angle))
|
||||
y = math.sin(math.radians(angle))
|
||||
self._setpoint = QPointF(x, y)
|
||||
self.update()
|
||||
|
||||
@Slot(int)
|
||||
def set_threshold(self, value):
|
||||
if value > self._max_value:
|
||||
self._threshold = self._max_value
|
||||
elif value < 0:
|
||||
self._threshold = 0
|
||||
else:
|
||||
self._threshold = value
|
||||
self.update()
|
||||
|
||||
def get_threshold(self):
|
||||
return self._threshold
|
||||
|
||||
def reset_threshold(self):
|
||||
self._threshold = 50
|
||||
|
||||
@Slot(int)
|
||||
def set_max_value(self, value):
|
||||
self._max_value = value
|
||||
|
||||
def get_max_value(self):
|
||||
return self._max_value
|
||||
|
||||
def reset_max_value(self):
|
||||
self._max_value = 100
|
||||
|
||||
@Slot(int)
|
||||
def set_max_reading(self, value):
|
||||
self._max_reading = value
|
||||
self.update()
|
||||
|
||||
def get_max_reading(self):
|
||||
return self._max_reading
|
||||
|
||||
def reset_max_reading(self):
|
||||
self._max_reading = 100
|
||||
|
||||
@Slot(int)
|
||||
def set_num_ticks(self, value):
|
||||
# cannot allow value <= 1 or there will be division by 0 errors
|
||||
self._num_ticks = value if value > 1 else 2
|
||||
self.create_unit_array()
|
||||
self.update()
|
||||
|
||||
def get_num_ticks(self):
|
||||
return self._num_ticks
|
||||
|
||||
def reset_num_ticks(self):
|
||||
self._num_ticks = 11
|
||||
|
||||
@Slot(str)
|
||||
def set_label(self, label):
|
||||
self._gauge_label = label
|
||||
self.update()
|
||||
|
||||
def get_label(self):
|
||||
return self._gauge_label
|
||||
|
||||
def reset_label(self):
|
||||
self._gauge_label = "GAUGE"
|
||||
|
||||
@Slot(QColor)
|
||||
def set_base_gradient_color(self, color):
|
||||
self._base_gradient_color = color
|
||||
self.update()
|
||||
|
||||
def get_base_gradient_color(self):
|
||||
return self._base_gradient_color
|
||||
|
||||
def reset_base_gradient_color(self):
|
||||
self._base_gradient_color = QColor(180, 180, 180)
|
||||
self.update()
|
||||
|
||||
@Slot(QColor)
|
||||
def set_base_color(self, color):
|
||||
self._base_color = color
|
||||
self.update()
|
||||
|
||||
def get_base_color(self):
|
||||
return self._base_color
|
||||
|
||||
def reset_base_color(self):
|
||||
self._base_color = QColor(40, 40, 40)
|
||||
self.update()
|
||||
|
||||
@Slot(QColor)
|
||||
def set_center_gradient_color(self, color):
|
||||
self._center_gradient_color = color
|
||||
self.update()
|
||||
|
||||
def get_center_gradient_color(self):
|
||||
return self._center_gradient_color
|
||||
|
||||
def reset_center_gradient_color(self):
|
||||
self._center_gradient_color = QColor("gray")
|
||||
self.update()
|
||||
|
||||
@Slot(QColor)
|
||||
def set_center_color(self, color):
|
||||
self._center_color = color
|
||||
self.update()
|
||||
|
||||
def get_center_color(self):
|
||||
return self._center_color
|
||||
|
||||
def reset_center_color(self):
|
||||
self._center_color = QColor("#404040")
|
||||
self.update()
|
||||
|
||||
@Slot(QColor)
|
||||
def set_zone2_color(self, color):
|
||||
self._zone2_color = color
|
||||
self.update()
|
||||
|
||||
def get_zone2_color(self):
|
||||
return self._zone2_color
|
||||
|
||||
def reset_zone2_color(self):
|
||||
self._zone2_color = QColor("red")
|
||||
|
||||
@Slot(QColor)
|
||||
def set_zone1_color(self, color):
|
||||
self._zone1_color = color
|
||||
self.update()
|
||||
|
||||
def get_zone1_color(self):
|
||||
return self._zone1_color
|
||||
|
||||
def reset_zone1_color(self):
|
||||
self._zone1_color = QColor("green")
|
||||
|
||||
@Slot(QColor)
|
||||
def set_zone2_color(self, color):
|
||||
self._zone2_color = color
|
||||
self.update()
|
||||
|
||||
def get_zone2_color(self):
|
||||
return self._zone2_color
|
||||
|
||||
def reset_zone2_color(self):
|
||||
self._zone2_color = QColor("red")
|
||||
|
||||
@Slot(QColor)
|
||||
def set_bezel_color(self, color):
|
||||
self._bezel_color = color
|
||||
self.update()
|
||||
|
||||
def get_bezel_color(self):
|
||||
return self._bezel_color
|
||||
|
||||
def reset_bezel_color(self):
|
||||
self._bezel_color = QColor("gray")
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(200, 200)
|
||||
|
||||
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
|
||||
|
||||
@Slot(int)
|
||||
def set_bezel_width(self, value):
|
||||
self._bezel_width = value
|
||||
self.update()
|
||||
|
||||
def get_bezel_width(self):
|
||||
return self._bezel_width
|
||||
|
||||
def reset_bezel_width(self):
|
||||
self._bezel_width = 6
|
||||
self.update()
|
||||
|
||||
def sizeHint(self):
|
||||
return QtCore.QSize(200, 200)
|
||||
|
||||
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
|
||||
|
||||
halpin_option = Property(bool, get_halpin_option, set_halpin_option, reset_halpin_option)
|
||||
threshold = Property(int, get_threshold, set_threshold, reset_threshold)
|
||||
max_value = Property(int, get_max_value, set_max_value, reset_max_value)
|
||||
max_reading = Property(int, get_max_reading, set_max_reading, reset_max_reading)
|
||||
num_ticks = Property(int, get_num_ticks, set_num_ticks, reset_num_ticks)
|
||||
gauge_label = Property(str, get_label, set_label, reset_label)
|
||||
base_gradient_color = Property(QColor, get_base_gradient_color, set_base_gradient_color, reset_base_gradient_color)
|
||||
base_color = Property(QColor, get_base_color, set_base_color, reset_base_color)
|
||||
center_gradient_color = Property(QColor, get_center_gradient_color, set_center_gradient_color, reset_center_gradient_color)
|
||||
center_color = Property(QColor, get_center_color, set_center_color, reset_center_color)
|
||||
zone1_color = Property(QColor, get_zone1_color, set_zone1_color, reset_zone1_color)
|
||||
zone2_color = Property(QColor, get_zone2_color, set_zone2_color, reset_zone2_color)
|
||||
bezel_color = Property(QColor, get_bezel_color, set_bezel_color, reset_bezel_color)
|
||||
bezel_width = Property(int, get_bezel_width, set_bezel_width, reset_bezel_width)
|
||||
|
||||
#############################
|
||||
# Testing #
|
||||
#############################
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from qtpy.QtWidgets import QSlider, QWidget, QVBoxLayout
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
w = QWidget()
|
||||
w.setGeometry(100, 100, 400, 400)
|
||||
w.setWindowTitle('Round Gauge')
|
||||
layout = QVBoxLayout(w)
|
||||
gauge = Gauge(w)
|
||||
gauge.set_max_value(20000)
|
||||
gauge.set_max_reading(20)
|
||||
gauge.set_threshold(7200)
|
||||
gauge.set_setpoint(14000)
|
||||
gauge.set_num_ticks(11)
|
||||
gauge.set_label("RPM")
|
||||
gauge._value_font_size = 10
|
||||
gauge._label_font_size = 10
|
||||
gauge._dial_font_size = 10
|
||||
slider = QSlider(Qt.Horizontal)
|
||||
slider.setMinimum(0)
|
||||
slider.setMaximum(20000)
|
||||
slider.setSingleStep(10)
|
||||
slider.setPageStep(100)
|
||||
slider.valueChanged.connect(gauge.update_value)
|
||||
layout.addWidget(gauge)
|
||||
layout.addWidget(slider)
|
||||
w.show()
|
||||
sys.exit( app.exec() )
|
||||
Reference in New Issue
Block a user