JAL-2630 update Overview/structure from graduated colour options dialog
[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.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   private static final int SCALE_FACTOR_1K = 1000;
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     threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
101     oldcs = fr.getFeatureColours().get(type);
102     if (oldcs.isGraduatedColour())
103     {
104       threshline.value = oldcs.getThreshold();
105       cs = new FeatureColour((FeatureColour) oldcs, min, max);
106     }
107     else
108     {
109       // promote original color to a graduated color
110       Color bl = Color.black;
111       if (oldcs.isSimpleColour())
112       {
113         bl = oldcs.getColour();
114       }
115       // original colour becomes the maximum colour
116       cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
117     }
118     minColour.setBackground(cs.getMinColour());
119     maxColour.setBackground(cs.getMaxColour());
120     minColour.setForeground(cs.getMinColour());
121     maxColour.setForeground(cs.getMaxColour());
122     colourFromLabel.setState(cs.isColourByLabel());
123     adjusting = true;
124
125     try
126     {
127       jbInit();
128     } catch (Exception ex)
129     {
130     }
131     threshold.select(cs.isAboveThreshold() ? 1 : (cs.isBelowThreshold() ? 2
132             : 0));
133
134     adjusting = false;
135     changeColour();
136     colourFromLabel.addItemListener(this);
137     slider.addAdjustmentListener(this);
138     slider.addMouseListener(this);
139     owner = (af != null) ? af : fs.frame;
140     frame = new JVDialog(owner, MessageManager.formatMessage(
141             "label.graduated_color_for_params", new String[] { type }),
142             true, 480, 248);
143     frame.setMainPanel(this);
144     validate();
145     frame.setVisible(true);
146     if (frame.accept)
147     {
148       changeColour();
149     }
150     else
151     {
152       // cancel
153       reset();
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 * SCALE_FACTOR_1K));
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 newCol)
320   {
321     if (newCol == 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(newCol);
330       minColour.setForeground(newCol);
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(minColour.getBackground(),
378             maxColour.getBackground(), min, max);
379
380     acg.setColourByLabel(colourFromLabel.getState());
381     maxColour.setEnabled(!colourFromLabel.getState());
382     minColour.setEnabled(!colourFromLabel.getState());
383     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
384     {
385       slider.setEnabled(false);
386       thresholdValue.setEnabled(false);
387       thresholdValue.setText("");
388     }
389
390     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
391     {
392       adjusting = true;
393       acg.setThreshold(threshline.value);
394
395       slider.setMinimum((int) (min * SCALE_FACTOR_1K));
396       slider.setMaximum((int) (max * SCALE_FACTOR_1K));
397       slider.setValue((int) (threshline.value * SCALE_FACTOR_1K));
398       thresholdValue.setText(threshline.value + "");
399       slider.setEnabled(true);
400       thresholdValue.setEnabled(true);
401       adjusting = false;
402     }
403
404     acg.setAboveThreshold(true);
405     if (thresholdIsMin.getState()
406             && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
407     {
408       if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD)
409       {
410         acg = new FeatureColour(acg, threshline.value, max);
411       }
412       else
413       {
414         acg = new FeatureColour(acg, min, threshline.value);
415       }
416     }
417
418     fr.setColour(type, acg);
419     cs = acg;
420     fs.selectionChanged();
421   }
422
423   void reset()
424   {
425     fr.setColour(type, oldcs);
426     fs.selectionChanged();
427   }
428
429   @Override
430   public void mouseClicked(MouseEvent evt)
431   {
432   }
433
434   @Override
435   public void mousePressed(MouseEvent evt)
436   {
437   }
438
439   @Override
440   public void mouseReleased(MouseEvent evt)
441   {
442     if (evt.getSource() == minColour || evt.getSource() == maxColour)
443     {
444       // relay the event
445       actionPerformed(new ActionEvent(evt.getSource(), 1, "Clicked"));
446     }
447     else
448     {
449       PaintRefresher.Refresh(this, fr.getViewport().getSequenceSetId());
450     }
451     // ap.paintAlignment(true);
452   }
453
454   @Override
455   public void mouseEntered(MouseEvent evt)
456   {
457   }
458
459   @Override
460   public void mouseExited(MouseEvent evt)
461   {
462   }
463
464 }