74
74
from itertools import chain
75
75
76
76
import numpy as np
77
- from qtpy .QtCore import Qt , QPoint , QItemSelection , QItemSelectionModel , Signal
78
- from qtpy .QtGui import QDoubleValidator , QIntValidator , QKeySequence , QFontMetrics , QCursor
77
+ from qtpy .QtCore import Qt , QPoint , QItemSelection , QItemSelectionModel , Signal , QSize
78
+ from qtpy .QtGui import (QDoubleValidator , QIntValidator , QKeySequence , QFontMetrics , QCursor , QPixmap , QPainter ,
79
+ QLinearGradient , QColor , QIcon )
79
80
from qtpy .QtWidgets import (QApplication , QTableView , QItemDelegate , QLineEdit , QCheckBox ,
80
81
QMessageBox , QMenu , QLabel , QSpinBox , QWidget , QToolTip , QShortcut , QScrollBar ,
81
- QHBoxLayout , QVBoxLayout , QGridLayout , QSizePolicy , QFrame )
82
+ QHBoxLayout , QVBoxLayout , QGridLayout , QSizePolicy , QFrame , QComboBox )
82
83
83
84
try :
84
85
import xlwings as xw
85
86
except ImportError :
86
87
xw = None
87
88
88
89
from larray_editor .utils import (keybinding , create_action , clear_layout , get_font , from_qvariant , to_qvariant ,
89
- is_number , is_float , _ , ima )
90
+ is_number , is_float , _ , ima , LinearGradient )
90
91
from larray_editor .arrayadapter import LArrayDataAdapter
91
92
from larray_editor .arraymodel import LabelsArrayModel , DataArrayModel
92
93
from larray_editor .combo import FilterComboBox , FilterMenu
@@ -505,10 +506,30 @@ def __init__(self, parent, data_scrollbar):
505
506
self .rangeChanged .connect (data_scrollbar .setRange )
506
507
507
508
509
+ available_gradients = [
510
+ # Hue, Saturation, Value, Alpha-channel
511
+ ('red-blue' , LinearGradient ([(0 , [0.99 , 0.7 , 1.0 , 0.6 ]), (1 , [0.66 , 0.7 , 1.0 , 0.6 ])])),
512
+ ('blue-red' , LinearGradient ([(0 , [0.66 , 0.7 , 1.0 , 0.6 ]), (1 , [0.99 , 0.7 , 1.0 , 0.6 ])])),
513
+ ('red-white-blue' , LinearGradient ([(0 , [.99 , .85 , 1. , .6 ]),
514
+ (0.5 - 1e-16 , [.99 , .15 , 1. , .6 ]),
515
+ (0.5 , [1. , 0. , 1. , 1. ]),
516
+ (0.5 + 1e-16 , [.66 , .15 , 1. , .6 ]),
517
+ (1 , [.66 , .85 , 1. , .6 ])])),
518
+ ('blue-white-red' , LinearGradient ([(0 , [.66 , .85 , 1. , .6 ]),
519
+ (0.5 - 1e-16 , [.66 , .15 , 1. , .6 ]),
520
+ (0.5 , [1. , 0. , 1. , 1. ]),
521
+ (0.5 + 1e-16 , [.99 , .15 , 1. , .6 ]),
522
+ (1 , [.99 , .85 , 1. , .6 ])])),
523
+ ]
524
+ gradient_map = dict (available_gradients )
525
+
526
+
527
+
508
528
class ArrayEditorWidget (QWidget ):
509
- def __init__ (self , parent , data = None , readonly = False , bg_value = None , bg_gradient = None ,
529
+ def __init__ (self , parent , data = None , readonly = False , bg_value = None , bg_gradient = 'blue-red' ,
510
530
minvalue = None , maxvalue = None ):
511
531
QWidget .__init__ (self , parent )
532
+ assert bg_gradient in gradient_map
512
533
readonly = np .isscalar (data )
513
534
self .readonly = readonly
514
535
@@ -613,10 +634,33 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
613
634
self .scientific_checkbox = scientific
614
635
btn_layout .addWidget (scientific )
615
636
616
- bgcolor = QCheckBox (_ ('Background color' ))
617
- bgcolor .stateChanged .connect (self .model_data .bgcolor )
618
- self .bgcolor_checkbox = bgcolor
619
- btn_layout .addWidget (bgcolor )
637
+ gradient_chooser = QComboBox ()
638
+ gradient_chooser .setMaximumSize (120 , 20 )
639
+ gradient_chooser .setIconSize (QSize (100 , 20 ))
640
+
641
+ pixmap = QPixmap (100 , 15 )
642
+ pixmap .fill (Qt .white )
643
+ gradient_chooser .addItem (QIcon (pixmap ), " " )
644
+
645
+ pixmap .fill (Qt .transparent )
646
+ painter = QPainter (pixmap )
647
+ for name , gradient in available_gradients :
648
+ qgradient = gradient .as_qgradient ()
649
+
650
+ # * fill with white because gradient can be transparent and if we do not "start from whilte", it skews the
651
+ # colors.
652
+ # * 1 and 13 instead of 0 and 15 to have a transparent border around/between the gradients
653
+ painter .fillRect (0 , 1 , 100 , 13 , Qt .white )
654
+ painter .fillRect (0 , 1 , 100 , 13 , qgradient )
655
+ gradient_chooser .addItem (QIcon (pixmap ), name , gradient )
656
+
657
+ # without this, we can crash python :)
658
+ del painter , pixmap
659
+ # select default gradient
660
+ gradient_chooser .setCurrentText (bg_gradient )
661
+ gradient_chooser .currentIndexChanged .connect (self .gradient_changed )
662
+ btn_layout .addWidget (gradient_chooser )
663
+ self .gradient_chooser = gradient_chooser
620
664
621
665
# Set widget layout
622
666
layout = QVBoxLayout ()
@@ -625,11 +669,16 @@ def __init__(self, parent, data=None, readonly=False, bg_value=None, bg_gradient
625
669
layout .addLayout (btn_layout )
626
670
layout .setContentsMargins (0 , 0 , 0 , 0 )
627
671
self .setLayout (layout )
628
- self .set_data (data , bg_value = bg_value , bg_gradient = bg_gradient )
672
+ self .set_data (data , bg_value = bg_value )
673
+ self .model_data .set_bg_gradient (gradient_map [bg_gradient ])
629
674
630
675
# See http://doc.qt.io/qt-4.8/qt-draganddrop-fridgemagnets-dragwidget-cpp.html for an example
631
676
self .setAcceptDrops (True )
632
677
678
+ def gradient_changed (self , index ):
679
+ gradient = self .gradient_chooser .itemData (index ) if index > 0 else None
680
+ self .model_data .set_bg_gradient (gradient )
681
+
633
682
def mousePressEvent (self , event ):
634
683
self .dragLabel = self .childAt (event .pos ()) if event .button () == Qt .LeftButton else None
635
684
self .dragStartPosition = event .pos ()
@@ -692,7 +741,10 @@ def dropEvent(self, event):
692
741
new_axes = la_data .axes .copy ()
693
742
new_axes .insert (new_index , new_axes .pop (new_axes [previous_index ]))
694
743
la_data = la_data .transpose (new_axes )
695
- self .set_data (la_data , self .model_data .bg_gradient , self .model_data .bg_value )
744
+ bg_value = self .data_adapter .bg_value
745
+ if bg_value is not None :
746
+ bg_value = bg_value .transpose (new_axes )
747
+ self .set_data (la_data , bg_value )
696
748
697
749
event .setDropAction (Qt .MoveAction )
698
750
event .accept ()
@@ -701,9 +753,9 @@ def dropEvent(self, event):
701
753
else :
702
754
event .ignore ()
703
755
704
- def set_data (self , data = None , bg_gradient = None , bg_value = None ):
756
+ def set_data (self , data = None , bg_value = None ):
705
757
# update adapter
706
- self .data_adapter .set_data (data , bg_gradient = bg_gradient , bg_value = bg_value )
758
+ self .data_adapter .set_data (data , bg_value = bg_value )
707
759
la_data = self .data_adapter .get_data ()
708
760
axes = la_data .axes
709
761
display_names = axes .display_names
@@ -756,8 +808,7 @@ def _update_digits_scientific(self, data):
756
808
self .scientific_checkbox .setChecked (use_scientific )
757
809
self .scientific_checkbox .setEnabled (is_number (dtype ))
758
810
759
- self .bgcolor_checkbox .setChecked (self .model_data .bgcolor_enabled )
760
- self .bgcolor_checkbox .setEnabled (self .model_data .bgcolor_enabled )
811
+ self .gradient_chooser .setEnabled (self .model_data .bgcolor_possible )
761
812
762
813
def choose_scientific (self , data ):
763
814
# max_digits = self.get_max_digits()
0 commit comments