diff options
Diffstat (limited to 'gr-qtgui/python/qtgui/toggleswitch.py')
-rw-r--r-- | gr-qtgui/python/qtgui/toggleswitch.py | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/gr-qtgui/python/qtgui/toggleswitch.py b/gr-qtgui/python/qtgui/toggleswitch.py new file mode 100644 index 0000000000..7ef5a113fa --- /dev/null +++ b/gr-qtgui/python/qtgui/toggleswitch.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2020 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# + +from gnuradio import gr +import pmt + +from PyQt5.QtWidgets import QFrame, QHBoxLayout, QVBoxLayout, QLabel +from PyQt5.QtGui import QPainter, QBrush, QColor, QPen, QFontMetricsF +from PyQt5.QtCore import Qt as Qtc +from PyQt5.QtCore import QRect + +class LabeledToggleSwitch(QFrame): + # Positions: 1 = above, 2=below, 3=left, 4=right + def __init__(self, lbl='', onColor='green', offColor='red', initialState=False, + maxSize=50, position=1, parent=None, callback=None, alignment=1, valignment=1): + QFrame.__init__(self, parent) + self.numberControl = ToggleSwitch(onColor, offColor, initialState, maxSize, + parent, callback) + + if position < 3: + layout = QVBoxLayout() + else: + layout = QHBoxLayout() + + self.lbl = lbl + self.lblcontrol = QLabel(lbl, self) + + if position == 3: # left of switch + self.lblcontrol.setAlignment(Qtc.AlignRight) + elif position == 4: # right of switch + self.lblcontrol.setAlignment(Qtc.AlignLeft) + else: + # Above or below + self.lblcontrol.setAlignment(Qtc.AlignCenter) + + # add top or left + if len: + if position == 1 or position == 3: + layout.addWidget(self.lblcontrol) + + layout.addWidget(self.numberControl) + + # Add bottom or right + if len: + if position == 2 or position == 4: + layout.addWidget(self.lblcontrol) + + if alignment == 1: + halign = Qtc.AlignCenter + elif alignment == 2: + halign = Qtc.AlignLeft + else: + halign = Qtc.AlignRight + + if valignment == 1: + valign = Qtc.AlignVCenter + elif valignment == 2: + valign = Qtc.AlignTop + else: + valign = Qtc.AlignBottom + + layout.setAlignment(halign | valign) + + self.setLayout(layout) + + textfont = self.lblcontrol.font() + metrics = QFontMetricsF(textfont) + + maxWidth = max((maxSize+4), (maxSize*2 + metrics.width(lbl))) + maxHeight = max((maxSize/2+4), (maxSize/2 + metrics.height()+2)) + + self.setMinimumSize(int(maxWidth), int(maxHeight)) + + self.show() + + def setState(self, on_off): + self.numberControl.setState(on_off) + +class ToggleSwitch(QFrame): + def __init__(self, onColor='green', offColor='red', initialState=False, maxSize=50, + parent=None, callback=None): + QFrame.__init__(self, parent) + + self.maxSize = maxSize + self.curState = initialState + self.onColor = QColor(onColor) + self.offColor = QColor(offColor) + self.callback = callback + self.setMinimumSize(maxSize, maxSize/2) + self.setMaximumSize(maxSize, maxSize/2) + + def setState(self, on_off): + self.curState = on_off + if self.callback is not None: + self.callback(on_off) + + super().update() + + def paintEvent(self, event): + super().paintEvent(event) + + painter = QPainter(self) + painter.setRenderHint(QPainter.Antialiasing) + + size = self.size() + brush = QBrush() + + center_x = size.width()/2 + + if self.curState: + brush.setColor(self.onColor) + painter.setPen(QPen(self.onColor, 0)) + else: + brush.setColor(self.offColor) + painter.setPen(QPen(self.offColor, 0)) + + brush.setStyle(Qtc.SolidPattern) + painter.setBrush(brush) + + # Draw the switch background + centerRect = QRect(size.width()/4, 0, size.width()/2-4, size.height()) + painter.drawRect(centerRect) + painter.drawEllipse(0, 0, size.height(), size.height()) + painter.drawEllipse(size.width()/2, 0, size.height(), size.height()) + + # Draw the switch itself + brush.setColor(QColor('white')) + painter.setBrush(brush) + painter.setPen(QPen(QColor('white'), 0)) + if self.curState: + painter.drawEllipse(2, 2, size.height() - 4, size.height() - 4) + else: + painter.drawEllipse(center_x+2, 2, size.height() - 4, size.height() - 4) + + def mousePressEvent(self, event): + if event.x() <= self.size().width()/2: + self.setState(True) + else: + self.setState(False) + + super().update() + +class GrToggleSwitch(gr.sync_block, LabeledToggleSwitch): + """ + This block creates a modern toggle switch. The variable will take + on one value or the other as set in the dialog. This button will + also produce a state message matching the set values. + """ + def __init__(self, callback, lbl, pressedReleasedDict, initialState=False, + onColor='green', offColor='silver', position=3, maxSize=50, + alignment=1, valignment=1, parent=None, outputmsgname='value'): + gr.sync_block.__init__(self, name="ToggleSwitch", in_sig=None, out_sig=None) + LabeledToggleSwitch.__init__(self, lbl, onColor, offColor, initialState, + maxSize, position, parent, self.notifyUpdate, + alignment, valignment) + + self.outputmsgname = outputmsgname + self.pressReleasedDict = pressedReleasedDict + self.callback = callback + self.message_port_register_out(pmt.intern("state")) + + def notifyUpdate(self, new_val): + if self.callback is not None: + if new_val: + self.callback(self.pressReleasedDict['Pressed']) + else: + self.callback(self.pressReleasedDict['Released']) + + if new_val: + if type(self.pressReleasedDict['Pressed']) == bool: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_bool(self.pressReleasedDict['Pressed']))) + elif type(self.pressReleasedDict['Pressed']) == int: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_long(self.pressReleasedDict['Pressed']))) + elif type(self.pressReleasedDict['Pressed']) == float: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_float(self.pressReleasedDict['Pressed']))) + else: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.intern(self.pressReleasedDict['Pressed']))) + else: + if type(self.pressReleasedDict['Released']) == bool: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_bool(self.pressReleasedDict['Released']))) + elif type(self.pressReleasedDict['Released']) == int: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_long(self.pressReleasedDict['Released']))) + elif type(self.pressReleasedDict['Released']) == float: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.from_float(self.pressReleasedDict['Released']))) + else: + self.message_port_pub(pmt.intern("state"), + pmt.cons(pmt.intern(self.outputmsgname), + pmt.intern(self.pressReleasedDict['Released']))) |