summaryrefslogtreecommitdiff
path: root/gr-qtgui/python/qtgui/toggleswitch.py
diff options
context:
space:
mode:
Diffstat (limited to 'gr-qtgui/python/qtgui/toggleswitch.py')
-rw-r--r--gr-qtgui/python/qtgui/toggleswitch.py210
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'])))