dialog box appears in centre of desktop window
[jalview.git] / src / jalview / gui / FeatureColourChooser.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Development Version 2.4.1)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
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.event.*;
27
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30 import java.awt.Dimension;
31
32 public class FeatureColourChooser extends JPanel 
33 {
34   JDialog frame;
35   
36
37 //  FeatureSettings fs;
38   FeatureRenderer fr;
39   
40   
41   private GraduatedColor cs;
42   private Object oldcs;
43   /**
44    * 
45    * @return the last colour setting selected by user - either oldcs (which may be a java.awt.Color) or the new GraduatedColor
46    */
47   public Object getLastColour() {
48     if (cs==null)
49     {
50       return oldcs;
51     }
52     return cs;
53   }
54   Hashtable oldgroupColours;
55   
56   AlignmentPanel ap;
57   
58
59   boolean adjusting = false;
60
61   private float min;
62
63   private float max;
64   String type = null;
65   public FeatureColourChooser(FeatureRenderer frender, String type)
66   {
67     this(frender,false,type);
68   }
69     public FeatureColourChooser(FeatureRenderer frender, boolean block, String type)
70     {
71     this.fr = frender;
72     this.type = type;
73     ap = fr.ap;
74     frame = new JDialog(Desktop.instance,true);
75     frame.setTitle("Graduated Feature Colour for "+type);
76     Rectangle deskr = Desktop.instance.getBounds();
77     frame.setBounds(new Rectangle((int) (deskr.getCenterX()-240),(int) (deskr.getCenterY()-92),480,185));
78     frame.setContentPane(this);
79     //frame.setLayer(JLayeredPane.PALETTE_LAYER);
80     //Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type, 480, 145);
81
82     slider.addChangeListener(new ChangeListener()
83     {
84       public void stateChanged(ChangeEvent evt)
85       {
86         if (!adjusting)
87         {
88           thresholdValue.setText(((float) slider.getValue() / 1000f) + "");
89           valueChanged();
90         }
91       }
92     });
93     slider.addMouseListener(new MouseAdapter()
94     {
95       public void mouseReleased(MouseEvent evt)
96       {
97         if (ap!=null) { ap.paintAlignment(true); };
98       }
99     });
100
101     float mm[] = ((float[][]) fr.minmax.get(type))[0];
102     min = mm[0];
103     max = mm[1];
104     oldcs = fr.featureColours.get(type);
105     if (oldcs instanceof GraduatedColor)
106     {
107       if (((GraduatedColor)oldcs).isAutoScale())
108       {
109         // update the scale
110         cs = new GraduatedColor((GraduatedColor) oldcs, min, max);
111       } else {
112         cs = new GraduatedColor((GraduatedColor) oldcs);
113       }
114     } else {
115       // promote original color to a graduated color
116       Color bl = Color.black;
117       if (oldcs instanceof Color)
118       {
119         bl = (Color) oldcs;
120       }
121       // original colour becomes the maximum colour
122       cs = new GraduatedColor(Color.white,bl,mm[0],mm[1]);
123       cs.setColourByLabel(false);
124     }
125     minColour.setBackground(oldminColour=cs.getMinColor());
126     maxColour.setBackground(oldmaxColour=cs.getMaxColor());
127     adjusting = true;
128     
129     try
130     {
131       jbInit();
132     } catch (Exception ex)
133     {
134     }
135     // update the gui from threshold state
136     thresholdIsMin.setSelected(!cs.isAutoScale());
137     colourByLabel.setSelected(cs.isColourByLabel());
138     if (cs.getThreshType()!=AnnotationColourGradient.NO_THRESHOLD)
139     {
140       // initialise threshold slider and selector
141       threshold.setSelectedIndex(cs.getThreshType()==AnnotationColourGradient.ABOVE_THRESHOLD ? 1 : 2);
142             slider.setEnabled(true);
143       thresholdValue.setEnabled(true);
144       threshline = new jalview.datamodel.GraphLine(
145                         (max - min) / 2f,
146                         "Threshold", Color.black);
147       
148     }
149
150     adjusting = false;
151
152     changeColour();
153     if (!block)
154     {
155       new Thread(new Runnable() {
156
157       public void run()
158       {
159         frame.show();
160       }
161       
162     }).start();
163     } else {
164       frame.show();
165     }
166   }
167
168   public FeatureColourChooser()
169   {
170     try
171     {
172       jbInit();
173     } catch (Exception ex)
174     {
175       ex.printStackTrace();
176     }
177   }
178
179   private void jbInit() throws Exception
180   {
181     
182     minColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
183     minColour.setBorder(BorderFactory.createEtchedBorder());
184     minColour.setPreferredSize(new Dimension(40, 20));
185     minColour.setToolTipText("Minimum Colour");
186     minColour.addMouseListener(new MouseAdapter()
187     {
188       public void mousePressed(MouseEvent e)
189       {
190         if (minColour.isEnabled())
191         {
192           minColour_actionPerformed();
193         }
194       }
195     });
196     maxColour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
197     maxColour.setBorder(BorderFactory.createEtchedBorder());
198     maxColour.setPreferredSize(new Dimension(40, 20));
199     maxColour.setToolTipText("Maximum Colour");
200     maxColour.addMouseListener(new MouseAdapter()
201     {
202       public void mousePressed(MouseEvent e)
203       {
204         if (maxColour.isEnabled())
205         {
206           maxColour_actionPerformed();
207         }
208       }
209     });
210     ok.setOpaque(false);
211     ok.setText("OK");
212     ok.addActionListener(new ActionListener()
213     {
214       public void actionPerformed(ActionEvent e)
215       {
216         ok_actionPerformed(e);
217       }
218     });
219     cancel.setOpaque(false);
220     cancel.setText("Cancel");
221     cancel.addActionListener(new ActionListener()
222     {
223       public void actionPerformed(ActionEvent e)
224       {
225         cancel_actionPerformed(e);
226       }
227     });
228     this.setLayout(borderLayout1);
229     jPanel2.setLayout(flowLayout1);
230     jPanel1.setBackground(Color.white);
231     jPanel2.setBackground(Color.white);
232     threshold.addActionListener(new ActionListener()
233     {
234       public void actionPerformed(ActionEvent e)
235       {
236         threshold_actionPerformed(e);
237       }
238     });
239     threshold.setToolTipText("Threshold the feature display by score.");
240     threshold.addItem("No Threshold"); // index 0
241     threshold.addItem("Above Threshold"); // index 1
242     threshold.addItem("Below Threshold"); // index 2
243     jPanel3.setLayout(flowLayout2);
244     thresholdValue.addActionListener(new ActionListener()
245     {
246       public void actionPerformed(ActionEvent e)
247       {
248         thresholdValue_actionPerformed(e);
249       }
250     });
251     slider.setPaintLabels(false);
252     slider.setPaintTicks(true);
253     slider.setBackground(Color.white);
254     slider.setEnabled(false);
255     slider.setOpaque(false);
256     slider.setPreferredSize(new Dimension(100, 32));
257     slider.setToolTipText("Adjust threshold");
258     thresholdValue.setEnabled(false);
259     thresholdValue.setColumns(7);
260     jPanel3.setBackground(Color.white);
261     thresholdIsMin.setBackground(Color.white);
262     thresholdIsMin.setText("Threshold is Min/Max");
263     thresholdIsMin.setToolTipText("Toggle between absolute and relative display threshold.");
264     thresholdIsMin.addActionListener(new ActionListener()
265     {
266       public void actionPerformed(ActionEvent actionEvent)
267       {
268         thresholdIsMin_actionPerformed(actionEvent);
269       }
270     });
271     colourByLabel.setBackground(Color.white);
272     colourByLabel.setText("Colour by Label");
273     colourByLabel.setToolTipText("Display features of the same type with a different label using a different colour. (e.g. domain features)");
274     colourByLabel.addActionListener(new ActionListener()
275     {
276       public void actionPerformed(ActionEvent actionEvent)
277       {
278         colourByLabel_actionPerformed(actionEvent);
279       }
280     });
281     jPanel1.add(ok);
282     jPanel1.add(cancel);
283     jPanel2.add(colourByLabel,java.awt.BorderLayout.WEST);
284     jPanel2.add(colourPanel,java.awt.BorderLayout.EAST);
285     colourPanel.add(minColour);
286     colourPanel.add(maxColour);
287     this.add(jPanel3, java.awt.BorderLayout.CENTER);
288     jPanel3.add(threshold);
289     jPanel3.add(slider);
290     jPanel3.add(thresholdValue);
291     jPanel3.add(thresholdIsMin);
292     this.add(jPanel1, java.awt.BorderLayout.SOUTH);
293     this.add(jPanel2, java.awt.BorderLayout.NORTH);
294   }
295
296
297   JPanel minColour = new JPanel();
298
299   JPanel maxColour = new JPanel();
300
301   JButton ok = new JButton();
302
303   JButton cancel = new JButton();
304   JPanel colourPanel = new JPanel();
305   JPanel jPanel1 = new JPanel();
306
307   JPanel jPanel2 = new JPanel();
308
309   BorderLayout borderLayout1 = new BorderLayout();
310
311   JComboBox threshold = new JComboBox();
312
313   FlowLayout flowLayout1 = new FlowLayout();
314
315   JPanel jPanel3 = new JPanel();
316
317   FlowLayout flowLayout2 = new FlowLayout();
318
319   JSlider slider = new JSlider();
320
321   JTextField thresholdValue = new JTextField(20);
322   // TODO implement GUI for tolower flag
323   // JCheckBox toLower = new JCheckBox();
324
325   JCheckBox thresholdIsMin = new JCheckBox();
326   JCheckBox colourByLabel = new JCheckBox();
327
328   private GraphLine threshline;
329
330
331   private Color oldmaxColour;
332
333
334   private Color oldminColour;
335
336   public void minColour_actionPerformed()
337   {
338     Color col = JColorChooser.showDialog(this,
339             "Select Colour for Minimum Value", minColour.getBackground());
340     if (col != null)
341     {
342       minColour.setBackground(col);
343     }
344     minColour.repaint();
345     changeColour();
346   }
347
348   public void maxColour_actionPerformed()
349   {
350     Color col = JColorChooser.showDialog(this,
351             "Select Colour for Maximum Value", maxColour.getBackground());
352     if (col != null)
353     {
354       maxColour.setBackground(col);
355     }
356     maxColour.repaint();
357     changeColour();
358   }
359
360   void changeColour()
361   {
362     // Check if combobox is still adjusting
363     if (adjusting)
364     {
365       return;
366     }
367
368
369     int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD;
370     if (threshold.getSelectedItem().equals("Above Threshold"))
371     {
372       aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD;
373     }
374     else if (threshold.getSelectedItem().equals("Below Threshold"))
375     {
376       aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD;
377     } 
378
379     slider.setEnabled(true);
380     thresholdValue.setEnabled(true);
381     
382     GraduatedColor acg;
383     if (cs.isColourByLabel())
384       {
385         acg = new GraduatedColor(oldminColour, oldmaxColour, min, max);
386       } else {
387         acg = new GraduatedColor(oldminColour=minColour.getBackground(), oldmaxColour=maxColour.getBackground(), min, max);
388         
389       }
390
391     if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD)
392     {
393       slider.setEnabled(false);
394       thresholdValue.setEnabled(false);
395       thresholdValue.setText("");
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(
402                       (max - min) / 2f,
403                       "Threshold", Color.black);
404     }
405
406     if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD)
407     {
408       adjusting = true;
409       acg.setThresh(threshline.value);
410
411       float range = max * 1000f
412               - min * 1000f;
413
414       slider.setMinimum((int) (min * 1000));
415       slider.setMaximum((int) (max * 1000));
416       slider.setValue((int) (threshline.value * 1000));
417       thresholdValue.setText(threshline.value + "");
418       slider.setMajorTickSpacing((int) (range / 10f));
419       slider.setEnabled(true);
420       thresholdValue.setEnabled(true);
421       adjusting = false;
422     }
423
424     acg.setThreshType(aboveThreshold);
425     if (thresholdIsMin.isSelected() && 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       } else { 
432         acg = new GraduatedColor(acg, min,threshline.value);
433       }
434     } else {
435       acg.setAutoScaled(true);
436     }
437     acg.setColourByLabel(colourByLabel.isSelected());
438     if (acg.isColourByLabel())
439     {
440       maxColour.setEnabled(false);
441       minColour.setEnabled(false);
442       maxColour.setBackground(this.getBackground());
443       minColour.setBackground(this.getBackground());
444     } else {
445       maxColour.setEnabled(true);
446       minColour.setEnabled(true);
447       maxColour.setBackground(oldmaxColour);
448       minColour.setBackground(oldminColour);
449     }
450     fr.featureColours.put(type,acg);
451     cs = acg;
452     ap.paintAlignment(false);
453   }
454   private void raiseClosed() {
455     if (this.colourEditor!=null)
456     {
457       colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
458     }
459   }
460   public void ok_actionPerformed(ActionEvent e)
461   {
462     changeColour();
463     try
464     {
465       frame.dispose();
466       raiseClosed();
467     } catch (Exception ex)
468     {
469     }
470   }
471
472   public void cancel_actionPerformed(ActionEvent e)
473   {
474     reset();
475     try
476     {
477       frame.dispose();
478 //      frame.setClosed(true);
479       raiseClosed();
480     } catch (Exception ex)
481     {
482     }
483   }
484
485   void reset()
486   {
487     fr.featureColours.put(type, oldcs);
488     ap.paintAlignment(false);
489     cs = null;
490   }
491
492   public void thresholdCheck_actionPerformed(ActionEvent e)
493   {
494     changeColour();
495   }
496
497   public void annotations_actionPerformed(ActionEvent e)
498   {
499     changeColour();
500   }
501
502   public void threshold_actionPerformed(ActionEvent e)
503   {
504     changeColour();
505   }
506
507   public void thresholdValue_actionPerformed(ActionEvent e)
508   {
509     try
510     {
511       float f = Float.parseFloat(thresholdValue.getText());
512       slider.setValue((int) (f * 1000));
513       threshline.value = f;
514     } catch (NumberFormatException ex)
515     {
516     }
517   }
518
519   public void valueChanged()
520   {
521     threshline.value = (float) slider.getValue() / 1000f;
522     cs.setThresh(threshline.value);
523     changeColour();
524     ap.paintAlignment(false);
525   }
526
527   public void thresholdIsMin_actionPerformed(ActionEvent actionEvent)
528   {
529     changeColour();
530   }
531   public void colourByLabel_actionPerformed(ActionEvent actionEvent)
532   {
533     changeColour();
534   }
535   ActionListener colourEditor=null;
536   public void addActionListener(ActionListener graduatedColorEditor)
537   {
538     if (colourEditor!=null)
539     {
540       System.err.println("IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
541     }
542     colourEditor = graduatedColorEditor;
543   }
544
545 }