source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java@ 12082

Last change on this file since 12082 was 12082, checked in by bastiK, 7 years ago

minor fixes to ensure unmodifiable StyleElement classes

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.styleelement;
3
4import java.awt.Color;
5import java.awt.Font;
6import java.util.Objects;
7
8import org.openstreetmap.josm.data.osm.OsmPrimitive;
9import org.openstreetmap.josm.gui.mappaint.Cascade;
10import org.openstreetmap.josm.gui.mappaint.Environment;
11import org.openstreetmap.josm.gui.mappaint.Keyword;
12import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.TagKeyReference;
13import org.openstreetmap.josm.gui.mappaint.StyleKeys;
14import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy;
15import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.StaticLabelCompositionStrategy;
16import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.TagLookupCompositionStrategy;
17import org.openstreetmap.josm.gui.mappaint.styleelement.placement.CompletelyInsideAreaStrategy;
18import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy;
19import org.openstreetmap.josm.tools.CheckParameterUtil;
20import org.openstreetmap.josm.tools.Utils;
21
22/**
23 * Represents the rendering style for a textual label placed somewhere on the map.
24 * @since 3880
25 */
26public class TextLabel implements StyleKeys {
27 public static final LabelCompositionStrategy AUTO_LABEL_COMPOSITION_STRATEGY = new DeriveLabelFromNameTagsCompositionStrategy();
28
29 /**
30 * The strategy for building the actual label value for a given a {@link OsmPrimitive}.
31 * Check for null before accessing.
32 */
33 public LabelCompositionStrategy labelCompositionStrategy;
34 /**
35 * the font to be used when rendering
36 */
37 public Font font;
38 /**
39 * The x offset of the text.
40 */
41 public int xOffset;
42 /**
43 * The y offset of the text.
44 */
45 public int yOffset;
46 /**
47 * The color to draw the text in, includes alpha.
48 */
49 public Color color;
50 /**
51 * The radius of the halo effect.
52 */
53 public Float haloRadius;
54 /**
55 * The color of the halo effect.
56 */
57 public Color haloColor;
58
59 /**
60 * The position strategy for this text label.
61 */
62 private final PositionForAreaStrategy labelPositionStrategy;
63
64 /**
65 * Creates a new text element
66 *
67 * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered.
68 * If null, no label is rendered.
69 * @param font the font to be used. Must not be null.
70 * @param xOffset x offset
71 * @param yOffset y offset
72 * @param color the color to be used. Must not be null
73 * @param haloRadius halo radius
74 * @param haloColor halo color
75 * @deprecated since 11722, To be removed in mid-2017
76 */
77 @Deprecated
78 public TextLabel(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) {
79 this(strategy, font, xOffset, yOffset, color, haloRadius, haloColor, CompletelyInsideAreaStrategy.INSTANCE);
80 }
81
82 /**
83 * Creates a new text element
84 *
85 * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered.
86 * If null, no label is rendered.
87 * @param font the font to be used. Must not be null.
88 * @param xOffset x offset
89 * @param yOffset y offset
90 * @param color the color to be used. Must not be null
91 * @param haloRadius halo radius
92 * @param haloColor halo color
93 * @param labelPositionStrategy The position in the area.
94 */
95 protected TextLabel(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius,
96 Color haloColor, PositionForAreaStrategy labelPositionStrategy) {
97 this.labelCompositionStrategy = strategy;
98 this.font = Objects.requireNonNull(font, "font");
99 this.xOffset = xOffset;
100 this.yOffset = yOffset;
101 this.color = Objects.requireNonNull(color, "color");
102 this.haloRadius = haloRadius;
103 this.haloColor = haloColor;
104 this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy");
105 }
106
107 /**
108 * Copy constructor
109 *
110 * @param other the other element.
111 */
112 public TextLabel(TextLabel other) {
113 this.labelCompositionStrategy = other.labelCompositionStrategy;
114 this.font = other.font;
115 this.xOffset = other.xOffset;
116 this.yOffset = other.yOffset;
117 this.color = other.color;
118 this.haloColor = other.haloColor;
119 this.haloRadius = other.haloRadius;
120 this.labelPositionStrategy = other.labelPositionStrategy;
121 }
122
123 /**
124 * Copy constructor that changes the position strategy.
125 *
126 * @param other the other element.
127 * @param labelPositionStrategy the position
128 */
129 private TextLabel(TextLabel other, PositionForAreaStrategy labelPositionStrategy) {
130 this.labelCompositionStrategy = other.labelCompositionStrategy;
131 this.font = other.font;
132 this.xOffset = other.xOffset;
133 this.yOffset = other.yOffset;
134 this.color = other.color;
135 this.haloColor = other.haloColor;
136 this.haloRadius = other.haloRadius;
137 this.labelPositionStrategy = labelPositionStrategy;
138 }
139
140 /**
141 * Derives a suitable label composition strategy from the style properties in {@code c}.
142 *
143 * @param c the style properties
144 * @param defaultAnnotate whether to return {@link #AUTO_LABEL_COMPOSITION_STRATEGY} if not strategy is found
145 * @return the label composition strategy, or {@code null}
146 */
147 protected static LabelCompositionStrategy buildLabelCompositionStrategy(Cascade c, boolean defaultAnnotate) {
148 /*
149 * If the cascade includes a TagKeyReference we will lookup the rendered label
150 * from a tag value.
151 */
152 TagKeyReference tkr = c.get(TEXT, null, TagKeyReference.class, true);
153 if (tkr != null)
154 return new TagLookupCompositionStrategy(tkr.key);
155
156 /*
157 * Check whether the label composition strategy is given by a keyword
158 */
159 Keyword keyword = c.get(TEXT, null, Keyword.class, true);
160 if (Keyword.AUTO.equals(keyword))
161 return AUTO_LABEL_COMPOSITION_STRATEGY;
162
163 /*
164 * Do we have a static text label?
165 */
166 String text = c.get(TEXT, null, String.class, true);
167 if (text != null)
168 return new StaticLabelCompositionStrategy(text);
169 return defaultAnnotate ? AUTO_LABEL_COMPOSITION_STRATEGY : null;
170 }
171
172 /**
173 * Builds a text element from style properties in {@code c} and the
174 * default text color {@code defaultTextColor}
175 *
176 * @param env the environment
177 * @param defaultTextColor the default text color. Must not be null.
178 * @param defaultAnnotate true, if a text label shall be rendered by default, even if the style sheet
179 * doesn't include respective style declarations
180 * @return the text element or null, if the style properties don't include
181 * properties for text rendering
182 * @throws IllegalArgumentException if {@code defaultTextColor} is null
183 */
184 public static TextLabel create(Environment env, Color defaultTextColor, boolean defaultAnnotate) {
185 CheckParameterUtil.ensureParameterNotNull(defaultTextColor);
186 Cascade c = env.mc.getCascade(env.layer);
187
188 LabelCompositionStrategy strategy = buildLabelCompositionStrategy(c, defaultAnnotate);
189 if (strategy == null) return null;
190 String s = strategy.compose(env.osm);
191 if (s == null) return null;
192 Font font = StyleElement.getFont(c, s);
193
194 float xOffset = 0;
195 float yOffset = 0;
196 float[] offset = c.get(TEXT_OFFSET, null, float[].class);
197 if (offset != null) {
198 if (offset.length == 1) {
199 yOffset = offset[0];
200 } else if (offset.length >= 2) {
201 xOffset = offset[0];
202 yOffset = offset[1];
203 }
204 }
205 xOffset = c.get(TEXT_OFFSET_X, xOffset, Float.class);
206 yOffset = c.get(TEXT_OFFSET_Y, yOffset, Float.class);
207
208 Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class);
209 float alpha = c.get(TEXT_OPACITY, 1f, Float.class);
210 color = Utils.alphaMultiply(color, alpha);
211
212 Float haloRadius = c.get(TEXT_HALO_RADIUS, null, Float.class);
213 if (haloRadius != null && haloRadius <= 0) {
214 haloRadius = null;
215 }
216 Color haloColor = null;
217 if (haloRadius != null) {
218 haloColor = c.get(TEXT_HALO_COLOR, Utils.complement(color), Color.class);
219 float haloAlphaFactor = c.get(TEXT_HALO_OPACITY, 1f, Float.class);
220 haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor);
221 }
222
223 Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class);
224 PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword);
225
226 return new TextLabel(strategy, font, (int) xOffset, -(int) yOffset, color, haloRadius, haloColor, position);
227 }
228
229 /**
230 * Replies the label to be rendered for the primitive {@code osm}.
231 *
232 * @param osm the OSM object
233 * @return the label, or null, if {@code osm} is null or if no label can be
234 * derived for {@code osm}
235 */
236 public String getString(OsmPrimitive osm) {
237 if (labelCompositionStrategy == null) return null;
238 return labelCompositionStrategy.compose(osm);
239 }
240
241 /**
242 * Gets the strategy that defines where to place the label.
243 * @return The strategy. Never null.
244 * @since 11722
245 */
246 public PositionForAreaStrategy getLabelPositionStrategy() {
247 return labelPositionStrategy;
248 }
249
250 public TextLabel withPosition(PositionForAreaStrategy labelPositionStrategy) {
251 return new TextLabel(this, labelPositionStrategy);
252 }
253
254 @Override
255 public String toString() {
256 return "TextLabel{" + toStringImpl() + '}';
257 }
258
259 protected String toStringImpl() {
260 StringBuilder sb = new StringBuilder(96);
261 sb.append("labelCompositionStrategy=").append(labelCompositionStrategy)
262 .append(" font=").append(font);
263 if (xOffset != 0) {
264 sb.append(" xOffset=").append(xOffset);
265 }
266 if (yOffset != 0) {
267 sb.append(" yOffset=").append(yOffset);
268 }
269 sb.append(" color=").append(Utils.toString(color));
270 if (haloRadius != null) {
271 sb.append(" haloRadius=").append(haloRadius)
272 .append(" haloColor=").append(haloColor);
273 }
274 return sb.toString();
275 }
276
277 @Override
278 public int hashCode() {
279 return Objects.hash(labelCompositionStrategy, font, xOffset, yOffset, color, haloRadius, haloColor);
280 }
281
282 @Override
283 public boolean equals(Object obj) {
284 if (this == obj) return true;
285 if (obj == null || getClass() != obj.getClass()) return false;
286 TextLabel textLabel = (TextLabel) obj;
287 return xOffset == textLabel.xOffset &&
288 yOffset == textLabel.yOffset &&
289 Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) &&
290 Objects.equals(font, textLabel.font) &&
291 Objects.equals(color, textLabel.color) &&
292 Objects.equals(haloRadius, textLabel.haloRadius) &&
293 Objects.equals(haloColor, textLabel.haloColor);
294 }
295}
Note: See TracBrowser for help on using the repository browser.