source: orange/orange/OrangeWidgets/ColorPalette.py @ 8181:54af17f63bcc

Revision 8181:54af17f63bcc, 13.8 KB checked in by Noughmad <Noughmad@…>, 3 years ago (diff)

Make Qwt depencencies in Optimization dialogs optional

Line 
1from PyQt4.QtCore import *
2from PyQt4.QtGui import *
3import math
4from OWWidget import *
5import OWGUI
6
7###########################################################################
8class TestWidget(OWWidget):
9    def __init__(self, parent=None, name='TestWidget'):
10        OWWidget.__init__(self, parent, name, 'Microarray Heat Map', FALSE)
11        #self.controlArea = self
12        #self.setLayout(QVBoxLayout())
13
14        self.colorPalette = ColorPalette(self, self.controlArea, "", additionalColors = None)
15        self.controlArea.layout().addWidget(self.colorPalette)
16        #a = ColorButton(self)
17        #self.controlArea.layout().addWidget(a)
18
19###########################################################################
20
21colorButtonSize = 15
22specialColorLabelWidth = 160
23paletteInterpolationColors = 250
24
25# On Mac OS X there are problems with QRgb and whether it is long or int and even whether
26# it is positive or negative number (there is corelation between those)
27# Color can be stored in 32 bit unsigned int but Python does not have unsigned int explicitly
28# So Python on Mac sometimes uses long where it should use int (when the highest bit is set and
29# it sees the number as positive - so it cannot be stored as positive number in 31 bits) and sometimes
30# it needs unsigned number and so uses long and does not want a signed int
31
32try:
33    qRed(-1)
34    wantsPositiveColor = False
35except:
36    wantsPositiveColor = True
37
38def signedColor(long):
39    if isinstance(long, int):
40        return long
41   
42    long &= 0xFFFFFFFF
43   
44    if long & 0x80000000:
45        return int(-((long ^ 0xFFFFFFFF) + 1))
46    else:
47        return int(long)
48
49def positiveColor(color):
50    if wantsPositiveColor and color < 0:
51        return (-color - 1) ^ 0xFFFFFFFF
52    else:
53        return color
54
55def signedPalette(palette):
56    return [signedColor(color) for color in palette]
57
58class ColorPalette(QWidget):
59    def __init__(self, parent, master, value, label = "Colors", additionalColors = None, callback = None):
60        QWidget.__init__(self, parent)
61
62        self.constructing = TRUE
63        self.callback = callback
64        self.schema = ""
65        self.passThroughBlack = 0
66
67        self.colorSchemas = {}
68
69        self.setMinimumHeight(300)
70        self.setMinimumWidth(200)
71
72        self.box = OWGUI.widgetBox(self, label, orientation = "vertical")
73
74        self.schemaCombo = OWGUI.comboBox(self.box, self, "schema", callback = self.onComboBoxChange)
75
76        self.interpolationHBox = OWGUI.widgetBox(self.box, orientation = "horizontal")
77        self.colorButton1 = ColorButton(self, self.interpolationHBox)
78        self.interpolationView = InterpolationView(self.interpolationHBox)
79        self.colorButton2 = ColorButton(self, self.interpolationHBox)
80
81        self.chkPassThroughBlack = OWGUI.checkBox(self.box, self, "passThroughBlack", "Pass through black", callback = self.onCheckBoxChange)
82        #OWGUI.separator(self.box, 10, 10)
83        self.box.layout().addSpacing(10)
84
85        #special colors buttons
86
87        self.NAColorButton = ColorButton(self, self.box, "N/A")
88        self.underflowColorButton = ColorButton(self, self.box, "Underflow")
89        self.overflowColorButton = ColorButton(self, self.box, "Overflow")
90        self.backgroundColorButton = ColorButton(self, self.box, "Background (Grid)")
91
92        #set up additional colors
93        self.additionalColorButtons = {}
94
95        if additionalColors<>None:
96            for colorName in additionalColors:
97                self.additionalColorButtons[colorName] = ColorButton(self, self.box, colorName)
98
99        #set up new and delete buttons
100        self.buttonHBox = OWGUI.widgetBox(self.box, orientation = "horizontal")
101        self.newButton = OWGUI.button(self.buttonHBox, self, "New", self.OnNewButtonClicked)
102        self.deleteButton = OWGUI.button(self.buttonHBox, self, "Delete", self.OnDeleteButtonClicked)
103
104        self.setInitialColorPalettes()
105        self.paletteSelected()
106        self.constructing = FALSE
107
108    def onComboBoxChange(self, string):
109        self.paletteSelected()
110
111    def onCheckBoxChange(self, state):
112        self.colorSchemaChange()
113
114    def OnNewButtonClicked(self):
115        message = "Please enter new color schema name"
116        ok = FALSE
117        while (not ok):
118            s = QInputDialog.getText(self, "New Schema", message)
119            ok = TRUE
120            if (s[1]==TRUE):
121                for i in range(self.schemaCombo.count()):
122                    if s[0].lower().compare(self.schemaCombo.itemText(i).lower())==0:
123                        ok = FALSE
124                        message = "Color schema with that name already exists, please enter another name"
125                if (ok):
126                    self.colorSchemas[str(s[0])] = ColorSchema(self.getCurrentColorSchema().getName(),
127                                                               self.getCurrentColorSchema().getPalette(),
128                                                               self.getCurrentColorSchema().getAdditionalColors(),
129                                                               self.getCurrentColorSchema().getPassThroughBlack())
130                    self.schemaCombo.addItem(s[0])
131                    self.schemaCombo.setCurrentIndex(self.schemaCombo.count()-1)
132            self.deleteButton.setEnabled(self.schemaCombo.count()>1)
133
134
135    def OnDeleteButtonClicked(self):
136        i = self.schemaCombo.currentIndex()
137        self.schemaCombo.removeItem(i)
138        self.schemaCombo.setCurrentIndex(i)
139        self.deleteButton.setEnabled(self.schemaCombo.count()>1)
140        self.paletteSelected()
141
142    def getCurrentColorSchema(self):
143        return self.colorSchemas[str(self.schemaCombo.currentText())]
144
145    def setCurrentColorSchema(self, schema):
146        self.colorSchemas[str(self.schemaCombo.currentText())] = schema
147
148
149    def getColorSchemas(self):
150        return self.colorSchemas
151
152    def setColorSchemas(self, schemas):
153        self.colorSchemas = schemas
154        self.schemaCombo.clear()
155        self.schemaCombo.addItems(schemas)
156        self.paletteSelected()
157
158    def createPalette(self,color1,color2, passThroughBlack):
159        palette = []
160        if passThroughBlack:
161            for i in range(paletteInterpolationColors/2):
162                palette += [qRgb(color1.red() - color1.red()*i*2./paletteInterpolationColors,
163                                 color1.green() - color1.green()*i*2./paletteInterpolationColors,
164                                 color1.blue() - color1.blue()*i*2./paletteInterpolationColors)]
165
166            for i in range(paletteInterpolationColors - (paletteInterpolationColors/2)):
167                palette += [qRgb(color2.red()*i*2./paletteInterpolationColors,
168                                 color2.green()*i*2./paletteInterpolationColors,
169                                 color2.blue()*i*2./paletteInterpolationColors)]
170        else:
171            for i in range(paletteInterpolationColors):
172                palette += [qRgb(color1.red() + (color2.red()-color1.red())*i/paletteInterpolationColors,
173                                 color1.green() + (color2.green()-color1.green())*i/paletteInterpolationColors,
174                                 color1.blue() + (color2.blue()-color1.blue())*i/paletteInterpolationColors)]
175        return palette
176
177    def paletteSelected(self):
178        schema = self.getCurrentColorSchema()
179        self.interpolationView.setPalette1(schema.getPalette())
180        self.colorButton1.setColor(self.rgbToQColor(schema.getPalette()[0]))
181        self.colorButton2.setColor(self.rgbToQColor(schema.getPalette()[249]))
182
183        self.chkPassThroughBlack.setChecked(schema.getPassThroughBlack())
184
185        self.NAColorButton.setColor(self.rgbToQColor(schema.getPalette()[255]))
186        self.overflowColorButton.setColor(self.rgbToQColor(schema.getPalette()[254]))
187        self.underflowColorButton.setColor(self.rgbToQColor(schema.getPalette()[253]))
188        self.backgroundColorButton.setColor(self.rgbToQColor(schema.getPalette()[252]))
189
190        for buttonName in self.additionalColorButtons:
191            self.additionalColorButtons[buttonName].setColor(self.rgbToQColor(schema.getAdditionalColors()[buttonName]))
192
193        if not self.constructing:
194            self.callback()
195
196    def rgbToQColor(self, rgb):
197        # we could also use QColor(positiveColor(rgb), 0xFFFFFFFF) but there is probably a reason
198        # why this was not used before so I am leaving it as it is
199
200        return QColor(qRed(positiveColor(rgb)), qGreen(positiveColor(rgb)), qBlue(positiveColor(rgb))) # on Mac color cannot be negative number in this case so we convert it manually
201
202    def qRgbFromQColor(self, qcolor):
203        return qRgb(qcolor.red(), qcolor.green(), qcolor.blue())
204
205    def colorSchemaChange(self):
206        white = qRgb(255,255,255)
207        gray = qRgb(200,200,200)
208        name = self.getCurrentColorSchema().getName()
209        passThroughBlack = self.chkPassThroughBlack.isChecked()
210        palette = self.createPalette(self.colorButton1.getColor(), self.colorButton2.getColor(), passThroughBlack)
211        palette += [white]*2 + [self.qRgbFromQColor(self.backgroundColorButton.getColor())] + \
212                               [self.qRgbFromQColor(self.underflowColorButton.getColor())] + \
213                               [self.qRgbFromQColor(self.overflowColorButton.getColor())] + \
214                               [self.qRgbFromQColor(self.NAColorButton.getColor())]
215
216        self.interpolationView.setPalette1(palette)
217
218        additionalColors = {}
219        for buttonName in self.additionalColorButtons:
220            additionalColors[buttonName] = self.qRgbFromQColor(self.additionalColorButtons[buttonName].getColor())
221
222        schema = ColorSchema(name, palette, additionalColors, passThroughBlack)
223        self.setCurrentColorSchema(schema)
224
225        if not self.constructing and self.callback:
226            self.callback()
227
228
229    def setInitialColorPalettes(self):
230        white = qRgb(255,255,255)
231        gray = qRgb(200,200,200)
232
233        additionalColors = {}
234        for buttonName in self.additionalColorButtons:
235            additionalColors[buttonName] = gray
236
237
238        self.schemaCombo.addItem("Blue - Yellow")
239        palette = self.createPalette(QColor(0,0,255), QColor(255,255,0),FALSE)
240        palette += [white]*3 + [qRgb(0., 0., 255.), qRgb(255., 255., 0.), gray]
241        self.colorSchemas["Blue - Yellow"] = ColorSchema("Blue - Yellow", palette, additionalColors, FALSE)
242
243        self.schemaCombo.addItem("Black - Red")
244        palette = self.createPalette(QColor(0,0,0), QColor(255,0,0),FALSE)
245        palette += [white]*3 + [qRgb(0., 0, 0), qRgb(255., 0, 0), gray]
246        self.colorSchemas["Black - Red"] = ColorSchema("Black - Red", palette, additionalColors, FALSE)
247
248        self.schemaCombo.addItem("Green - Black - Red")
249        palette = self.createPalette(QColor(0,255,0), QColor(255,0,0),TRUE)
250        palette += [white]*3 + [qRgb(0, 255., 0), qRgb(255., 0, 0), gray]
251        self.colorSchemas["Green - Black - Red"] = ColorSchema("Green - Black - Red", palette, additionalColors, TRUE)
252
253
254class ColorSchema:
255    def __init__(self, name, palette, additionalColors, passThroughBlack):
256        self.name = name
257        self.palette = palette
258        self.additionalColors = additionalColors
259        self.passThroughBlack = passThroughBlack
260
261    def getName(self):
262        return self.name
263
264    def getPalette(self):
265        return self.palette
266
267    def getAdditionalColors(self):
268        return self.additionalColors
269
270    def getPassThroughBlack(self):
271        return self.passThroughBlack
272
273class InterpolationView(QGraphicsView):
274    def __init__(self, parent = None):
275        self.canvas = QGraphicsScene(0,0,colorButtonSize,colorButtonSize)
276        QGraphicsView.__init__(self, self.canvas, parent)
277
278        self.setFrameStyle(QFrame.NoFrame)
279        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
280        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
281
282        self.setFixedHeight(colorButtonSize)
283        self.setMinimumWidth(colorButtonSize)
284        self.setMaximumWidth(135)
285        if parent and parent.layout():
286            parent.layout().addWidget(self)
287
288    def setPalette1(self, palette):
289        dx = 140; dy = colorButtonSize
290        bmp = chr(252)*dx*2 + reduce(lambda x,y:x+y, [chr(i*250/dx) for i in range(dx)] * (dy-4)) + chr(252)*dx*2
291        image = QImage(bmp, dx, dy, QImage.Format_MonoLSB)
292        #image.setNumColors(256)
293        image.setColorTable(palette)
294        pm = QPixmap()
295        pm.fromImage(image)
296
297        self.canvas.addPixmap(pm)
298        self.canvas.update()
299
300class ColorButton(QWidget):
301    def __init__(self, master = None, parent = None, label = None, color = None):
302        QWidget.__init__(self, master)
303
304        self.parent = parent
305        self.master = master
306
307        if self.parent and self.parent.layout():
308            self.parent.layout().addWidget(self)
309
310        self.setLayout(QHBoxLayout())
311        self.layout().setMargin(0)
312        self.icon = QFrame(self)
313        self.icon.setFixedSize(colorButtonSize, colorButtonSize)
314        self.icon.setAutoFillBackground(1)
315        self.icon.setFrameStyle (QFrame.StyledPanel+ QFrame.Sunken)
316        self.layout().addWidget(self.icon)
317
318        if label != None:
319            self.label = OWGUI.widgetLabel(self, label)
320            self.layout().addWidget(self.label)
321
322        if color != None:
323            self.setColor(color)
324
325
326    def setColor(self, color):
327        self.color = color
328        palette = QPalette()
329        palette.setBrush(QPalette.Background, color)
330        self.icon.setPalette(palette)
331
332    def getColor(self):
333        return self.color
334
335    def mousePressEvent(self, ev):
336        color = QColorDialog.getColor(self.color, self.parent)
337        if color.isValid():
338            self.setColor(color)
339            if self.master and hasattr(self.master, "colorSchemaChange"):
340                self.master.colorSchemaChange()
341
342
343if __name__=="__main__":
344    import orange
345    a = QApplication(sys.argv)
346    ow = TestWidget()
347    #a.setMainWidget(ow)
348
349    ow.show()
350    sys.exit(a.exec_())
351    ow.saveSettings()
352
Note: See TracBrowser for help on using the repository browser.