2929__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
3030
3131import logging
32+ import re
3233import sys
3334
3435if sys .version_info < (3 , ):
37343735 }
37353736
37363737
3738+ DARK_MODE_TABLE = [
3739+ "average16" , "derive" , "fit" , "logx" , "logy" , "normal" ,
3740+ "normalize16" , "peak" , "peakreset" , "peaksearch" , "roi" ,
3741+ "roireset" , "rotate_left" , "rotate_right" , "smooth" ,
3742+ "xauto" , "yauto" , "ymintozero" , "filesave"
3743+ ]
3744+
3745+
3746+ def _parse_xpm_color (color_spec ):
3747+ """Parse an XPM color specification into an (r, g, b) tuple.
3748+
3749+ Returns None if color is unknown.
3750+ """
3751+ spec = color_spec .strip ()
3752+ lower = spec .lower ()
3753+ if lower == 'none' :
3754+ return None
3755+ if spec .startswith ('#' ):
3756+ h = spec [1 :]
3757+ # hex colors
3758+ if len (h ) == 6 :
3759+ return (int (h [0 :2 ], 16 ), int (h [2 :4 ], 16 ), int (h [4 :6 ], 16 ))
3760+ # short hex colors
3761+ if len (h ) == 3 :
3762+ return (int (h [0 ], 16 ) * 17 , int (h [1 ], 16 ) * 17 ,
3763+ int (h [2 ], 16 ) * 17 )
3764+ # named colors, no reason to check red, yellow, etc as they are saturated
3765+ if lower == "black" :
3766+ return (0 , 0 , 0 )
3767+ elif lower == "white" :
3768+ return (255 , 255 , 255 )
3769+ else :
3770+ return None
3771+
3772+
3773+ def _to_reverse_color (r , g , b ):
3774+ """Return True if the color need to be reversed for dark mode.
3775+ """
3776+ # not to reverse saturated colours
3777+ if (max (r , g , b ) - min (r , g , b )) > 40 :
3778+ return False
3779+ # one can check (r + g + b) < 3*128 but then outlines could look bad
3780+ return True
3781+
3782+
3783+ def _adapt_xpm_for_dark_mode (xpm_data ):
3784+ """Return a copy of *xpm_data* with some colours inverted.
3785+
3786+ """
3787+ result = list (xpm_data )
3788+ xpm_info = result [0 ].split ()
3789+ number_of_colors = int (xpm_info [2 ])
3790+ for i in range (1 , 1 + number_of_colors ):
3791+ symbol = result [i ].split (" c " )[0 ]
3792+ rgb_raw = result [i ].split (" c " )[1 ]
3793+ rgb = _parse_xpm_color (rgb_raw )
3794+ if rgb is None :
3795+ continue
3796+ r , g , b = _parse_xpm_color (rgb_raw )
3797+ if _to_reverse_color (r , g , b ):
3798+ result [i ] = "%s c #%02x%02x%02x" \
3799+ % (symbol , 255 - r , 255 - g , 255 - b )
3800+ return result
3801+
3802+
37373803class _PatchedIconDict (MutableMapping ):
37383804 """IconDict that patches some legacy icons with new
37393805 silx icons, when available.
@@ -3749,6 +3815,7 @@ class _PatchedIconDict(MutableMapping):
37493815 def __init__ (self , * args , ** kw ):
37503816 self ._unpatched_icons = dict (* args , ** kw )
37513817 self .__initialized = False
3818+ self ._dark = {}
37523819
37533820 def __iter__ (self ):
37543821 for key in self ._unpatched_icons :
@@ -3778,6 +3845,19 @@ def __getitem__(self, key):
37783845
37793846 if key not in self ._unpatched_icons :
37803847 raise KeyError ("Unknown icon '%s'" % key )
3848+
3849+ # even if it is dark mode but text is not white then black can probably be used
3850+ if self ._qt .QApplication .instance ().palette ().color (self ._qt .QPalette .Text ) == self ._qt .QColor ('white' ):
3851+ from PyMca5 .PyMcaGui .plotting .Silx_Icons import IconDict as _silx_xpm
3852+ if key in DARK_MODE_TABLE :
3853+ silx_key = TRANSLATION_TABLE .get (key )
3854+ if silx_key :
3855+ xpm = _silx_xpm .get (silx_key )
3856+ else :
3857+ xpm = self ._unpatched_icons .get (key )
3858+ self ._dark [key ] = _adapt_xpm_for_dark_mode (xpm )
3859+ return self ._dark [key ]
3860+
37813861
37823862 if key not in TRANSLATION_TABLE :
37833863 _logger .debug ("Using legacy icon '%s' because there is no "
@@ -3825,7 +3905,7 @@ def __setitem__(self, key, item):
38253905
38263906
38273907IconDict = _PatchedIconDict (IconDict0 )
3828-
3908+ # IconDict = IconDict0
38293909
38303910def change_icons (plot ):
38313911 """Replace some of the silx icons with PyMca icons.
0 commit comments