#! /usr/bin/env python3 # -*- coding: utf-8 -*- """ Copyright 2021, Nils Hilbricht, Germany ( https://www.hilbricht.net ) This file is part of Laborejo ( https://www.laborejo.org ) Laborejo 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 . """ import logging; logger = logging.getLogger(__name__); logger.info("import") from PyQt5 import QtCore, QtGui, QtWidgets from hashlib import md5 def iconFromString(st, size=128): px = QtGui.QPixmap(size,size) color = stringToColor(st) px.fill(color) return QtGui.QIcon(px) def stringToColor(st): """Convert a string to QColor. Same string, same color Is used for group coloring""" if st: c = md5(st.encode()).hexdigest() return QtGui.QColor(int(c[0:9],16) % 255, int(c[10:19],16) % 255, int(c[20:29],16)% 255, 255) else: return QtGui.QColor(255,255,255,255) #Return White def invertColor(qcolor): r = 255 - qcolor.red() g = 255 - qcolor.green() b = 255 - qcolor.blue() return QtGui.QColor(r, g, b, qcolor.alpha()) def removeInstancesFromScene(qtGraphicsClass): """"Remove all instances of a qt class that implements .instances=[] from the QGraphicsScene. Don't use for items or anything in the notation view. This is used by the likes of the conductor only since they exist only once and gets redrawn completely each time.""" for instance in qtGraphicsClass.instances: instance.setParentItem(None) instance.scene().removeWhenIdle(instance) qtGraphicsClass.instances = [] def callContextMenu(listOfLabelsAndFunctions): menu = QtWidgets.QMenu() for text, function in listOfLabelsAndFunctions: if text == "separator": menu.addSeparator() else: a = QtWidgets.QAction(text, menu) menu.addAction(a) a.triggered.connect(function) pos = QtGui.QCursor.pos() pos.setY(pos.y() + 5) menu.exec_(pos) def stretchLine(qGraphicsLineItem, factor): line = qGraphicsLineItem.line() line.setLength(line.length() * factor) qGraphicsLineItem.setLine(line) def stretchRect(qGraphicsRectItem, factor): r = qGraphicsRectItem.rect() r.setRight(r.right() * factor) qGraphicsRectItem.setRect(r) class QHLine(QtWidgets.QFrame): def __init__(self): super().__init__() self.setFrameShape(QtWidgets.QFrame.HLine) self.setFrameShadow(QtWidgets.QFrame.Sunken) def setPaletteAndFont(qtApp): """Set our programs color This is in its own function because it is a annoying to scroll by that in init. http://doc.qt.io/qt-5/qpalette.html""" fPalBlue = QtGui.QPalette() fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Window, QtGui.QColor(32, 35, 39)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Window, QtGui.QColor(37, 40, 45)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Window, QtGui.QColor(37, 40, 45)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, QtGui.QColor(89, 95, 104)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.WindowText, QtGui.QColor(223, 237, 255)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.WindowText, QtGui.QColor(223, 237, 255)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Base, QtGui.QColor(48, 53, 60)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, QtGui.QColor(55, 61, 69)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Base, QtGui.QColor(55, 61, 69)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.AlternateBase, QtGui.QColor(60, 64, 67)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.AlternateBase, QtGui.QColor(69, 73, 77)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.AlternateBase, QtGui.QColor(69, 73, 77)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipBase, QtGui.QColor(182, 193, 208)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.ToolTipBase, QtGui.QColor(182, 193, 208)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.ToolTipBase, QtGui.QColor(182, 193, 208)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ToolTipText, QtGui.QColor(42, 44, 48)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.ToolTipText, QtGui.QColor(42, 44, 48)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.ToolTipText, QtGui.QColor(42, 44, 48)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Text, QtGui.QColor(96, 103, 113)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Text, QtGui.QColor(210, 222, 240)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Text, QtGui.QColor(210, 222, 240)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Button, QtGui.QColor(51, 55, 62)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Button, QtGui.QColor(59, 63, 71)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Button, QtGui.QColor(59, 63, 71)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, QtGui.QColor(98, 104, 114)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, QtGui.QColor(210, 222, 240)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, QtGui.QColor(210, 222, 240)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.BrightText, QtGui.QColor(255, 255, 255)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.BrightText, QtGui.QColor(255, 255, 255)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.BrightText, QtGui.QColor(255, 255, 255)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Light, QtGui.QColor(59, 64, 72)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Light, QtGui.QColor(63, 68, 76)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Light, QtGui.QColor(63, 68, 76)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Midlight, QtGui.QColor(48, 52, 59)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Midlight, QtGui.QColor(51, 56, 63)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Midlight, QtGui.QColor(51, 56, 63)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Dark, QtGui.QColor(18, 19, 22)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Dark, QtGui.QColor(20, 22, 25)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Dark, QtGui.QColor(20, 22, 25)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Mid, QtGui.QColor(28, 30, 34)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Mid, QtGui.QColor(32, 35, 39)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Mid, QtGui.QColor(32, 35, 39)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Shadow, QtGui.QColor(13, 14, 16)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Shadow, QtGui.QColor(15, 16, 18)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Shadow, QtGui.QColor(15, 16, 18)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, QtGui.QColor(32, 35, 39)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Highlight, QtGui.QColor(14, 14, 17)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, QtGui.QColor(27, 28, 33)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, QtGui.QColor(89, 95, 104)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText, QtGui.QColor(217, 234, 253)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText, QtGui.QColor(223, 237, 255)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Link, QtGui.QColor(79, 100, 118)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.Link, QtGui.QColor(156, 212, 255)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Link, QtGui.QColor(156, 212, 255)) fPalBlue.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.LinkVisited, QtGui.QColor(51, 74, 118)) fPalBlue.setColor(QtGui.QPalette.Active, QtGui.QPalette.LinkVisited, QtGui.QColor(64, 128, 255)) fPalBlue.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.LinkVisited, QtGui.QColor(64, 128, 255)) qtApp.setPalette(fPalBlue) font = QtGui.QFont("DejaVu Sans", 10) font.setPixelSize(12) qtApp.setFont(font) return fPalBlue class ToggleSwitch(QtWidgets.QAbstractButton): """From https://stackoverflow.com/questions/14780517/toggle-switch-in-qt/38102598 Usage: # Thumb size < track size (Gitlab style) s1 = ToggleSwitch() 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 = ToggleSwitch() s2.setEnabled(False) # Thumb size > track size (Android style) s3 = ToggleSwitch(thumb_radius=11, track_radius=8) s4 = ToggleSwitch(thumb_radius=11, track_radius=8) s4.setEnabled(False) """ def __init__(self, parent=None, track_radius=10, thumb_radius=8): super().__init__(parent=parent) self.setCheckable(True) self.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.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.mid(), } self._thumb_color = { True: palette.highlight(), False: palette.light(), } self._text_color = { True: palette.highlightedText().color(), False: palette.mid().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.mid(), } self._text_color = { True: palette.highlight().color(), False: palette.mid().color(), } self._thumb_text = { True: '✔', False: '✕', } self._track_opacity = 0.7 @property 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 QtCore.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 = QtGui.QPainter(self) p.setRenderHint(QtGui.QPainter.Antialiasing, True) p.setPen(QtCore.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( QtCore.QRectF( self.offset - self._thumb_radius, self._base_offset - self._thumb_radius, 2 * self._thumb_radius, 2 * self._thumb_radius, ), QtCore.Qt.AlignCenter, self._thumb_text[self.isChecked()], ) def mouseReleaseEvent(self, event): # pylint: disable=invalid-name super().mouseReleaseEvent(event) if event.button() == QtCore.Qt.LeftButton: anim = QtCore.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(QtCore.Qt.PointingHandCursor) super().enterEvent(event) class FancySwitch(ToggleSwitch): pass