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

Last change on this file since 4319 was 4319, checked in by bastiK, 13 years ago

mappaint: split NodeElemStyle into icon/symbol part and text part

  • Property svn:eol-style set to native
File size: 15.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 javax.swing.GrayFilter;
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.tools.Pair;
22import org.openstreetmap.josm.tools.Utils;
23
24/**
25 * applies for Nodes and turn restriction relations
26 */
27public class NodeElemStyle extends ElemStyle {
28 public ImageIcon icon;
29 public int iconAlpha;
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 protected NodeElemStyle(Cascade c, ImageIcon icon, Integer iconAlpha, Symbol symbol) {
95 super(c, 1000f);
96 this.icon = icon;
97 this.iconAlpha = iconAlpha == null ? 0 : iconAlpha;
98 this.symbol = symbol;
99 }
100
101 public static NodeElemStyle create(Environment env) {
102 return create(env, false);
103 }
104
105 private static NodeElemStyle create(Environment env, boolean allowDefault) {
106 Cascade c = env.mc.getCascade(env.layer);
107
108 Pair<ImageIcon, Integer> icon = createIcon(env);
109 Symbol symbol = null;
110 if (icon == null) {
111 symbol = createSymbol(env);
112 }
113
114 // optimization: if we neither have a symbol, nor an icon
115 // we don't have to check for the remaining style properties and we don't
116 // have to allocate a node element style.
117 if (!allowDefault && symbol == null && icon == null) return null;
118
119 return new NodeElemStyle(c,
120 icon == null ? null : icon.a,
121 icon == null ? null : icon.b,
122 symbol);
123 }
124
125 private static Pair<ImageIcon, Integer> createIcon(Environment env) {
126 Cascade c = env.mc.getCascade(env.layer);
127 Cascade c_def = env.mc.getCascade("default");
128
129 IconReference iconRef = c.get("icon-image", null, IconReference.class);
130 if (iconRef == null)
131 return null;
132
133 Float widthOnDefault = c_def.get("icon-width", null, Float.class);
134 if (widthOnDefault != null && widthOnDefault <= 0) {
135 widthOnDefault = null;
136 }
137 Float widthF = getWidth(c, "icon-width", widthOnDefault);
138
139 Float heightOnDefault = c_def.get("icon-height", null, Float.class);
140 if (heightOnDefault != null && heightOnDefault <= 0) {
141 heightOnDefault = null;
142 }
143 Float heightF = getWidth(c, "icon-height", heightOnDefault);
144
145 int width = widthF == null ? -1 : Math.round(widthF);
146 int height = heightF == null ? -1 : Math.round(heightF);
147
148 ImageIcon icon = MapPaintStyles.getIcon(iconRef, width, height, false);
149 if (icon == null)
150 return new Pair<ImageIcon, Integer>(MapPaintStyles.getNoIcon_Icon(iconRef.source, false), 255);
151 int iconAlpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
152 Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
153 if (pAlpha != null) {
154 iconAlpha = pAlpha;
155 }
156
157 return new Pair<ImageIcon, Integer>(icon, iconAlpha);
158 }
159
160 private static Symbol createSymbol(Environment env) {
161 Cascade c = env.mc.getCascade(env.layer);
162 Cascade c_def = env.mc.getCascade("default");
163
164 SymbolShape shape;
165 Keyword shapeKW = c.get("symbol-shape", null, Keyword.class);
166 if (shapeKW == null)
167 return null;
168 if (equal(shapeKW.val, "square")) {
169 shape = SymbolShape.SQUARE;
170 } else if (equal(shapeKW.val, "circle")) {
171 shape = SymbolShape.CIRCLE;
172 } else if (equal(shapeKW.val, "triangle")) {
173 shape = SymbolShape.TRIANGLE;
174 } else if (equal(shapeKW.val, "pentagon")) {
175 shape = SymbolShape.PENTAGON;
176 } else if (equal(shapeKW.val, "hexagon")) {
177 shape = SymbolShape.HEXAGON;
178 } else if (equal(shapeKW.val, "heptagon")) {
179 shape = SymbolShape.HEPTAGON;
180 } else if (equal(shapeKW.val, "octagon")) {
181 shape = SymbolShape.OCTAGON;
182 } else if (equal(shapeKW.val, "nonagon")) {
183 shape = SymbolShape.NONAGON;
184 } else if (equal(shapeKW.val, "decagon")) {
185 shape = SymbolShape.DECAGON;
186 } else
187 return null;
188
189 Float sizeOnDefault = c_def.get("symbol-size", null, Float.class);
190 if (sizeOnDefault != null && sizeOnDefault <= 0) {
191 sizeOnDefault = null;
192 }
193 Float size = getWidth(c, "symbol-size", sizeOnDefault);
194
195 if (size == null) {
196 size = 10f;
197 }
198
199 if (size <= 0)
200 return null;
201
202 Float strokeWidthOnDefault = getWidth(c_def, "symbol-stroke-width", null);
203 Float strokeWidth = getWidth(c, "symbol-stroke-width", strokeWidthOnDefault);
204
205 Color strokeColor = c.get("symbol-stroke-color", null, Color.class);
206
207 if (strokeWidth == null && strokeColor != null) {
208 strokeWidth = 1f;
209 } else if (strokeWidth != null && strokeColor == null) {
210 strokeColor = Color.ORANGE;
211 }
212
213 Stroke stroke = null;
214 if (strokeColor != null) {
215 float strokeAlpha = c.get("symbol-stroke-opacity", 1f, Float.class);
216 strokeColor = new Color(strokeColor.getRed(), strokeColor.getGreen(),
217 strokeColor.getBlue(), Utils.color_float2int(strokeAlpha));
218 stroke = new BasicStroke(strokeWidth);
219 }
220
221 Color fillColor = c.get("symbol-fill-color", null, Color.class);
222 if (stroke == null && fillColor == null) {
223 fillColor = Color.BLUE;
224 }
225
226 if (fillColor != null) {
227 float fillAlpha = c.get("symbol-fill-opacity", 1f, Float.class);
228 fillColor = new Color(fillColor.getRed(), fillColor.getGreen(),
229 fillColor.getBlue(), Utils.color_float2int(fillAlpha));
230 }
231
232 return new Symbol(shape, Math.round(size), stroke, strokeColor, fillColor);
233 }
234
235 @Override
236 public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings settings, MapPainter painter, boolean selected, boolean member) {
237 if (primitive instanceof Node) {
238 Node n = (Node) primitive;
239 if (icon != null && painter.isShowIcons()) {
240 painter.drawNodeIcon(n, (painter.isInactiveMode() || n.isDisabled()) ? getDisabledIcon() : icon,
241 Utils.color_int2float(iconAlpha), selected, member);
242 } else if (symbol != null) {
243 Color fillColor = symbol.fillColor;
244 if (fillColor != null) {
245 if (n.isHighlighted()) {
246 fillColor = settings.getHighlightColor();
247 } else {
248 if (painter.isInactiveMode() || n.isDisabled()) {
249 fillColor = settings.getInactiveColor();
250 } else if (selected) {
251 fillColor = settings.getSelectedColor(fillColor.getAlpha());
252 } else if (member) {
253 fillColor = settings.getRelationSelectedColor(fillColor.getAlpha());
254 }
255 }
256 }
257 Color strokeColor = symbol.strokeColor;
258 if (strokeColor != null) {
259 if (n.isHighlighted()) {
260 strokeColor = settings.getHighlightColor();
261 } else {
262 if (painter.isInactiveMode() || n.isDisabled()) {
263 strokeColor = settings.getInactiveColor();
264 } else if (selected) {
265 strokeColor = settings.getSelectedColor(strokeColor.getAlpha());
266 } else if (member) {
267 strokeColor = settings.getRelationSelectedColor(strokeColor.getAlpha());
268 }
269 }
270 }
271 painter.drawNodeSymbol(n, symbol, fillColor, strokeColor);
272 } else {
273 if (n.isHighlighted()) {
274 painter.drawNode(n, settings.getHighlightColor(), settings.getSelectedNodeSize(), settings.isFillSelectedNode());
275 } else {
276 Color color;
277 boolean isConnection = n.isConnectionNode();
278
279 if (painter.isInactiveMode() || n.isDisabled()) {
280 color = settings.getInactiveColor();
281 } else if (selected) {
282 color = settings.getSelectedColor();
283 } else if (member) {
284 color = settings.getRelationSelectedColor();
285 } else if (isConnection) {
286 if (n.isTagged()) {
287 color = settings.getTaggedConnectionColor();
288 } else {
289 color = settings.getConnectionColor();
290 }
291 } else {
292 if (n.isTagged()) {
293 color = settings.getTaggedColor();
294 } else {
295 color = settings.getNodeColor();
296 }
297 }
298
299 final int size = Utils.max((selected ? settings.getSelectedNodeSize() : 0),
300 (n.isTagged() ? settings.getTaggedNodeSize() : 0),
301 (isConnection ? settings.getConnectionNodeSize() : 0),
302 settings.getUnselectedNodeSize());
303
304 final boolean fill = (selected && settings.isFillSelectedNode()) ||
305 (n.isTagged() && settings.isFillTaggedNode()) ||
306 (isConnection && settings.isFillConnectionNode()) ||
307 settings.isFillUnselectedNode();
308
309 painter.drawNode(n, color, size, fill);
310 }
311 }
312 } else if (primitive instanceof Relation && icon != null) {
313 painter.drawRestriction((Relation) primitive, this);
314 }
315 }
316
317 public ImageIcon getDisabledIcon() {
318 if (disabledIcon != null)
319 return disabledIcon;
320 if (icon == null)
321 return null;
322 return disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(icon.getImage()));
323 }
324
325 public Rectangle getBox() {
326 if (icon != null) {
327 int w = icon.getIconWidth(), h=icon.getIconHeight();
328 return new Rectangle(-w/2, -h/2, w, h);
329 } else if (symbol != null) {
330 return new Rectangle(-symbol.size/2, -symbol.size/2, symbol.size, symbol.size);
331 } else {
332 // This is only executed once, so no performance concerns.
333 // However, it would be better, if the settings could be changed at runtime.
334 int size = Utils.max(
335 Main.pref.getInteger("mappaint.node.selected-size", 5),
336 Main.pref.getInteger("mappaint.node.unselected-size", 3),
337 Main.pref.getInteger("mappaint.node.connection-size", 5),
338 Main.pref.getInteger("mappaint.node.tagged-size", 3)
339 );
340 return new Rectangle(-size/2, -size/2, size, size);
341 }
342 }
343
344 @Override
345 public int hashCode() {
346 int hash = super.hashCode();
347 hash = 17 * hash + (icon != null ? icon.getImage().hashCode() : 0);
348 hash = 17 * hash + iconAlpha;
349 hash = 17 * hash + (symbol != null ? symbol.hashCode() : 0);
350 return hash;
351 }
352
353 @Override
354 public boolean equals(Object obj) {
355 if (obj == null || getClass() != obj.getClass())
356 return false;
357 if (!super.equals(obj))
358 return false;
359
360 final NodeElemStyle other = (NodeElemStyle) obj;
361 // we should get the same image object due to caching
362 if (icon != other.icon && (icon == null || other.icon == null || icon.getImage() != other.icon.getImage()))
363 return false;
364 if (this.iconAlpha != other.iconAlpha)
365 return false;
366 if (!equal(symbol, other.symbol))
367 return false;
368 return true;
369 }
370
371
372 @Override
373 public String toString() {
374 StringBuilder s = new StringBuilder("NodeElemStyle{");
375 s.append(super.toString());
376 if (icon != null) {
377 s.append(" icon=" + icon + " iconAlpha=" + iconAlpha);
378 }
379 if (symbol != null) {
380 s.append(" symbol=[" + symbol + "]");
381 }
382 s.append('}');
383 return s.toString();
384 }
385}
Note: See TracBrowser for help on using the repository browser.