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