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