From e088b03c047d3d0339b2f37bb8240b2ec52327e1 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Sun, 3 May 2020 12:04:36 +0200 Subject: [PATCH] Added original switch code from stack overflow --- nw/additions/qswitch.py | 223 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 nw/additions/qswitch.py diff --git a/nw/additions/qswitch.py b/nw/additions/qswitch.py new file mode 100644 index 00000000..b7d3fdcd --- /dev/null +++ b/nw/additions/qswitch.py @@ -0,0 +1,223 @@ +# -*- coding: utf-8 -*- +"""novelWriter Addition QSwitch + + novelWriter – Addition QSwitch +================================ + A custom Qt switch button + + File History: + Created: 2020-05-03 [0.4.5] + + This class is based on Stack Overflow code by Stefan Scherfke, based + again on contribution by IMAN4K, published under license CC BY-SA 4.0. + https://stackoverflow.com/a/51825815/5825851 + + The above code has been modified to integrate with novelWriter, and + re-released under compatible GPLv3 (see creativecommons.org). + + This file is a part of novelWriter + Copyright 2020, Veronica Berglyd Olsen + + 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 3 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see https://www.gnu.org/licenses/. +""" + +import logging +import nw + +from PyQt5.QtCore import QPropertyAnimation, QRectF, QSize, Qt, pyqtProperty +from PyQt5.QtGui import QPainter +from PyQt5.QtWidgets import ( + QAbstractButton, + QApplication, + QHBoxLayout, + QSizePolicy, + QWidget, +) + +logger = logging.getLogger(__name__) + +class Switch(QAbstractButton): + def __init__(self, parent=None, track_radius=10, thumb_radius=8): + super().__init__(parent=parent) + self.setCheckable(True) + self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + + self._track_radius = track_radius + self._thumb_radius = thumb_radius + + self._margin = max(0, self._thumb_radius - self._track_radius) + self._base_offset = max(self._thumb_radius, self._track_radius) + self._end_offset = { + True: lambda: self.width() - self._base_offset, + False: lambda: self._base_offset, + } + self._offset = self._base_offset + + palette = self.palette() + if self._thumb_radius > self._track_radius: + self._track_color = { + True: palette.highlight(), + False: palette.dark(), + } + self._thumb_color = { + True: palette.highlight(), + False: palette.light(), + } + self._text_color = { + True: palette.highlightedText().color(), + False: palette.dark().color(), + } + self._thumb_text = { + True: '', + False: '', + } + self._track_opacity = 0.5 + else: + self._thumb_color = { + True: palette.highlightedText(), + False: palette.light(), + } + self._track_color = { + True: palette.highlight(), + False: palette.dark(), + } + self._text_color = { + True: palette.highlight().color(), + False: palette.dark().color(), + } + self._thumb_text = { + True: '✔', + False: '✕', + } + self._track_opacity = 1 + + @pyqtProperty(int) + def offset(self): + return self._offset + + @offset.setter + def offset(self, value): + self._offset = value + self.update() + + def sizeHint(self): # pylint: disable=invalid-name + return QSize( + 4 * self._track_radius + 2 * self._margin, + 2 * self._track_radius + 2 * self._margin, + ) + + def setChecked(self, checked): + super().setChecked(checked) + self.offset = self._end_offset[checked]() + + def resizeEvent(self, event): + super().resizeEvent(event) + self.offset = self._end_offset[self.isChecked()]() + + def paintEvent(self, event): # pylint: disable=invalid-name, unused-argument + p = QPainter(self) + p.setRenderHint(QPainter.Antialiasing, True) + p.setPen(Qt.NoPen) + track_opacity = self._track_opacity + thumb_opacity = 1.0 + text_opacity = 1.0 + if self.isEnabled(): + track_brush = self._track_color[self.isChecked()] + thumb_brush = self._thumb_color[self.isChecked()] + text_color = self._text_color[self.isChecked()] + else: + track_opacity *= 0.8 + track_brush = self.palette().shadow() + thumb_brush = self.palette().mid() + text_color = self.palette().shadow().color() + + p.setBrush(track_brush) + p.setOpacity(track_opacity) + p.drawRoundedRect( + self._margin, + self._margin, + self.width() - 2 * self._margin, + self.height() - 2 * self._margin, + self._track_radius, + self._track_radius, + ) + p.setBrush(thumb_brush) + p.setOpacity(thumb_opacity) + p.drawEllipse( + self.offset - self._thumb_radius, + self._base_offset - self._thumb_radius, + 2 * self._thumb_radius, + 2 * self._thumb_radius, + ) + p.setPen(text_color) + p.setOpacity(text_opacity) + font = p.font() + font.setPixelSize(1.5 * self._thumb_radius) + p.setFont(font) + p.drawText( + QRectF( + self.offset - self._thumb_radius, + self._base_offset - self._thumb_radius, + 2 * self._thumb_radius, + 2 * self._thumb_radius, + ), + Qt.AlignCenter, + self._thumb_text[self.isChecked()], + ) + + def mouseReleaseEvent(self, event): # pylint: disable=invalid-name + super().mouseReleaseEvent(event) + if event.button() == Qt.LeftButton: + anim = QPropertyAnimation(self, b'offset', self) + anim.setDuration(120) + anim.setStartValue(self.offset) + anim.setEndValue(self._end_offset[self.isChecked()]()) + anim.start() + + def enterEvent(self, event): # pylint: disable=invalid-name + self.setCursor(Qt.PointingHandCursor) + super().enterEvent(event) + + +# def main(): +# app = QApplication([]) + +# # Thumb size < track size (Gitlab style) +# s1 = Switch() +# s1.toggled.connect(lambda c: print('toggled', c)) +# s1.clicked.connect(lambda c: print('clicked', c)) +# s1.pressed.connect(lambda: print('pressed')) +# s1.released.connect(lambda: print('released')) +# s2 = Switch() +# s2.setEnabled(False) + +# # Thumb size > track size (Android style) +# s3 = Switch(thumb_radius=11, track_radius=8) +# s4 = Switch(thumb_radius=11, track_radius=8) +# s4.setEnabled(False) + +# l = QHBoxLayout() +# l.addWidget(s1) +# l.addWidget(s2) +# l.addWidget(s3) +# l.addWidget(s4) +# w = QWidget() +# w.setLayout(l) +# w.show() + +# app.exec() + + +# if __name__ == '__main__': +# main()