235e82cab98fc1cc2512356faef089b441d4547e
[jalview.git] / src / jalview / appletgui / FeatureColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import java.util.*;
21
22 import java.awt.*;
23 import java.awt.event.*;
24
25 import jalview.datamodel.*;
26 import jalview.schemes.*;
27
28 public class FeatureColourChooser extends Panel implements ActionListener,
29         AdjustmentListener, ItemListener, MouseListener
30 {
31   JVDialog frame;
32
33   Frame owner;
34
35   FeatureRenderer fr;
36
37   FeatureSettings fs = null;
38
39   // AlignmentPanel ap;
40
41   GraduatedColor cs;
42
43   Object oldcs;
44
45   Hashtable oldgroupColours;
46
47   boolean adjusting = false;
48
49   private float min, max;
50
51   String type = null;
52
53   private AlignFrame af = null;
54
55   public FeatureColourChooser(AlignFrame af, String type)
56   {
57     this.af = af;
58     init(af.getSeqcanvas().getFeatureRenderer(), type);
59   }
60
61   public FeatureColourChooser(FeatureSettings fsettings, String type)
62   {
63     this.fs = fsettings;
64     init(fsettings.fr, type);
65     // this.ap = fsettings.ap;
66   }
67
68   private void init(FeatureRenderer frenderer, String type)
69   {
70     this.type = type;
71     fr = frenderer;
72     float mm[] = ((float[][]) fr.minmax.get(type))[0];
73     min = mm[0];
74     max = mm[1];
75     oldcs = fr.featureColours.get(type);
76     if (oldcs instanceof GraduatedColor)
77     {
78       cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
79     }
80     else
81     {
82       // promote original color to a graduated color
83       Color bl = Color.black;
84       if (oldcs instanceof Color)
85       {
86         bl = (Color) oldcs;
87       }
88       // original colour becomes the maximum colour
89       cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
90     }
91     minColour.setBackground(cs.getMinColor());
92     maxColour.setBackground(cs.getMaxColor());
93     minColour.setForeground(cs.getMinColor());
94     maxColour.setForeground(cs.getMaxColor());
95     colourFromLabel.setState(cs.isColourByLabel());
96     adjusting = true;
97
98     try
99     {
100       jbInit();
101     } catch (Exception ex)
102     {
103     }
104     threshold
105             .select(cs.getThreshType() == AnnotationColourGradient.NO_THRESHOLD ? 0
106                     : cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
107                             : 2);
108
109     adjusting = false;
110     changeColour();
111     colourFromLabel.addItemListener(this);
112     slider.addAdjustmentListener(this);
113     slider.addMouseListener(this);
114     owner = (af != null) ? af : fs.frame;
115     frame = new JVDialog(owner, "Graduated Feature Colour for " + type,
116             true, 480, 248);
117     frame.setMainPanel(this);
118     validate();
119     frame.setVisible(true);
120     if (frame.accept)
121     {
122       changeColour();
123     }
124     else
125     {
126       // cancel
127       reset();
128       PaintRefresher.Refresh(this, fr.av.getSequenceSetId());
129       frame.setVisible(false);
130     }
131   }
132
133   public FeatureColourChooser()
134   {
135     try
136     {
137       jbInit();
138     } catch (Exception ex)
139     {
140       ex.printStackTrace();
141     }
142   }
143
144   private void jbInit() throws Exception
145   {
146     Label minLabel = new Label("Min:"), maxLabel = new Label("Max:");
147     minLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
148     maxLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
149     // minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
150     // minColour.setLabel("Min Colour");
151
152     minColour.setBounds(0, 0, 40, 27);
153     maxColour.setBounds(0, 0, 40, 27);
154     minColour.addMouseListener(this);
155
156     maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
157     maxColour.addMouseListener(this);
158
159     thresholdIsMin.addItemListener(this);
160
161     this.setLayout(new GridLayout(4, 1));
162     jPanel1.setLayout(new FlowLayout());
163     jPanel2.setLayout(new FlowLayout());
164     jPanel3.setLayout(new GridLayout(1, 1));
165     jPanel4.setLayout(new FlowLayout());
166     jPanel1.setBackground(Color.white);
167     jPanel2.setBackground(Color.white);
168     jPanel4.setBackground(Color.white);
169     threshold.addItemListener(this);
170     threshold.addItem("No Threshold");
171     threshold.addItem("Above Threshold");
172     threshold.addItem("Below Threshold");
173     thresholdValue.addActionListener(this);
174     slider.setBackground(Color.white);
175     slider.setEnabled(false);
176     slider.setSize(new Dimension(93, 21));
177     thresholdValue.setEnabled(false);
178     thresholdValue.setSize(new Dimension(79, 22)); // setBounds(new
179                                                    // Rectangle(248, 2, 79,
180                                                    // 22));
181     thresholdValue.setColumns(5);
182     jPanel3.setBackground(Color.white);
183
184     colourFromLabel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
185     colourFromLabel.setLabel("Colour by Label");
186     colourFromLabel.setSize(new Dimension(139, 22));
187     // threshold.setBounds(new Rectangle(11, 3, 139, 22));
188     thresholdIsMin.setBackground(Color.white);
189     thresholdIsMin.setLabel("Threshold is min/max");
190     thresholdIsMin.setSize(new Dimension(135, 23));
191     // thresholdIsMin.setBounds(new Rectangle(328, 3, 135, 23));
192     jPanel1.add(minLabel);
193     jPanel1.add(minColour);
194     jPanel1.add(maxLabel);
195     jPanel1.add(maxColour);
196     jPanel1.add(colourFromLabel);
197     jPanel2.add(threshold);
198     jPanel3.add(slider);
199     jPanel4.add(thresholdValue);
200     jPanel4.add(thresholdIsMin);
201     this.add(jPanel1);// , java.awt.BorderLayout.NORTH);
202     this.add(jPanel2);// , java.awt.BorderLayout.NORTH);
203     this.add(jPanel3);// , java.awt.BorderLayout.CENTER);
204     this.add(jPanel4);// , java.awt.BorderLayout.CENTER);
205   }
206
207   Panel minColour = new Panel();
208
209   Panel maxColour = new Panel();
210
211   Panel jPanel1 = new Panel();
212
213   Panel jPanel2 = new Panel();
214
215   Choice threshold = new Choice();
216
217   Panel jPanel3 = new Panel();
218
219   Panel jPanel4 = new Panel();
220
221   Scrollbar slider = new Scrollbar(Scrollbar.HORIZONTAL);
222
223   TextField thresholdValue = new TextField(20);
224
225   // BorderLayout borderLayout1 = new BorderLayout();
226
227   Checkbox thresholdIsMin = new Checkbox();
228
229   Checkbox colourFromLabel = new Checkbox();
230
231   private GraphLine threshline;
232
233   public void actionPerformed(ActionEvent evt)
234   {
235     if (evt.getSource() == thresholdValue)
236     {
237       try
238       {
239         float f = new Float(thresholdValue.getText()).floatValue();
240         slider.setValue((int) (f * 1000));
241         adjustmentValueChanged(null);
242       } catch (NumberFormatException ex)
243       {
244       }
245     }
246     else if (evt.getSource() == minColour)
247     {
248       minColour_actionPerformed(null);
249     }
250     else if (evt.getSource() == maxColour)
251     {
252       maxColour_actionPerformed(null);
253     }
254     else
255     {
256       changeColour();
257     }
258   }
259
260   public void itemStateChanged(ItemEvent evt)
261   {
262     maxColour.setEnabled(!colourFromLabel.getState());
263     minColour.setEnabled(!colourFromLabel.getState());
264     changeColour();
265   }
266
267   public void adjustmentValueChanged(AdjustmentEvent evt)
268   {
269     if (!adjusting)
270     {
271       thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
272       valueChanged();
273     }
274   }
275
276   protected void valueChanged()
277   {
278     threshline.value = (float) slider.getValue() / 1000f;
279     cs.setThresh(threshline.value);
280     changeColour();
281     PaintRefresher.Refresh(this, fr.av.getSequenceSetId());
282     // ap.paintAlignment(false);
283   }
284
285   public void minColour_actionPerformed(Color newCol)
286   {
287     if (newCol == null)
288     {
289       UserDefinedColours udc = new UserDefinedColours(this,
290               minColour.getBackground(), owner,
291               "Select Colour for Minimum Value"); // frame.owner,
292     }
293     else
294     {
295       minColour.setBackground(newCol);
296       minColour.setForeground(newCol);
297       minColour.repaint();
298       changeColour();
299     }
300
301   }
302
303   public void maxColour_actionPerformed(Color newCol)
304   {
305     if (newCol == null)
306     {
307
308       // UserDefinedColours udc = new UserDefinedColours(this,
309       // "Select Colour for Maximum Value",maxColour.getBackground(),true);
310       UserDefinedColours udc = new UserDefinedColours(this,
311               maxColour.getBackground(), owner,
312               "Select Colour for Maximum Value");
313     }
314     else
315     {
316       maxColour.setBackground(newCol);
317       maxColour.setForeground(newCol);
318       maxColour.repaint();
319       changeColour();
320     }
321   }
322
323   void changeColour()
324   {
325     // Check if combobox is still adjusting
326     if (adjusting)
327     {
328       return;
329     }
330
331     int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
332     if (threshold.getSelectedItem().equals("Above Threshold"))
333     {
334       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
335     }
336     else if (threshold.getSelectedItem().equals("Below Threshold"))
337     {
338       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
339     }
340
341     slider.setEnabled(true);
342     thresholdValue.setEnabled(true);
343     GraduatedColor acg = new GraduatedColor(minColour.getBackground(),
344             maxColour.getBackground(), min, max);
345
346     acg.setColourByLabel(colourFromLabel.getState());
347     maxColour.setEnabled(!colourFromLabel.getState());
348     minColour.setEnabled(!colourFromLabel.getState());
349     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
350     {
351       slider.setEnabled(false);
352       thresholdValue.setEnabled(false);
353       thresholdValue.setText("");
354     }
355
356     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
357             && threshline == null)
358     {
359       // todo visual indication of feature threshold
360       threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
361               "Threshold", Color.black);
362     }
363
364     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
365     {
366       adjusting = true;
367       acg.setThresh(threshline.value);
368
369       float range = max * 1000f - min * 1000f;
370
371       slider.setMinimum((int) (min * 1000));
372       slider.setMaximum((int) (max * 1000));
373       slider.setValue((int) (threshline.value * 1000));
374       thresholdValue.setText(threshline.value + "");
375       slider.setEnabled(true);
376       thresholdValue.setEnabled(true);
377       adjusting = false;
378     }
379
380     acg.setThreshType(aboveThreshold);
381     if (thresholdIsMin.getState()
382             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
383     {
384       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
385       {
386         acg = new GraduatedColor(acg, threshline.value, max);
387       }
388       else
389       {
390         acg = new GraduatedColor(acg, min, threshline.value);
391       }
392     }
393
394     fr.featureColours.put(type, acg);
395     cs = acg;
396     PaintRefresher.Refresh(this, fr.av.getSequenceSetId());
397     // ap.paintAlignment(false);
398   }
399
400   void reset()
401   {
402     fr.featureColours.put(type, oldcs);
403     PaintRefresher.Refresh(this, fr.av.getSequenceSetId());
404     // ap.paintAlignment(true);
405
406   }
407
408   public void mouseClicked(MouseEvent evt)
409   {
410   }
411
412   public void mousePressed(MouseEvent evt)
413   {
414   }
415
416   public void mouseReleased(MouseEvent evt)
417   {
418     if (evt.getSource() == minColour || evt.getSource() == maxColour)
419     {
420       // relay the event
421       actionPerformed(new ActionEvent(evt.getSource(), 1, "Clicked"));
422     }
423     else
424     {
425       PaintRefresher.Refresh(this, fr.av.getSequenceSetId());
426     }
427     // ap.paintAlignment(true);
428   }
429
430   public void mouseEntered(MouseEvent evt)
431   {
432   }
433
434   public void mouseExited(MouseEvent evt)
435   {
436   }
437
438 }