JAL-3161 limit tooltip and status updates to visible columns
[jalview.git] / src / jalview / appletgui / UserDefinedColours.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.analysis.AAFrequency;
24 import jalview.api.FeatureColourI;
25 import jalview.datamodel.SequenceGroup;
26 import jalview.renderer.ResidueShader;
27 import jalview.schemes.Blosum62ColourScheme;
28 import jalview.schemes.ColourSchemeI;
29 import jalview.schemes.FeatureColour;
30 import jalview.schemes.PIDColourScheme;
31 import jalview.schemes.ResidueProperties;
32 import jalview.schemes.UserColourScheme;
33 import jalview.util.MessageManager;
34
35 import java.awt.Button;
36 import java.awt.Color;
37 import java.awt.Component;
38 import java.awt.Container;
39 import java.awt.Dialog;
40 import java.awt.Font;
41 import java.awt.Frame;
42 import java.awt.GridLayout;
43 import java.awt.Label;
44 import java.awt.Panel;
45 import java.awt.Rectangle;
46 import java.awt.Scrollbar;
47 import java.awt.TextField;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.AdjustmentEvent;
51 import java.awt.event.AdjustmentListener;
52 import java.awt.event.FocusEvent;
53 import java.awt.event.FocusListener;
54 import java.awt.event.MouseEvent;
55 import java.util.Vector;
56
57 public class UserDefinedColours extends Panel
58         implements ActionListener, AdjustmentListener, FocusListener
59 {
60
61   AlignmentPanel ap;
62
63   SequenceGroup seqGroup;
64
65   Button selectedButton;
66
67   Vector<Color> oldColours = new Vector<>();
68
69   ColourSchemeI oldColourScheme;
70
71   Frame frame;
72
73   MCview.AppletPDBCanvas pdbcanvas;
74
75   AppletJmol jmol;
76
77   Dialog dialog;
78
79   Object caller;
80
81   String originalLabel;
82
83   FeatureColourI originalColour;
84
85   int R = 0, G = 0, B = 0;
86
87   public ColourSchemeI loadDefaultColours()
88   {
89     // NOT IMPLEMENTED YET IN APPLET VERSION
90     return null;
91   }
92
93   public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
94   {
95     this.ap = ap;
96     seqGroup = sg;
97
98     if (seqGroup != null)
99     {
100       oldColourScheme = seqGroup.getColourScheme();
101     }
102     else
103     {
104       oldColourScheme = ap.av.getGlobalColourScheme();
105     }
106
107     init();
108   }
109
110   public UserDefinedColours(MCview.AppletPDBCanvas pdb)
111   {
112     this.pdbcanvas = pdb;
113     init();
114   }
115
116   public UserDefinedColours(AppletJmol jmol)
117   {
118     this.jmol = jmol;
119     init();
120   }
121
122   public UserDefinedColours(FeatureRenderer fr, Frame alignframe)
123   {
124     caller = fr;
125     originalColour = new FeatureColour(fr.colourPanel.getBackground());
126     originalLabel = "Feature Colour";
127     setForDialog("Select Feature Colour", alignframe);
128     setTargetColour(fr.colourPanel.getBackground());
129     dialog.setVisible(true);
130   }
131
132   public UserDefinedColours(Component caller, Color col1, Frame alignframe)
133   {
134     this(caller, col1, alignframe, "Select Colour");
135   }
136
137   /**
138    * Makes a dialog to choose the colour
139    * 
140    * @param caller
141    *          - handles events
142    * @param col
143    *          - original colour
144    * @param alignframe
145    *          - the parent Frame for the dialog
146    * @param title
147    *          - window title
148    */
149   public UserDefinedColours(Component caller, Color col, Frame alignframe,
150           String title)
151   {
152     this.caller = caller;
153     originalColour = new FeatureColour(col);
154     originalLabel = title;
155     setForDialog(title, alignframe);
156     setTargetColour(col);
157     dialog.setVisible(true);
158   }
159
160   /**
161    * feature colour chooser
162    * 
163    * @param caller
164    * @param label
165    * @param colour
166    */
167   public UserDefinedColours(Object caller, String label, Color colour)
168   {
169     this(caller, label, new FeatureColour(colour), colour);
170   }
171
172   /**
173    * feature colour chooser when changing style to single color
174    * 
175    * @param me
176    * @param type
177    * @param graduatedColor
178    */
179   public UserDefinedColours(FeatureSettings me, String type,
180           FeatureColourI graduatedColor)
181   {
182     this(me, type, graduatedColor, graduatedColor.getMaxColour());
183   }
184
185   private UserDefinedColours(Object caller, String label,
186           FeatureColourI ocolour, Color colour)
187   {
188     this.caller = caller;
189     originalColour = ocolour;
190     originalLabel = label;
191     init();
192     remove(buttonPanel);
193
194     setTargetColour(colour);
195
196     okcancelPanel.setBounds(new Rectangle(0, 113, 400, 35));
197     frame.setTitle(MessageManager.getString("label.user_defined_colours")
198             + " - " + label);
199     frame.setSize(420, 200);
200   }
201
202   void setForDialog(String title, Container alignframe)
203   {
204     init();
205     frame.setVisible(false);
206     remove(buttonPanel);
207     if (alignframe instanceof Frame)
208     {
209       dialog = new Dialog((Frame) alignframe, title, true);
210     }
211     else
212     {
213       // if (alignframe instanceof JVDialog){
214       // // not 1.1 compatible!
215       // dialog = new Dialog(((JVDialog)alignframe), title, true);
216       // } else {
217       throw new Error(MessageManager.getString(
218               "label.error_unsupported_owwner_user_colour_scheme"));
219     }
220
221     dialog.add(this);
222     this.setSize(400, 123);
223     okcancelPanel.setBounds(new Rectangle(0, 123, 400, 35));
224     int height = 160 + alignframe.getInsets().top + getInsets().bottom;
225     int width = 400;
226
227     dialog.setBounds(
228             alignframe.getBounds().x
229                     + (alignframe.getSize().width - width) / 2,
230             alignframe.getBounds().y
231                     + (alignframe.getSize().height - height) / 2,
232             width, height);
233
234   }
235
236   @Override
237   public void actionPerformed(ActionEvent evt)
238   {
239     final Object source = evt.getSource();
240     if (source == okButton)
241     {
242       okButton_actionPerformed();
243     }
244     else if (source == applyButton)
245     {
246       applyButton_actionPerformed();
247     }
248     else if (source == cancelButton)
249     {
250       cancelButton_actionPerformed();
251     }
252     else if (source == rText)
253     {
254       rText_actionPerformed();
255     }
256     else if (source == gText)
257     {
258       gText_actionPerformed();
259     }
260     else if (source == bText)
261     {
262       bText_actionPerformed();
263     }
264   }
265
266   @Override
267   public void adjustmentValueChanged(AdjustmentEvent evt)
268   {
269     if (evt.getSource() == rScroller)
270     {
271       rScroller_adjustmentValueChanged();
272     }
273     else if (evt.getSource() == gScroller)
274     {
275       gScroller_adjustmentValueChanged();
276     }
277     else if (evt.getSource() == bScroller)
278     {
279       bScroller_adjustmentValueChanged();
280     }
281   }
282
283   void init()
284   {
285     try
286     {
287       jbInit();
288     } catch (Exception e)
289     {
290       e.printStackTrace();
291     }
292     frame = new Frame();
293     frame.add(this);
294     jalview.bin.JalviewLite.addFrame(frame,
295             MessageManager.getString("label.user_defined_colours"), 420,
296             345);
297
298     if (seqGroup != null)
299     {
300       frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
301     }
302
303     for (int i = 0; i < 20; i++)
304     {
305       makeButton(ResidueProperties.aa2Triplet.get(ResidueProperties.aa[i])
306               + "", ResidueProperties.aa[i]);
307     }
308
309     makeButton("B", "B");
310     makeButton("Z", "Z");
311     makeButton("X", "X");
312     makeButton("Gap", "'.','-',' '");
313
314     validate();
315   }
316
317   protected void rText_actionPerformed()
318   {
319     try
320     {
321       int i = Integer.parseInt(rText.getText());
322       rScroller.setValue(i);
323       rScroller_adjustmentValueChanged();
324     } catch (NumberFormatException ex)
325     {
326     }
327   }
328
329   protected void gText_actionPerformed()
330   {
331     try
332     {
333       int i = Integer.parseInt(gText.getText());
334       gScroller.setValue(i);
335       gScroller_adjustmentValueChanged();
336     } catch (NumberFormatException ex)
337     {
338     }
339
340   }
341
342   protected void bText_actionPerformed()
343   {
344     try
345     {
346       int i = Integer.parseInt(bText.getText());
347       bScroller.setValue(i);
348       bScroller_adjustmentValueChanged();
349     } catch (NumberFormatException ex)
350     {
351     }
352
353   }
354
355   protected void rScroller_adjustmentValueChanged()
356   {
357     R = rScroller.getValue();
358     rText.setText(R + "");
359     colourChanged();
360   }
361
362   protected void gScroller_adjustmentValueChanged()
363   {
364     G = gScroller.getValue();
365     gText.setText(G + "");
366     colourChanged();
367   }
368
369   protected void bScroller_adjustmentValueChanged()
370   {
371     B = bScroller.getValue();
372     bText.setText(B + "");
373     colourChanged();
374   }
375
376   public void colourChanged()
377   {
378     Color col = new Color(R, G, B);
379     target.setBackground(col);
380     target.repaint();
381
382     if (selectedButton != null)
383     {
384       selectedButton.setBackground(col);
385       selectedButton.repaint();
386     }
387   }
388
389   void setTargetColour(Color col)
390   {
391     R = col.getRed();
392     G = col.getGreen();
393     B = col.getBlue();
394
395     rScroller.setValue(R);
396     gScroller.setValue(G);
397     bScroller.setValue(B);
398     rText.setText(R + "");
399     gText.setText(G + "");
400     bText.setText(B + "");
401     colourChanged();
402   }
403
404   public void colourButtonPressed(MouseEvent e)
405   {
406     selectedButton = (Button) e.getSource();
407     setTargetColour(selectedButton.getBackground());
408   }
409
410   void makeButton(String label, String aa)
411   {
412     final Button button = new Button();
413     Color col = Color.white;
414     if (oldColourScheme != null && oldColourScheme.isSimple())
415     {
416       col = oldColourScheme.findColour(aa.charAt(0), 0, null, null, 0f);
417     }
418     button.setBackground(col);
419     oldColours.addElement(col);
420     button.setLabel(label);
421     button.setForeground(col.darker().darker().darker());
422     button.setFont(new java.awt.Font("Verdana", 1, 10));
423     button.addMouseListener(new java.awt.event.MouseAdapter()
424     {
425       @Override
426       public void mousePressed(MouseEvent e)
427       {
428         colourButtonPressed(e);
429       }
430     });
431
432     buttonPanel.add(button, null);
433   }
434
435   protected void okButton_actionPerformed()
436   {
437     applyButton_actionPerformed();
438     if (dialog != null)
439     {
440       dialog.setVisible(false);
441     }
442
443     frame.setVisible(false);
444   }
445
446   public Color getColor()
447   {
448     return new Color(R, G, B);
449   }
450
451   protected void applyButton_actionPerformed()
452   {
453     if (caller != null)
454     {
455       if (caller instanceof FeatureSettings)
456       {
457         ((FeatureSettings) caller).setUserColour(originalLabel,
458                 new FeatureColour(getColor()));
459       }
460       else if (caller instanceof AnnotationColourChooser)
461       {
462         if (originalLabel.equals("Min Colour"))
463         {
464           ((AnnotationColourChooser) caller)
465                   .minColour_actionPerformed(getColor());
466         }
467         else
468         {
469           ((AnnotationColourChooser) caller)
470                   .maxColour_actionPerformed(getColor());
471         }
472       }
473       else if (caller instanceof FeatureRenderer)
474       {
475         ((FeatureRenderer) caller).colourPanel
476                 .updateColor(new FeatureColour(getColor()));
477       }
478       else if (caller instanceof FeatureColourChooser)
479       {
480         if (originalLabel.indexOf("inimum") > -1)
481         {
482           ((FeatureColourChooser) caller)
483                   .minColour_actionPerformed(getColor());
484         }
485         else
486         {
487           ((FeatureColourChooser) caller)
488                   .maxColour_actionPerformed(getColor());
489         }
490       }
491
492       return;
493     }
494
495     Color[] newColours = new Color[24];
496     for (int i = 0; i < 24; i++)
497     {
498       Button button = (Button) buttonPanel.getComponent(i);
499       newColours[i] = button.getBackground();
500     }
501
502     UserColourScheme ucs = new UserColourScheme(newColours);
503     // if (ap != null)
504     // {
505     // ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
506     // }
507
508     if (ap != null)
509     {
510       if (seqGroup != null)
511       {
512         seqGroup.cs = new ResidueShader(ucs);
513         seqGroup.getGroupColourScheme().setThreshold(0,
514                 ap.av.isIgnoreGapsConsensus());
515       }
516       else
517       {
518         ap.av.setGlobalColourScheme(ucs);
519         ap.av.getResidueShading().setThreshold(0,
520                 ap.av.isIgnoreGapsConsensus());
521       }
522       ap.seqPanel.seqCanvas.img = null;
523       ap.paintAlignment(true, true);
524     }
525     else if (jmol != null)
526     {
527       jmol.setJalviewColourScheme(ucs);
528     }
529     else if (pdbcanvas != null)
530     {
531       pdbcanvas.setColours(ucs);
532     }
533   }
534
535   protected void cancelButton_actionPerformed()
536   {
537     if (caller != null)
538     {
539       if (caller instanceof FeatureSettings)
540       {
541         ((FeatureSettings) caller).setUserColour(originalLabel,
542                 originalColour);
543       }
544       else if (caller instanceof AnnotationColourChooser)
545       {
546         if (originalLabel.equals("Min Colour"))
547         {
548           ((AnnotationColourChooser) caller)
549                   .minColour_actionPerformed(originalColour.getColour());
550         }
551         else
552         {
553           ((AnnotationColourChooser) caller)
554                   .maxColour_actionPerformed(originalColour.getColour());
555         }
556       }
557       else if (caller instanceof FeatureRenderer)
558       {
559         ((FeatureRenderer) caller).colourPanel.updateColor(originalColour);
560
561       }
562
563       else if (caller instanceof FeatureColourChooser)
564       {
565         if (originalLabel.indexOf("inimum") > -1)
566         {
567           ((FeatureColourChooser) caller)
568                   .minColour_actionPerformed(originalColour.getColour());
569         }
570         else
571         {
572           ((FeatureColourChooser) caller)
573                   .maxColour_actionPerformed(originalColour.getColour());
574         }
575       }
576       if (dialog != null)
577       {
578         dialog.setVisible(false);
579       }
580
581       frame.setVisible(false);
582       return;
583     }
584
585     if (ap != null)
586     {
587       if (seqGroup != null)
588       {
589         seqGroup.cs = new ResidueShader(oldColourScheme);
590         if (oldColourScheme instanceof PIDColourScheme
591                 || oldColourScheme instanceof Blosum62ColourScheme)
592         {
593           seqGroup.cs.setConsensus(AAFrequency.calculate(
594                   seqGroup.getSequences(ap.av.getHiddenRepSequences()), 0,
595                   ap.av.getAlignment().getWidth()));
596         }
597       }
598       else
599       {
600         ap.av.setGlobalColourScheme(oldColourScheme);
601       }
602       ap.paintAlignment(true, true);
603     }
604
605     frame.setVisible(false);
606   }
607
608   protected Panel buttonPanel = new Panel();
609
610   protected GridLayout gridLayout = new GridLayout();
611
612   Panel okcancelPanel = new Panel();
613
614   protected Button okButton = new Button();
615
616   protected Button applyButton = new Button();
617
618   protected Button cancelButton = new Button();
619
620   protected Scrollbar rScroller = new Scrollbar();
621
622   Label label1 = new Label();
623
624   protected TextField rText = new TextField();
625
626   Label label4 = new Label();
627
628   protected Scrollbar gScroller = new Scrollbar();
629
630   protected TextField gText = new TextField();
631
632   Label label5 = new Label();
633
634   protected Scrollbar bScroller = new Scrollbar();
635
636   protected TextField bText = new TextField();
637
638   protected Panel target = new Panel();
639
640   private void jbInit() throws Exception
641   {
642     this.setLayout(null);
643     buttonPanel.setLayout(gridLayout);
644     gridLayout.setColumns(6);
645     gridLayout.setRows(4);
646     okButton.setFont(new java.awt.Font("Verdana", 0, 11));
647     okButton.setLabel(MessageManager.getString("action.ok"));
648     okButton.addActionListener(this);
649     applyButton.setFont(new java.awt.Font("Verdana", 0, 11));
650     applyButton.setLabel(MessageManager.getString("action.apply"));
651     applyButton.addActionListener(this);
652     cancelButton.setFont(new java.awt.Font("Verdana", 0, 11));
653     cancelButton.setLabel(MessageManager.getString("action.cancel"));
654     cancelButton.addActionListener(this);
655     this.setBackground(new Color(212, 208, 223));
656     okcancelPanel.setBounds(new Rectangle(0, 265, 400, 35));
657     buttonPanel.setBounds(new Rectangle(0, 123, 400, 142));
658     rScroller.setMaximum(256);
659     rScroller.setMinimum(0);
660     rScroller.setOrientation(0);
661     rScroller.setUnitIncrement(1);
662     rScroller.setVisibleAmount(1);
663     rScroller.setBounds(new Rectangle(36, 27, 119, 19));
664     rScroller.addAdjustmentListener(this);
665     label1.setAlignment(Label.RIGHT);
666     label1.setText("R");
667     label1.setBounds(new Rectangle(19, 30, 16, 15));
668     rText.setFont(new java.awt.Font("Dialog", Font.PLAIN, 10));
669     rText.setText("0        ");
670     rText.setBounds(new Rectangle(156, 27, 53, 19));
671     rText.addActionListener(this);
672     rText.addFocusListener(this);
673     label4.setAlignment(Label.RIGHT);
674     label4.setText("G");
675     label4.setBounds(new Rectangle(15, 56, 20, 15));
676     gScroller.setMaximum(256);
677     gScroller.setMinimum(0);
678     gScroller.setOrientation(0);
679     gScroller.setUnitIncrement(1);
680     gScroller.setVisibleAmount(1);
681     gScroller.setBounds(new Rectangle(35, 52, 120, 20));
682     gScroller.addAdjustmentListener(this);
683     gText.setFont(new java.awt.Font("Dialog", Font.PLAIN, 10));
684     gText.setText("0        ");
685     gText.setBounds(new Rectangle(156, 52, 53, 20));
686     gText.addActionListener(this);
687     gText.addFocusListener(this);
688     label5.setAlignment(Label.RIGHT);
689     label5.setText("B");
690     label5.setBounds(new Rectangle(14, 82, 20, 15));
691     bScroller.setMaximum(256);
692     bScroller.setMinimum(0);
693     bScroller.setOrientation(0);
694     bScroller.setUnitIncrement(1);
695     bScroller.setVisibleAmount(1);
696     bScroller.setBounds(new Rectangle(35, 78, 120, 20));
697     bScroller.addAdjustmentListener(this);
698     bText.setFont(new java.awt.Font("Dialog", Font.PLAIN, 10));
699     bText.setText("0        ");
700     bText.setBounds(new Rectangle(157, 78, 52, 20));
701     bText.addActionListener(this);
702     bText.addFocusListener(this);
703     target.setBackground(Color.black);
704     target.setBounds(new Rectangle(229, 26, 134, 79));
705     this.add(okcancelPanel, null);
706     okcancelPanel.add(okButton, null);
707     okcancelPanel.add(applyButton, null);
708     okcancelPanel.add(cancelButton, null);
709     this.add(rText);
710     this.add(gText);
711     this.add(bText);
712     this.add(buttonPanel, null);
713     this.add(target, null);
714     this.add(gScroller);
715     this.add(rScroller);
716     this.add(bScroller);
717     this.add(label5);
718     this.add(label4);
719     this.add(label1);
720   }
721
722   @Override
723   public void focusGained(FocusEvent e)
724   {
725     // noop
726   }
727
728   /**
729    * This method applies any change to an RGB value if the user tabs out of the
730    * field instead of pressing Enter
731    */
732   @Override
733   public void focusLost(FocusEvent e)
734   {
735     Component c = e.getComponent();
736     if (c == rText)
737     {
738       rText_actionPerformed();
739     }
740     else
741     {
742       if (c == gText)
743       {
744         gText_actionPerformed();
745       }
746       else
747       {
748         if (c == bText)
749         {
750           bText_actionPerformed();
751         }
752       }
753     }
754   }
755
756 }