JAL-4380 Added information to annotation tooltips when description is not present
[jalview.git] / src / jalview / datamodel / annotations / AnnotationColouringRanges.java
1 package jalview.datamodel.annotations;
2
3 import java.awt.Color;
4 import java.util.AbstractMap;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 public class AnnotationColouringRanges extends AnnotationColouring
12 {
13   private static List<Color> colours = new ArrayList<Color>();
14
15   private static List<Float> values = new ArrayList<Float>();
16
17   protected static void addValColour(float v, Color c)
18   {
19     values.add(v);
20     colours.add(c);
21   }
22
23   protected static void addFirstColour(Color c)
24   {
25     colours.add(0, c);
26   }
27
28   static
29   {
30     // e.g.
31     // addFirstColour(Color.black); -infty..25 = black
32     // addValColour(25,Color.darkGray); 25..50 = darkGray
33     // addValColour(50,Color.gray); 50..75 = gray
34     // addValColour(75,Color.lightGray); 75..100 = lightGray
35     // addValColour(100,Color.white); 100..infty = white
36   }
37
38   @Override
39   public Color valueToColour(float val)
40   {
41     Color col = null;
42     boolean set = false;
43     for (int i = 0; i < values.size(); i++)
44     {
45       float compareVal = values.get(i);
46       if (colours.size() > i)
47       {
48         col = colours.get(i);
49       }
50       if (val < compareVal)
51       {
52         set = true;
53         break;
54       }
55     }
56     if (!set && colours.size() > values.size())
57     {
58       col = colours.get(values.size());
59     }
60     return col;
61   }
62
63   @Override
64   public List<Map.Entry<Float, Color>> rangeColours(float val1, float val2)
65   {
66     String cacheKey = cacheKey(val1, val2);
67     if (!valColorsCache.containsKey(cacheKey))
68     {
69       List<Map.Entry<Float, Color>> valCols = new ArrayList<>();
70       float v1 = val1 <= val2 ? val1 : val2;
71       float v2 = val1 <= val2 ? val2 : val1;
72       boolean reversed = val1 > val2;
73       Color col = null;
74       boolean set1 = false;
75       boolean set2 = false;
76       int i = 0;
77       while (i < values.size() && (!set1 || !set2))
78       {
79         float compareVal = values.get(i);
80         if (colours.size() > i)
81         {
82           col = colours.get(i);
83         }
84
85         if (!set1 && v1 < compareVal)
86         {
87           // add the initial checkpoint
88           valCols.add(valCol(reversed ? 1f : 0f, col));
89           set1 = true;
90         }
91
92         if (!set2 && v2 < compareVal)
93         {
94           // add the final checkpoint
95           valCols.add(valCol(reversed ? 0f : 1f, col));
96           set2 = true;
97           break;
98         }
99
100         if (set1) // && !set2
101         {
102           // add an intermediate checkpoint
103           float v = (compareVal - v1) / (v2 - v1);
104           valCols.add(valCol(reversed ? 1f - v : v, col));
105         }
106
107         i++;
108       }
109       if (colours.size() > i)
110       {
111         col = colours.get(i);
112       }
113       // add above the final checkpoint colour(s) if not set
114       if (!set1)
115       {
116         valCols.add(valCol(reversed ? 1f : 0f, col));
117         set1 = true;
118       }
119       if (!set2)
120       {
121         // add the final checkpoint
122         valCols.add(valCol(reversed ? 0f : 1f, col));
123         set2 = true;
124       }
125       if (reversed)
126       {
127         Collections.reverse(valCols);
128       }
129       // put in the cache
130       valColorsCache.put(cacheKey, valCols);
131     }
132
133     return getFromCache(cacheKey);
134   }
135
136   private Map.Entry<Float, Color> valCol(Float v, Color c)
137   {
138     return new AbstractMap.SimpleEntry<Float, Color>(v, c);
139   }
140
141   private Map<String, List<Map.Entry<Float, Color>>> valColorsCache = new HashMap<String, List<Map.Entry<Float, Color>>>();
142
143   private List<Map.Entry<Float, Color>> getFromCache(String key)
144   {
145     // return a copy of the list in case of element order manipulation (e.g.
146     // valCols.remove(0))
147     return new ArrayList<Map.Entry<Float, Color>>(valColorsCache.get(key));
148   }
149
150   private static String cacheKey(float f1, float f2)
151   {
152     return new StringBuilder().append(Float.hashCode(f1)).append(' ')
153             .append(Float.hashCode(f2)).toString();
154   }
155 }