source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java@ 4822

Last change on this file since 4822 was 4822, checked in by bastiK, 12 years ago

make identity of map icons depend on the name and not the image data (see #6797)

  • Property svn:eol-style set to native
File size: 14.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.openstreetmap.josm.tools.Utils.equal;
5
6import java.awt.BasicStroke;
7import java.awt.Color;
8import java.awt.Image;
9import java.awt.Rectangle;
10import java.awt.Stroke;
11
12import javax.swing.ImageIcon;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.data.osm.Node;
16import org.openstreetmap.josm.data.osm.OsmPrimitive;
17import org.openstreetmap.josm.data.osm.Relation;
18import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
19import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
20import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
21import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
22import org.openstreetmap.josm.tools.Pair;
23import org.openstreetmap.josm.tools.Utils;
24
25/**
26 * applies for Nodes and turn restriction relations
27 */
28public class NodeElemStyle extends ElemStyle {
29 public MapImage<Image> mapImage;
30 public Symbol symbol;
31
32 private ImageIcon disabledIcon;
33
34 public enum SymbolShape { SQUARE, CIRCLE, TRIANGLE, PENTAGON, HEXAGON, HEPTAGON, OCTAGON, NONAGON, DECAGON }
35
36 public static class Symbol {
37 public SymbolShape symbol;
38 public int size;
39 public Stroke stroke;
40 public Color strokeColor;
41 public Color fillColor;
42
43 public Symbol(SymbolShape symbol, int size, Stroke stroke, Color strokeColor, Color fillColor) {
44 if (stroke != null && strokeColor == null)
45 throw new IllegalArgumentException();
46 if (stroke == null && fillColor == null)
47 throw new IllegalArgumentException();
48 this.symbol = symbol;
49 this.size = size;
50 this.stroke = stroke;
51 this.strokeColor = strokeColor;
52 this.fillColor = fillColor;
53 }
54
55 @Override
56 public boolean equals(Object obj) {
57 if (obj == null || getClass() != obj.getClass())
58 return false;
59 final Symbol other = (Symbol) obj;
60 return symbol == other.symbol &&
61 size == other.size &&
62 equal(stroke, other.stroke) &&
63 equal(strokeColor, other.strokeColor) &&
64 equal(fillColor, other.fillColor);
65 }
66
67 @Override
68 public int hashCode() {
69 int hash = 7;
70 hash = 67 * hash + symbol.hashCode();
71 hash = 67 * hash + size;
72 hash = 67 * hash + (stroke != null ? stroke.hashCode() : 0);
73 hash = 67 * hash + (strokeColor != null ? strokeColor.hashCode() : 0);
74 hash = 67 * hash + (fillColor != null ? fillColor.hashCode() : 0);
75 return hash;
76 }
77
78 @Override
79 public String toString() {
80 return "symbol=" + symbol + " size=" + size +
81 (stroke != null ? (" stroke=" + stroke + " strokeColor=" + strokeColor) : "") +
82 (fillColor != null ? (" fillColor=" + fillColor) : "");
83 }
84 }
85
86 public static final NodeElemStyle SIMPLE_NODE_ELEMSTYLE;
87 static {
88 MultiCascade mc = new MultiCascade();
89 Cascade c = mc.getOrCreateCascade("default");
90 SIMPLE_NODE_ELEMSTYLE = create(new Environment(null, mc, "default", null), true);
91 if (SIMPLE_NODE_ELEMSTYLE == null) throw new AssertionError();
92 }
93
94 public static final StyleList DEFAULT_NODE_STYLELIST = new StyleList(NodeElemStyle.SIMPLE_NODE_ELEMSTYLE);
95 public static final StyleList DEFAULT_NODE_STYLELIST_TEXT = new StyleList(NodeElemStyle.SIMPLE_NODE_ELEMSTYLE, BoxTextElemStyle.SIMPLE_NODE_TEXT_ELEMSTYLE);
96
97 protected NodeElemStyle(Cascade c, MapImage<Image> mapImage, Symbol symbol) {
98 super(c, 1000f);
99 this.mapImage = mapImage;
100 this.symbol = symbol;
101 }
102
103 public static NodeElemStyle create(Environment env) {
104 return create(env, false);
105 }
106
107 private static NodeElemStyle create(Environment env, boolean allowDefault) {
108 Cascade c = env.mc.getCascade(env.layer);
109
110 MapImage<Image> mapImage = createIcon(env);
111 Symbol symbol = null;
112 if (mapImage == null) {
113 symbol = createSymbol(env);
114 }
115
116 // optimization: if we neither have a symbol, nor a mapImage
117 // we don't have to check for the remaining style properties and we don't
118 // have to allocate a node element style.
119 if (!allowDefault && symbol == null && mapImage == null) return null;
120
121 return new NodeElemStyle(c, mapImage, symbol);
122 }
123
124 private static MapImage<Image> createIcon(Environment env) {
125 Cascade c = env.mc.getCascade(env.layer);
126 Cascade c_def = env.mc.getCascade("default");
127
128 IconReference iconRef = c.get("icon-image", null, IconReference.class);
129 if (iconRef == null)
130 return null;
131
132 Float widthOnDefault = c_def.get("icon-width", null, Float.class);
133 if (widthOnDefault != null && widthOnDefault <= 0) {
134 widthOnDefault = null;
135 }
136 Float widthF = getWidth(c, "icon-width", widthOnDefault);
137
138 Float heightOnDefault = c_def.get("icon-height", null, Float.class);
139 if (heightOnDefault != null && heightOnDefault <= 0) {
140 heightOnDefault = null;
141 }
142 Float heightF = getWidth(c, "icon-height", heightOnDefault);
143
144 int width = widthF == null ? -1 : Math.round(widthF);
145 int height = heightF == null ? -1 : Math.round(heightF);
146
147 MapImage<Image> mapImage = new MapImage<Image>(iconRef.iconName, iconRef.source);
148
149 ImageIcon icon = MapPaintStyles.getIcon(iconRef, width, height);
150 if (icon == null) {
151 mapImage.img = MapPaintStyles.getNoIcon_Icon(iconRef.source).getImage();
152 } else {
153 mapImage.img = icon.getImage();
154 mapImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
155 Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
156 if (pAlpha != null) {
157 mapImage.alpha = pAlpha;
158 }
159 mapImage.width = width;
160 mapImage.height = height;
161 }
162 return mapImage;
163 }
164
165 private static Symbol createSymbol(Environment env) {
166 Cascade c = env.mc.getCascade(env.layer);
167 Cascade c_def = env.mc.getCascade("default");
168
169 SymbolShape shape;
170 Keyword shapeKW = c.get("symbol-shape", null, Keyword.class);
171 if (shapeKW == null)
172 return null;
173 if (equal(shapeKW.val, "square")) {
174 shape = SymbolShape.SQUARE;
175 } else if (equal(shapeKW.val, "circle")) {
176 shape = SymbolShape.CIRCLE;
177 } else if (equal(shapeKW.val, "triangle")) {
178 shape = SymbolShape.TRIANGLE;
179 } else if (equal(shapeKW.val, "pentagon")) {
180 shape = SymbolShape.PENTAGON;
181 } else if (equal(shapeKW.val, "hexagon")) {
182 shape = SymbolShape.HEXAGON;
183 } else if (equal(shapeKW.val, "heptagon")) {
184 shape = SymbolShape.HEPTAGON;
185 } else if (equal(shapeKW.val, "octagon")) {
186 shape = SymbolShape.OCTAGON;
187 } else if (equal(shapeKW.val, "nonagon")) {
188 shape = SymbolShape.NONAGON;
189 } else if (equal(shapeKW.val, "decagon")) {
190 shape = SymbolShape.DECAGON;
191 } else
192 return null;
193
194 Float sizeOnDefault = c_def.get("symbol-size", null, Float.class);
195 if (sizeOnDefault != null && sizeOnDefault <= 0) {
196 sizeOnDefault = null;
197 }
198 Float size = getWidth(c, "symbol-size", sizeOnDefault);
199
200 if (size == null) {
201 size = 10f;
202 }
203
204 if (size <= 0)
205 return null;
206
207 Float strokeWidthOnDefault = getWidth(c_def, "symbol-stroke-width", null);
208 Float strokeWidth = getWidth(c, "symbol-stroke-width", strokeWidthOnDefault);
209
210 Color strokeColor = c.get("symbol-stroke-color", null, Color.class);
211
212 if (strokeWidth == null && strokeColor != null) {
213 strokeWidth = 1f;
214 } else if (strokeWidth != null && strokeColor == null) {
215 strokeColor = Color.ORANGE;
216 }
217
218 Stroke stroke = null;
219 if (strokeColor != null) {
220 float strokeAlpha = c.get("symbol-stroke-opacity", 1f, Float.class);
221 strokeColor = new Color(strokeColor.getRed(), strokeColor.getGreen(),
222 strokeColor.getBlue(), Utils.color_float2int(strokeAlpha));
223 stroke = new BasicStroke(strokeWidth);
224 }
225
226 Color fillColor = c.get("symbol-fill-color", null, Color.class);
227 if (stroke == null && fillColor == null) {
228 fillColor = Color.BLUE;
229 }
230
231 if (fillColor != null) {
232 float fillAlpha = c.get("symbol-fill-opacity", 1f, Float.class);
233 fillColor = new Color(fillColor.getRed(), fillColor.getGreen(),
234 fillColor.getBlue(), Utils.color_float2int(fillAlpha));
235 }
236
237 return new Symbol(shape, Math.round(size), stroke, strokeColor, fillColor);
238 }
239
240 @Override
241 public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings settings, MapPainter painter, boolean selected, boolean member) {
242 if (primitive instanceof Node) {
243 Node n = (Node) primitive;
244 if (mapImage != null && painter.isShowIcons()) {
245 painter.drawNodeIcon(n, (painter.isInactiveMode() || n.isDisabled()) ? mapImage.getDisabled() : mapImage.img,
246 Utils.color_int2float(mapImage.alpha), selected, member);
247 } else if (symbol != null) {
248 Color fillColor = symbol.fillColor;
249 if (fillColor != null) {
250 if (painter.isInactiveMode() || n.isDisabled()) {
251 fillColor = settings.getInactiveColor();
252 } else if (selected) {
253 fillColor = settings.getSelectedColor(fillColor.getAlpha());
254 } else if (member) {
255 fillColor = settings.getRelationSelectedColor(fillColor.getAlpha());
256 }
257 }
258 Color strokeColor = symbol.strokeColor;
259 if (strokeColor != null) {
260 if (painter.isInactiveMode() || n.isDisabled()) {
261 strokeColor = settings.getInactiveColor();
262 } else if (selected) {
263 strokeColor = settings.getSelectedColor(strokeColor.getAlpha());
264 } else if (member) {
265 strokeColor = settings.getRelationSelectedColor(strokeColor.getAlpha());
266 }
267 }
268 painter.drawNodeSymbol(n, symbol, fillColor, strokeColor);
269 } else {
270 Color color;
271 boolean isConnection = n.isConnectionNode();
272
273 if (painter.isInactiveMode() || n.isDisabled()) {
274 color = settings.getInactiveColor();
275 } else if (selected) {
276 color = settings.getSelectedColor();
277 } else if (member) {
278 color = settings.getRelationSelectedColor();
279 } else if (isConnection) {
280 if (n.isTagged()) {
281 color = settings.getTaggedConnectionColor();
282 } else {
283 color = settings.getConnectionColor();
284 }
285 } else {
286 if (n.isTagged()) {
287 color = settings.getTaggedColor();
288 } else {
289 color = settings.getNodeColor();
290 }
291 }
292
293 final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0),
294 (n.isTagged() ? settings.getTaggedNodeSize() : 0),
295 (isConnection ? settings.getConnectionNodeSize() : 0),
296 settings.getUnselectedNodeSize());
297
298 final boolean fill = (selected && settings.isFillSelectedNode()) ||
299 (n.isTagged() && settings.isFillTaggedNode()) ||
300 (isConnection && settings.isFillConnectionNode()) ||
301 settings.isFillUnselectedNode();
302
303 painter.drawNode(n, color, size, fill);
304
305 }
306 } else if (primitive instanceof Relation && mapImage != null) {
307 painter.drawRestriction((Relation) primitive, mapImage);
308 }
309 }
310
311 public Rectangle getBox() {
312 if (mapImage != null) {
313 int w = mapImage.img.getWidth(null), h = mapImage.img.getHeight(null);
314 return new Rectangle(-w/2, -h/2, w, h);
315 } else if (symbol != null) {
316 return new Rectangle(-symbol.size/2, -symbol.size/2, symbol.size, symbol.size);
317 } else {
318 // This is only executed once, so no performance concerns.
319 // However, it would be better, if the settings could be changed at runtime.
320 int size = Utils.max(
321 Main.pref.getInteger("mappaint.node.selected-size", 5),
322 Main.pref.getInteger("mappaint.node.unselected-size", 3),
323 Main.pref.getInteger("mappaint.node.connection-size", 5),
324 Main.pref.getInteger("mappaint.node.tagged-size", 3)
325 );
326 return new Rectangle(-size/2, -size/2, size, size);
327 }
328 }
329
330 @Override
331 public int hashCode() {
332 int hash = super.hashCode();
333 hash = 17 * hash + (mapImage != null ? mapImage.hashCode() : 0);
334 hash = 17 * hash + (symbol != null ? symbol.hashCode() : 0);
335 return hash;
336 }
337
338 @Override
339 public boolean equals(Object obj) {
340 if (obj == null || getClass() != obj.getClass())
341 return false;
342 if (!super.equals(obj))
343 return false;
344
345 final NodeElemStyle other = (NodeElemStyle) obj;
346 // we should get the same image object due to caching
347 if (!equal(mapImage, other.mapImage))
348 return false;
349 if (!equal(symbol, other.symbol))
350 return false;
351 return true;
352 }
353
354 @Override
355 public String toString() {
356 StringBuilder s = new StringBuilder("NodeElemStyle{");
357 s.append(super.toString());
358 if (mapImage != null) {
359 s.append(" icon=[" + mapImage + "]");
360 }
361 if (symbol != null) {
362 s.append(" symbol=[" + symbol + "]");
363 }
364 s.append('}');
365 return s.toString();
366 }
367}
Note: See TracBrowser for help on using the repository browser.