Merge branch 'JAL-3878_ws-overhaul-3' into with_ws_overhaul-3
[jalview.git] / src / jalview / gui / TextColourChooser.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.gui;
22
23 import java.awt.BorderLayout;
24 import java.awt.Color;
25 import java.awt.Dimension;
26 import java.awt.event.MouseAdapter;
27 import java.awt.event.MouseEvent;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 import javax.swing.BorderFactory;
32 import javax.swing.JLabel;
33 import javax.swing.JPanel;
34 import javax.swing.JSlider;
35 import javax.swing.event.ChangeEvent;
36 import javax.swing.event.ChangeListener;
37
38 import jalview.datamodel.SequenceGroup;
39 import jalview.gui.JalviewColourChooser.ColourChooserListener;
40 import jalview.util.MessageManager;
41
42 public class TextColourChooser
43 {
44   AlignmentPanel ap;
45
46   SequenceGroup sg;
47
48   Color original1, original2;
49
50   int originalThreshold;
51
52   Map<SequenceGroup, Color> groupColour1;
53
54   Map<SequenceGroup, Color> groupColour2;
55
56   Map<SequenceGroup, Integer> groupThreshold;
57
58   /**
59    * Show a dialogue which allows the user to select two text colours and adjust
60    * a slider for the cross-over point
61    * 
62    * @param alignPanel
63    *          the AlignmentPanel context
64    * @param sequenceGroup
65    *          the SequenceGroup context (only for group pop-menu option)
66    */
67   public void chooseColour(AlignmentPanel alignPanel,
68           SequenceGroup sequenceGroup)
69   {
70     this.ap = alignPanel;
71     this.sg = sequenceGroup;
72
73     saveInitialSettings();
74
75     final JSlider slider = new JSlider(0, 750, originalThreshold);
76     final JPanel col1 = new JPanel();
77     col1.setPreferredSize(new Dimension(40, 20));
78     col1.setBorder(BorderFactory.createEtchedBorder());
79     col1.setToolTipText(MessageManager.getString("label.dark_colour"));
80     col1.setBackground(original1);
81     final JPanel col2 = new JPanel();
82     col2.setPreferredSize(new Dimension(40, 20));
83     col2.setBorder(BorderFactory.createEtchedBorder());
84     col2.setToolTipText(MessageManager.getString("label.light_colour"));
85     col2.setBackground(original2);
86     final JPanel bigpanel = new JPanel(new BorderLayout());
87     JPanel panel = new JPanel(new BorderLayout());
88     bigpanel.add(panel, BorderLayout.CENTER);
89     bigpanel.add(
90             new JLabel("<html>"
91                     + MessageManager.getString(
92                             "label.select_dark_light_set_threshold")
93                     + "</html>"),
94             BorderLayout.NORTH);
95     panel.add(col1, BorderLayout.WEST);
96     panel.add(slider, BorderLayout.CENTER);
97     panel.add(col2, BorderLayout.EAST);
98
99     col1.addMouseListener(new MouseAdapter()
100     {
101       @Override
102       public void mousePressed(MouseEvent e)
103       {
104         String ttl = MessageManager
105                 .getString("label.select_colour_for_text");
106         ColourChooserListener listener = new ColourChooserListener()
107         {
108           @Override
109           public void colourSelected(Color c)
110           {
111             colour1Changed(c);
112             col1.setBackground(c);
113           }
114         };
115         JalviewColourChooser.showColourChooser(bigpanel, ttl,
116                 col1.getBackground(), listener);
117       }
118     });
119
120     col2.addMouseListener(new MouseAdapter()
121     {
122       @Override
123       public void mousePressed(MouseEvent e)
124       {
125         String ttl = MessageManager
126                 .getString("label.select_colour_for_text");
127         ColourChooserListener listener = new ColourChooserListener()
128         {
129           @Override
130           public void colourSelected(Color c)
131           {
132             colour2Changed(c);
133             col2.setBackground(c);
134           }
135         };
136         JalviewColourChooser.showColourChooser(bigpanel, ttl,
137                 col2.getBackground(), listener);
138       }
139     });
140
141     slider.addChangeListener(new ChangeListener()
142     {
143       @Override
144       public void stateChanged(ChangeEvent evt)
145       {
146         thresholdChanged(slider.getValue());
147       }
148     });
149
150     Object[] options = new Object[] { MessageManager.getString("action.ok"),
151         MessageManager.getString("action.cancel") };
152     String title = MessageManager
153             .getString("label.adjust_foreground_text_colour_threshold");
154     Runnable action = new Runnable() // response for 1 = Cancel
155     {
156       @Override
157       public void run()
158       {
159         restoreInitialSettings();
160       }
161     };
162     JvOptionPane.newOptionDialog(alignPanel.alignFrame)
163             .setResponseHandler(1, action).showInternalDialog(bigpanel,
164                     title, JvOptionPane.YES_NO_CANCEL_OPTION,
165                     JvOptionPane.PLAIN_MESSAGE, null, options,
166                     MessageManager.getString("action.ok"));
167   }
168
169   /**
170    * Restore initial settings on Cancel
171    */
172   protected void restoreInitialSettings()
173   {
174     if (sg == null)
175     {
176       ap.av.setTextColour(original1);
177       ap.av.setTextColour2(original2);
178       ap.av.setThresholdTextColour(originalThreshold);
179     }
180     else
181     {
182       sg.textColour = original1;
183       sg.textColour2 = original2;
184       sg.thresholdTextColour = originalThreshold;
185     }
186
187     /*
188      * if 'Apply To All Groups' was in force, there will be 
189      * group-specific settings to restore as well
190      */
191     for (SequenceGroup group : this.groupColour1.keySet())
192     {
193       group.textColour = groupColour1.get(group);
194       group.textColour2 = groupColour2.get(group);
195       group.thresholdTextColour = groupThreshold.get(group);
196     }
197
198     ap.paintAlignment(false, false);
199   }
200
201   /**
202    * Save settings on entry, for restore on Cancel
203    */
204   protected void saveInitialSettings()
205   {
206     groupColour1 = new HashMap<>();
207     groupColour2 = new HashMap<>();
208     groupThreshold = new HashMap<>();
209
210     if (sg == null)
211     {
212       /*
213        * alignment scope
214        */
215       original1 = ap.av.getTextColour();
216       original2 = ap.av.getTextColour2();
217       originalThreshold = ap.av.getThresholdTextColour();
218       if (ap.av.getColourAppliesToAllGroups()
219               && ap.av.getAlignment().getGroups() != null)
220       {
221         /*
222          * if applying changes to all groups, need to be able to 
223          * restore group settings as well
224          */
225         for (SequenceGroup group : ap.av.getAlignment().getGroups())
226         {
227           groupColour1.put(group, group.textColour);
228           groupColour2.put(group, group.textColour2);
229           groupThreshold.put(group, group.thresholdTextColour);
230         }
231       }
232     }
233     else
234     {
235       /*
236        * Sequence group scope
237        */
238       original1 = sg.textColour;
239       original2 = sg.textColour2;
240       originalThreshold = sg.thresholdTextColour;
241     }
242   }
243
244   void colour1Changed(Color col)
245   {
246     if (sg == null)
247     {
248       ap.av.setTextColour(col);
249       if (ap.av.getColourAppliesToAllGroups())
250       {
251         setGroupTextColour();
252       }
253     }
254     else
255     {
256       sg.textColour = col;
257     }
258
259     ap.paintAlignment(false, false);
260   }
261
262   void colour2Changed(Color col)
263   {
264     if (sg == null)
265     {
266       ap.av.setTextColour2(col);
267       if (ap.av.getColourAppliesToAllGroups())
268       {
269         setGroupTextColour();
270       }
271     }
272     else
273     {
274       sg.textColour2 = col;
275     }
276
277     ap.paintAlignment(false, false);
278   }
279
280   void thresholdChanged(int value)
281   {
282     if (sg == null)
283     {
284       ap.av.setThresholdTextColour(value);
285       if (ap.av.getColourAppliesToAllGroups())
286       {
287         setGroupTextColour();
288       }
289     }
290     else
291     {
292       sg.thresholdTextColour = value;
293     }
294
295     ap.paintAlignment(false, false);
296   }
297
298   void setGroupTextColour()
299   {
300     if (ap.av.getAlignment().getGroups() == null)
301     {
302       return;
303     }
304
305     for (SequenceGroup group : ap.av.getAlignment().getGroups())
306     {
307       group.textColour = ap.av.getTextColour();
308       group.textColour2 = ap.av.getTextColour2();
309       group.thresholdTextColour = ap.av.getThresholdTextColour();
310     }
311   }
312
313 }