d6ddd16c4824f9b96ece02e5fb124d6bea646099
[jalview.git] / src / jalview / gui / FeatureColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.0b1)
3  * Copyright (C) 2014 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 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  * The Jalview Authors are detailed in the 'AUTHORS' file.
18  */
19 package jalview.gui;
20
21 import java.util.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25 import javax.swing.*;
26 import javax.swing.border.LineBorder;
27 import javax.swing.event.*;
28
29 import jalview.datamodel.*;
30 import jalview.schemes.*;
31 import jalview.util.MessageManager;
32
33 import java.awt.Dimension;
34
35 public class FeatureColourChooser extends JalviewDialog
36 {
37   // FeatureSettings fs;
38   FeatureRenderer fr;
39
40   private GraduatedColor cs;
41
42   private Object oldcs;
43
44   /**
45    * 
46    * @return the last colour setting selected by user - either oldcs (which may
47    *         be a java.awt.Color) or the new GraduatedColor
48    */
49   public Object getLastColour()
50   {
51     if (cs == null)
52     {
53       return oldcs;
54     }
55     return cs;
56   }
57
58   Hashtable oldgroupColours;
59
60   AlignmentPanel ap;
61
62   boolean adjusting = false;
63
64   private float min;
65
66   private float max;
67
68   String type = null;
69
70   public FeatureColourChooser(FeatureRenderer frender, String type)
71   {
72     this(frender, false, type);
73   }
74
75   public FeatureColourChooser(FeatureRenderer frender, boolean block,
76           String type)
77   {
78     this.fr = frender;
79     this.type = type;
80     ap = fr.ap;
81     initDialogFrame(this, true, block, "Graduated Feature Colour for "
82             + type, 480, 185);
83     // frame.setLayer(JLayeredPane.PALETTE_LAYER);
84     // Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type,
85     // 480, 145);
86
87     slider.addChangeListener(new ChangeListener()
88     {
89       public void stateChanged(ChangeEvent evt)
90       {
91         if (!adjusting)
92         {
93           thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
94           valueChanged();
95         }
96       }
97     });
98     slider.addMouseListener(new MouseAdapter()
99     {
100       public void mouseReleased(MouseEvent evt)
101       {
102         if (ap != null)
103         {
104           ap.paintAlignment(true);
105         }
106         ;
107       }
108     });
109
110     float mm[] = ((float[][]) fr.minmax.get(type))[0];
111     min = mm[0];
112     max = mm[1];
113     oldcs = fr.featureColours.get(type);
114     if (oldcs instanceof GraduatedColor)
115     {
116       if (((GraduatedColor) oldcs).isAutoScale())
117       {
118         // update the scale
119         cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
120       }
121       else
122       {
123         cs = new GraduatedColor((GraduatedColor) oldcs);
124       }
125     }
126     else
127     {
128       // promote original color to a graduated color
129       Color bl = Color.black;
130       if (oldcs instanceof Color)
131       {
132         bl = (Color) oldcs;
133       }
134       // original colour becomes the maximum colour
135       cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]);
136       cs.setColourByLabel(false);
137     }
138     minColour.setBackground(oldminColour = cs.getMinColor());
139     maxColour.setBackground(oldmaxColour = cs.getMaxColor());
140     adjusting = true;
141
142     try
143     {
144       jbInit();
145     } catch (Exception ex)
146     {
147     }
148     // update the gui from threshold state
149     thresholdIsMin.setSelected(!cs.isAutoScale());
150     colourByLabel.setSelected(cs.isColourByLabel());
151     if (cs.getThreshType() != AnnotationColourGradient.NO_THRESHOLD)
152     {
153       // initialise threshold slider and selector
154       threshold
155               .setSelectedIndex(cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1
156                       : 2);
157       slider.setEnabled(true);
158       thresholdValue.setEnabled(true);
159       threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
160               "Threshold", Color.black);
161
162     }
163
164     adjusting = false;
165
166     changeColour();
167     waitForInput();
168   }
169
170   public FeatureColourChooser()
171   {
172     try
173     {
174       jbInit();
175     } catch (Exception ex)
176     {
177       ex.printStackTrace();
178     }
179   }
180
181   private void jbInit() throws Exception
182   {
183
184     minColour.setFont(JvSwingUtils.getLabelFont());
185     minColour.setBorder(BorderFactory.createLineBorder(Color.black));
186     minColour.setPreferredSize(new Dimension(40, 20));
187     minColour.setToolTipText(MessageManager.getString("label.min_colour"));
188     minColour.addMouseListener(new MouseAdapter()
189     {
190       public void mousePressed(MouseEvent e)
191       {
192         if (minColour.isEnabled())
193         {
194           minColour_actionPerformed();
195         }
196       }
197     });
198     maxColour.setFont(JvSwingUtils.getLabelFont());
199     maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
200     maxColour.setPreferredSize(new Dimension(40, 20));
201     maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
202     maxColour.addMouseListener(new MouseAdapter()
203     {
204       public void mousePressed(MouseEvent e)
205       {
206         if (maxColour.isEnabled())
207         {
208           maxColour_actionPerformed();
209         }
210       }
211     });
212     maxColour.setBorder(new LineBorder(Color.black));
213     minText.setText(MessageManager.getString("label.min"));
214     minText.setFont(JvSwingUtils.getLabelFont());
215     maxText.setText(MessageManager.getString("label.max"));
216     maxText.setFont(JvSwingUtils.getLabelFont());
217     this.setLayout(borderLayout1);
218     jPanel2.setLayout(flowLayout1);
219     jPanel1.setBackground(Color.white);
220     jPanel2.setBackground(Color.white);
221     threshold.addActionListener(new ActionListener()
222     {
223       public void actionPerformed(ActionEvent e)
224       {
225         threshold_actionPerformed(e);
226       }
227     });
228     threshold.setToolTipText(MessageManager.getString("label.threshold_feature_display_by_score"));
229     threshold.addItem(MessageManager.getString("label.threshold_feature_no_thereshold")); // index 0
230     threshold.addItem(MessageManager.getString("label.threshold_feature_above_thereshold")); // index 1
231     threshold.addItem(MessageManager.getString("label.threshold_feature_below_thereshold")); // index 2
232     jPanel3.setLayout(flowLayout2);
233     thresholdValue.addActionListener(new ActionListener()
234     {
235       public void actionPerformed(ActionEvent e)
236       {
237         thresholdValue_actionPerformed(e);
238       }
239     });
240     slider.setPaintLabels(false);
241     slider.setPaintTicks(true);
242     slider.setBackground(Color.white);
243     slider.setEnabled(false);
244     slider.setOpaque(false);
245     slider.setPreferredSize(new Dimension(100, 32));
246     slider.setToolTipText(MessageManager.getString("label.adjust_thereshold"));
247     thresholdValue.setEnabled(false);
248     thresholdValue.setColumns(7);
249     jPanel3.setBackground(Color.white);
250     thresholdIsMin.setBackground(Color.white);
251     thresholdIsMin.setText(MessageManager.getString("label.threshold_minmax"));
252     thresholdIsMin
253             .setToolTipText(MessageManager.getString("label.toggle_absolute_relative_display_threshold"));
254     thresholdIsMin.addActionListener(new ActionListener()
255     {
256       public void actionPerformed(ActionEvent actionEvent)
257       {
258         thresholdIsMin_actionPerformed(actionEvent);
259       }
260     });
261     colourByLabel.setBackground(Color.white);
262     colourByLabel.setText(MessageManager.getString("label.colour_by_label"));
263     colourByLabel
264             .setToolTipText(MessageManager.getString("label.display_features_same_type_different_label_using_different_colour"));
265     colourByLabel.addActionListener(new ActionListener()
266     {
267       public void actionPerformed(ActionEvent actionEvent)
268       {
269         colourByLabel_actionPerformed(actionEvent);
270       }
271     });
272     colourPanel.setBackground(Color.white);
273     jPanel1.add(ok);
274     jPanel1.add(cancel);
275     jPanel2.add(colourByLabel, java.awt.BorderLayout.WEST);
276     jPanel2.add(colourPanel, java.awt.BorderLayout.EAST);
277     colourPanel.add(minText);
278     colourPanel.add(minColour);
279     colourPanel.add(maxText);
280     colourPanel.add(maxColour);
281     this.add(jPanel3, java.awt.BorderLayout.CENTER);
282     jPanel3.add(threshold);
283     jPanel3.add(slider);
284     jPanel3.add(thresholdValue);
285     jPanel3.add(thresholdIsMin);
286     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
287     this.add(jPanel2, java.awt.BorderLayout.NORTH);
288   }
289
290   JLabel minText = new JLabel();
291
292   JLabel maxText = new JLabel();
293
294   JPanel minColour = new JPanel();
295
296   JPanel maxColour = new JPanel();
297
298   JPanel colourPanel = new JPanel();
299
300   JPanel jPanel1 = new JPanel();
301
302   JPanel jPanel2 = new JPanel();
303
304   BorderLayout borderLayout1 = new BorderLayout();
305
306   JComboBox threshold = new JComboBox();
307
308   FlowLayout flowLayout1 = new FlowLayout();
309
310   JPanel jPanel3 = new JPanel();
311
312   FlowLayout flowLayout2 = new FlowLayout();
313
314   JSlider slider = new JSlider();
315
316   JTextField thresholdValue = new JTextField(20);
317
318   // TODO implement GUI for tolower flag
319   // JCheckBox toLower = new JCheckBox();
320
321   JCheckBox thresholdIsMin = new JCheckBox();
322
323   JCheckBox colourByLabel = new JCheckBox();
324
325   private GraphLine threshline;
326
327   private Color oldmaxColour;
328
329   private Color oldminColour;
330
331   public void minColour_actionPerformed()
332   {
333     Color col = JColorChooser.showDialog(this,
334             MessageManager.getString("label.select_colour_minimum_value"), minColour.getBackground());
335     if (col != null)
336     {
337       minColour.setBackground(col);
338       minColour.setForeground(col);
339     }
340     minColour.repaint();
341     changeColour();
342   }
343
344   public void maxColour_actionPerformed()
345   {
346     Color col = JColorChooser.showDialog(this,
347             MessageManager.getString("label.select_colour_maximum_value"), maxColour.getBackground());
348     if (col != null)
349     {
350       maxColour.setBackground(col);
351       maxColour.setForeground(col);
352     }
353     maxColour.repaint();
354     changeColour();
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
378     GraduatedColor acg;
379     if (cs.isColourByLabel())
380     {
381       acg = new GraduatedColor(oldminColour, oldmaxColour, min, max);
382     }
383     else
384     {
385       acg = new GraduatedColor(oldminColour = minColour.getBackground(),
386               oldmaxColour = maxColour.getBackground(), min, max);
387
388     }
389
390     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
391     {
392       slider.setEnabled(false);
393       thresholdValue.setEnabled(false);
394       thresholdValue.setText("");
395       thresholdIsMin.setEnabled(false);
396     }
397     else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD
398             && threshline == null)
399     {
400       // todo visual indication of feature threshold
401       threshline = new jalview.datamodel.GraphLine((max - min) / 2f,
402               "Threshold", Color.black);
403     }
404
405     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
406     {
407       adjusting = true;
408       acg.setThresh(threshline.value);
409
410       float range = max * 1000f - min * 1000f;
411
412       slider.setMinimum((int) (min * 1000));
413       slider.setMaximum((int) (max * 1000));
414       slider.setValue((int) (threshline.value * 1000));
415       thresholdValue.setText(threshline.value + "");
416       slider.setMajorTickSpacing((int) (range / 10f));
417       slider.setEnabled(true);
418       thresholdValue.setEnabled(true);
419       thresholdIsMin.setEnabled(!colourByLabel.isSelected());
420       adjusting = false;
421     }
422
423     acg.setThreshType(aboveThreshold);
424     if (thresholdIsMin.isSelected()
425             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
426     {
427       acg.setAutoScaled(false);
428       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
429       {
430         acg = new GraduatedColor(acg, threshline.value, max);
431       }
432       else
433       {
434         acg = new GraduatedColor(acg, min, threshline.value);
435       }
436     }
437     else
438     {
439       acg.setAutoScaled(true);
440     }
441     acg.setColourByLabel(colourByLabel.isSelected());
442     if (acg.isColourByLabel())
443     {
444       maxColour.setEnabled(false);
445       minColour.setEnabled(false);
446       maxColour.setBackground(this.getBackground());
447       maxColour.setForeground(this.getBackground());
448       minColour.setBackground(this.getBackground());
449       minColour.setForeground(this.getBackground());
450
451     }
452     else
453     {
454       maxColour.setEnabled(true);
455       minColour.setEnabled(true);
456       maxColour.setBackground(oldmaxColour);
457       minColour.setBackground(oldminColour);
458       maxColour.setForeground(oldmaxColour);
459       minColour.setForeground(oldminColour);
460     }
461     fr.featureColours.put(type, acg);
462     cs = acg;
463     ap.paintAlignment(false);
464   }
465
466   protected void raiseClosed()
467   {
468     if (this.colourEditor != null)
469     {
470       colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
471     }
472   }
473
474   public void okPressed()
475   {
476     changeColour();
477   }
478
479   public void cancelPressed()
480   {
481     reset();
482   }
483
484   void reset()
485   {
486     fr.featureColours.put(type, oldcs);
487     ap.paintAlignment(false);
488     cs = null;
489   }
490
491   public void thresholdCheck_actionPerformed(ActionEvent e)
492   {
493     changeColour();
494   }
495
496   public void annotations_actionPerformed(ActionEvent e)
497   {
498     changeColour();
499   }
500
501   public void threshold_actionPerformed(ActionEvent e)
502   {
503     changeColour();
504   }
505
506   public void thresholdValue_actionPerformed(ActionEvent e)
507   {
508     try
509     {
510       float f = Float.parseFloat(thresholdValue.getText());
511       slider.setValue((int) (f * 1000));
512       threshline.value = f;
513     } catch (NumberFormatException ex)
514     {
515     }
516   }
517
518   public void valueChanged()
519   {
520     threshline.value = (float) slider.getValue() / 1000f;
521     cs.setThresh(threshline.value);
522     changeColour();
523     ap.paintAlignment(false);
524   }
525
526   public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
527   {
528     changeColour();
529   }
530
531   public void colourByLabel_actionPerformed(ActionEvent actionEvent)
532   {
533     changeColour();
534   }
535
536   ActionListener colourEditor = null;
537
538   public void addActionListener(ActionListener graduatedColorEditor)
539   {
540     if (colourEditor != null)
541     {
542       System.err
543               .println("IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
544     }
545     colourEditor = graduatedColorEditor;
546   }
547
548 }