#! /usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Copyright 2022 , 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 < http : / / www . gnu . org / licenses / > .
"""
import logging ; logger = logging . getLogger ( __name__ ) ; logger . info ( " import " )
from PyQt5 import QtCore , QtGui , QtWidgets
from hashlib import md5
def makeValueWidget ( value : any ) :
""" Create a widget just from a value. Needs an external label e.g. in a formLayout.
First usecase was laborejo lilypond metadata and properties where it edited an engine - dict
directly and inplace .
Use with getValueFromWidget """
types = {
str : QtWidgets . QLineEdit ,
int : QtWidgets . QSpinBox ,
float : QtWidgets . QDoubleSpinBox ,
bool : QtWidgets . QCheckBox ,
}
typ = type ( value )
widget = types [ typ ] ( )
if typ == str :
widget . setText ( value )
elif typ == int or typ == float :
widget . setValue ( value )
elif typ == bool :
widget . setChecked ( value )
return widget
def getValueFromWidget ( widget ) :
""" Use with makeValueWidget """
typ = type ( widget )
if typ == QtWidgets . QLineEdit :
return widget . text ( )
elif typ == QtWidgets . QSpinBox or typ == QtWidgets . QDoubleSpinBox :
return widget . value ( )
elif typ == QtWidgets . QCheckBox :
return widget . isChecked ( )
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 ( int ( 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 )
"""
broken since Qt5 .15
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