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