source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/StyleElement.java@ 13691

Last change on this file since 13691 was 13662, checked in by Don-vip, 6 years ago

use of IPrimitive interface

  • Property svn:eol-style set to native
File size: 9.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.styleelement;
3
4import java.awt.Font;
5import java.util.HashMap;
6import java.util.Map;
7import java.util.Objects;
8
9import org.openstreetmap.josm.data.osm.IPrimitive;
10import org.openstreetmap.josm.data.osm.OsmPrimitive;
11import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
12import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
13import org.openstreetmap.josm.gui.mappaint.Cascade;
14import org.openstreetmap.josm.gui.mappaint.Keyword;
15import org.openstreetmap.josm.gui.mappaint.StyleKeys;
16import org.openstreetmap.josm.gui.mappaint.mapcss.Instruction.RelativeFloat;
17import org.openstreetmap.josm.spi.preferences.Config;
18
19/**
20 * Class that defines how objects ({@link OsmPrimitive}) should be drawn on the map.
21 *
22 * Several subclasses of this abstract class implement different drawing features,
23 * like icons for a node or area fill. This class and all its subclasses are immutable
24 * and tend to get shared when multiple objects have the same style (in order to
25 * save memory, see {@link org.openstreetmap.josm.gui.mappaint.StyleCache#intern()}).
26 */
27public abstract class StyleElement implements StyleKeys {
28
29 protected static final int ICON_IMAGE_IDX = 0;
30 protected static final int ICON_WIDTH_IDX = 1;
31 protected static final int ICON_HEIGHT_IDX = 2;
32 protected static final int ICON_OPACITY_IDX = 3;
33 protected static final int ICON_OFFSET_X_IDX = 4;
34 protected static final int ICON_OFFSET_Y_IDX = 5;
35
36 /**
37 * The major z index of this style element
38 */
39 public float majorZIndex;
40 /**
41 * The z index as set by the user
42 */
43 public float zIndex;
44 /**
45 * The object z index
46 */
47 public float objectZIndex;
48 /**
49 * false, if style can serve as main style for the primitive;
50 * true, if it is a highlight or modifier
51 */
52 public boolean isModifier;
53 /**
54 * A flag indicating that the selection color handling should be done automatically
55 */
56 public boolean defaultSelectedHandling;
57
58 /**
59 * Construct a new StyleElement
60 * @param majorZindex like z-index, but higher priority
61 * @param zIndex order the objects are drawn
62 * @param objectZindex like z-index, but lower priority
63 * @param isModifier if false, a default line or node symbol is generated
64 * @param defaultSelectedHandling true if default behavior for selected objects
65 * is enabled, false if a style for selected state is given explicitly
66 */
67 public StyleElement(float majorZindex, float zIndex, float objectZindex, boolean isModifier, boolean defaultSelectedHandling) {
68 this.majorZIndex = majorZindex;
69 this.zIndex = zIndex;
70 this.objectZIndex = objectZindex;
71 this.isModifier = isModifier;
72 this.defaultSelectedHandling = defaultSelectedHandling;
73 }
74
75 protected StyleElement(Cascade c, float defaultMajorZindex) {
76 majorZIndex = c.get(MAJOR_Z_INDEX, defaultMajorZindex, Float.class);
77 zIndex = c.get(Z_INDEX, 0f, Float.class);
78 objectZIndex = c.get(OBJECT_Z_INDEX, 0f, Float.class);
79 isModifier = c.get(MODIFIER, Boolean.FALSE, Boolean.class);
80 defaultSelectedHandling = c.isDefaultSelectedHandling();
81 }
82
83 /**
84 * draws a primitive
85 * @param primitive primitive to draw
86 * @param paintSettings paint settings
87 * @param painter painter
88 * @param selected true, if primitive is selected
89 * @param outermember true, if primitive is not selected and outer member of a selected multipolygon relation
90 * @param member true, if primitive is not selected and member of a selected relation
91 * @since 13662 (signature)
92 */
93 public abstract void paintPrimitive(IPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
94 boolean selected, boolean outermember, boolean member);
95
96 /**
97 * Check if this is a style that makes the line visible to the user
98 * @return <code>true</code> for line styles
99 */
100 public boolean isProperLineStyle() {
101 return false;
102 }
103
104 /**
105 * Get a property value of type Width
106 * @param c the cascade
107 * @param key property key for the width value
108 * @param relativeTo reference width. Only needed, when relative width syntax is used, e.g. "+4".
109 * @return width
110 */
111 protected static Float getWidth(Cascade c, String key, Float relativeTo) {
112 Float width = c.get(key, null, Float.class, true);
113 if (width != null) {
114 if (width > 0)
115 return width;
116 } else {
117 Keyword widthKW = c.get(key, null, Keyword.class, true);
118 if (Keyword.THINNEST.equals(widthKW))
119 return 0f;
120 if (Keyword.DEFAULT.equals(widthKW))
121 return (float) MapPaintSettings.INSTANCE.getDefaultSegmentWidth();
122 if (relativeTo != null) {
123 RelativeFloat widthRel = c.get(key, null, RelativeFloat.class, true);
124 if (widthRel != null)
125 return relativeTo + widthRel.val;
126 }
127 }
128 return null;
129 }
130
131 /* ------------------------------------------------------------------------------- */
132 /* cached values */
133 /* ------------------------------------------------------------------------------- */
134 /*
135 * Two preference values and the set of created fonts are cached in order to avoid
136 * expensive lookups and to avoid too many font objects
137 *
138 * FIXME: cached preference values are not updated if the user changes them during
139 * a JOSM session. Should have a listener listening to preference changes.
140 */
141 private static volatile String defaultFontName;
142 private static volatile Float defaultFontSize;
143 private static final Object lock = new Object();
144
145 // thread save access (double-checked locking)
146 private static Float getDefaultFontSize() {
147 Float s = defaultFontSize;
148 if (s == null) {
149 synchronized (lock) {
150 s = defaultFontSize;
151 if (s == null) {
152 defaultFontSize = s = (float) Config.getPref().getInt("mappaint.fontsize", 8);
153 }
154 }
155 }
156 return s;
157 }
158
159 private static String getDefaultFontName() {
160 String n = defaultFontName;
161 if (n == null) {
162 synchronized (lock) {
163 n = defaultFontName;
164 if (n == null) {
165 defaultFontName = n = Config.getPref().get("mappaint.font", "Droid Sans");
166 }
167 }
168 }
169 return n;
170 }
171
172 private static class FontDescriptor {
173 public String name;
174 public int style;
175 public int size;
176
177 FontDescriptor(String name, int style, int size) {
178 this.name = name;
179 this.style = style;
180 this.size = size;
181 }
182
183 @Override
184 public int hashCode() {
185 return Objects.hash(name, style, size);
186 }
187
188 @Override
189 public boolean equals(Object obj) {
190 if (this == obj) return true;
191 if (obj == null || getClass() != obj.getClass()) return false;
192 FontDescriptor that = (FontDescriptor) obj;
193 return style == that.style &&
194 size == that.size &&
195 Objects.equals(name, that.name);
196 }
197 }
198
199 private static final Map<FontDescriptor, Font> FONT_MAP = new HashMap<>();
200
201 private static Font getCachedFont(FontDescriptor fd) {
202 Font f = FONT_MAP.get(fd);
203 if (f != null) return f;
204 f = new Font(fd.name, fd.style, fd.size);
205 FONT_MAP.put(fd, f);
206 return f;
207 }
208
209 private static Font getCachedFont(String name, int style, int size) {
210 return getCachedFont(new FontDescriptor(name, style, size));
211 }
212
213 protected static Font getFont(Cascade c, String s) {
214 String name = c.get(FONT_FAMILY, getDefaultFontName(), String.class);
215 float size = c.get(FONT_SIZE, getDefaultFontSize(), Float.class);
216 int weight = Font.PLAIN;
217 if ("bold".equalsIgnoreCase(c.get(FONT_WEIGHT, null, String.class))) {
218 weight = Font.BOLD;
219 }
220 int style = Font.PLAIN;
221 if ("italic".equalsIgnoreCase(c.get(FONT_STYLE, null, String.class))) {
222 style = Font.ITALIC;
223 }
224 Font f = getCachedFont(name, style | weight, Math.round(size));
225 if (f.canDisplayUpTo(s) == -1)
226 return f;
227 else {
228 // fallback if the string contains characters that cannot be
229 // rendered by the selected font
230 return getCachedFont("SansSerif", style | weight, Math.round(size));
231 }
232 }
233
234 @Override
235 public boolean equals(Object o) {
236 if (this == o) return true;
237 if (o == null || getClass() != o.getClass()) return false;
238 StyleElement that = (StyleElement) o;
239 return isModifier == that.isModifier &&
240 Float.compare(that.majorZIndex, majorZIndex) == 0 &&
241 Float.compare(that.zIndex, zIndex) == 0 &&
242 Float.compare(that.objectZIndex, objectZIndex) == 0;
243 }
244
245 @Override
246 public int hashCode() {
247 return Objects.hash(majorZIndex, zIndex, objectZIndex, isModifier);
248 }
249
250 @Override
251 public String toString() {
252 return String.format("z_idx=[%s/%s/%s] ", majorZIndex, zIndex, objectZIndex) + (isModifier ? "modifier " : "");
253 }
254}
Note: See TracBrowser for help on using the repository browser.