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

Last change on this file since 5342 was 5342, checked in by Don-vip, 12 years ago

mappaint: fix "real width" painting, broken since r5212 because of a typo error on "real-width" key. Introduction of a StyleKeys interface centralizing key definitions at the same place to avoid same mistake in the future.

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