source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/BoxTextElemStyle.java@ 7530

Last change on this file since 7530 was 7383, checked in by bastiK, 10 years ago

applied #10301 - extend display of maxspeed nodes (patch by Klumbumbus)
Include Droid Sans font in the JOSM binary distribution.
This unifies the font rendering on different platforms and allows geometric constructions with text (as demonstrated for maxspeed). Both regular and bold style are available.

  • Property svn:eol-style set to native
File size: 8.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Color;
5import java.awt.Rectangle;
6
7import org.openstreetmap.josm.data.osm.Node;
8import org.openstreetmap.josm.data.osm.OsmPrimitive;
9import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
10import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
11import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
12import org.openstreetmap.josm.tools.CheckParameterUtil;
13
14/**
15 * Text style attached to a style with a bounding box, like an icon or a symbol.
16 */
17public class BoxTextElemStyle extends ElemStyle {
18
19 public enum HorizontalTextAlignment { LEFT, CENTER, RIGHT }
20 public enum VerticalTextAlignment { ABOVE, TOP, CENTER, BOTTOM, BELOW }
21
22 public static interface BoxProvider {
23 BoxProviderResult get();
24 }
25
26 public static class BoxProviderResult {
27 private Rectangle box;
28 private boolean temporary;
29
30 public BoxProviderResult(Rectangle box, boolean temporary) {
31 this.box = box;
32 this.temporary = temporary;
33 }
34
35 /**
36 * The box
37 */
38 public Rectangle getBox() {
39 return box;
40 }
41
42 /**
43 * True, if the box can change in future calls of the BoxProvider get() method
44 */
45 public boolean isTemporary() {
46 return temporary;
47 }
48 }
49
50 public static class SimpleBoxProvider implements BoxProvider {
51 private Rectangle box;
52
53 public SimpleBoxProvider(Rectangle box) {
54 this.box = box;
55 }
56
57 @Override
58 public BoxProviderResult get() {
59 return new BoxProviderResult(box, false);
60 }
61
62 @Override
63 public int hashCode() {
64 return box.hashCode();
65 }
66
67 @Override
68 public boolean equals(Object obj) {
69 if (!(obj instanceof BoxProvider))
70 return false;
71 final BoxProvider other = (BoxProvider) obj;
72 BoxProviderResult resultOther = other.get();
73 if (resultOther.isTemporary()) return false;
74 return box.equals(resultOther.getBox());
75 }
76 }
77
78 public static final Rectangle ZERO_BOX = new Rectangle(0, 0, 0, 0);
79
80 public TextElement text;
81 // Either boxProvider or box is not null. If boxProvider is different from
82 // null, this means, that the box can still change in future, otherwise
83 // it is fixed.
84 protected BoxProvider boxProvider;
85 protected Rectangle box;
86 public HorizontalTextAlignment hAlign;
87 public VerticalTextAlignment vAlign;
88
89 public BoxTextElemStyle(Cascade c, TextElement text, BoxProvider boxProvider, Rectangle box, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
90 super(c, 5f);
91 CheckParameterUtil.ensureParameterNotNull(text);
92 CheckParameterUtil.ensureParameterNotNull(hAlign);
93 CheckParameterUtil.ensureParameterNotNull(vAlign);
94 this.text = text;
95 this.boxProvider = boxProvider;
96 this.box = box == null ? ZERO_BOX : box;
97 this.hAlign = hAlign;
98 this.vAlign = vAlign;
99 }
100
101 public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider) {
102 return create(env, boxProvider, null);
103 }
104
105 public static BoxTextElemStyle create(Environment env, Rectangle box) {
106 return create(env, null, box);
107 }
108
109 public static BoxTextElemStyle create(Environment env, BoxProvider boxProvider, Rectangle box) {
110 initDefaultParameters();
111 Cascade c = env.mc.getCascade(env.layer);
112
113 TextElement text = TextElement.create(env, DEFAULT_TEXT_COLOR, false);
114 if (text == null) return null;
115 // Skip any primitives that don't have text to draw. (Styles are recreated for any tag change.)
116 // The concrete text to render is not cached in this object, but computed for each
117 // repaint. This way, one BoxTextElemStyle object can be used by multiple primitives (to save memory).
118 if (text.labelCompositionStrategy.compose(env.osm) == null) return null;
119
120 HorizontalTextAlignment hAlign = HorizontalTextAlignment.RIGHT;
121 Keyword hAlignKW = c.get("text-anchor-horizontal", Keyword.RIGHT, Keyword.class);
122 if ("left".equals(hAlignKW.val)) {
123 hAlign = HorizontalTextAlignment.LEFT;
124 } else if ("center".equals(hAlignKW.val)) {
125 hAlign = HorizontalTextAlignment.CENTER;
126 } else if ("right".equals(hAlignKW.val)) {
127 hAlign = HorizontalTextAlignment.RIGHT;
128 }
129 VerticalTextAlignment vAlign = VerticalTextAlignment.BOTTOM;
130 String vAlignStr = c.get("text-anchor-vertical", Keyword.BOTTOM, Keyword.class).val;
131 if ("above".equals(vAlignStr)) {
132 vAlign = VerticalTextAlignment.ABOVE;
133 } else if ("top".equals(vAlignStr)) {
134 vAlign = VerticalTextAlignment.TOP;
135 } else if ("center".equals(vAlignStr)) {
136 vAlign = VerticalTextAlignment.CENTER;
137 } else if ("bottom".equals(vAlignStr)) {
138 vAlign = VerticalTextAlignment.BOTTOM;
139 } else if ("below".equals(vAlignStr)) {
140 vAlign = VerticalTextAlignment.BELOW;
141 }
142
143 return new BoxTextElemStyle(c, text, boxProvider, box, hAlign, vAlign);
144 }
145
146 public Rectangle getBox() {
147 if (boxProvider != null) {
148 BoxProviderResult result = boxProvider.get();
149 if (!result.isTemporary()) {
150 box = result.getBox();
151 boxProvider = null;
152 }
153 return result.getBox();
154 }
155 return box;
156 }
157
158 public static final BoxTextElemStyle SIMPLE_NODE_TEXT_ELEMSTYLE;
159 static {
160 MultiCascade mc = new MultiCascade();
161 Cascade c = mc.getOrCreateCascade("default");
162 c.put(TEXT, Keyword.AUTO);
163 Node n = new Node();
164 n.put("name", "dummy");
165 SIMPLE_NODE_TEXT_ELEMSTYLE = create(new Environment(n, mc, "default", null), NodeElemStyle.SIMPLE_NODE_ELEMSTYLE.getBoxProvider());
166 if (SIMPLE_NODE_TEXT_ELEMSTYLE == null) throw new AssertionError();
167 }
168 /*
169 * Caches the default text color from the preferences.
170 *
171 * FIXME: the cache isn't updated if the user changes the preference during a JOSM
172 * session. There should be preference listener updating this cache.
173 */
174 private static Color DEFAULT_TEXT_COLOR = null;
175 private static void initDefaultParameters() {
176 if (DEFAULT_TEXT_COLOR != null) return;
177 DEFAULT_TEXT_COLOR = PaintColors.TEXT.get();
178 }
179
180 @Override
181 public void paintPrimitive(OsmPrimitive osm, MapPaintSettings settings, StyledMapRenderer painter, boolean selected, boolean member) {
182 if (osm instanceof Node) {
183 painter.drawBoxText((Node) osm, this);
184 }
185 }
186
187 @Override
188 public boolean equals(Object obj) {
189 if (!super.equals(obj))
190 return false;
191 if (obj == null || getClass() != obj.getClass())
192 return false;
193 final BoxTextElemStyle other = (BoxTextElemStyle) obj;
194 if (!text.equals(other.text)) return false;
195 if (boxProvider != null) {
196 if (!boxProvider.equals(other.boxProvider)) return false;
197 } else if (other.boxProvider != null)
198 return false;
199 else {
200 if (!box.equals(other.box)) return false;
201 }
202 if (hAlign != other.hAlign) return false;
203 if (vAlign != other.vAlign) return false;
204 return true;
205 }
206
207 @Override
208 public int hashCode() {
209 int hash = super.hashCode();
210 hash = 97 * hash + text.hashCode();
211 if (boxProvider != null) {
212 hash = 97 * hash + boxProvider.hashCode();
213 } else {
214 hash = 97 * hash + box.hashCode();
215 }
216 hash = 97 * hash + hAlign.hashCode();
217 hash = 97 * hash + vAlign.hashCode();
218 return hash;
219 }
220
221 @Override
222 public String toString() {
223 return "BoxTextElemStyle{" + super.toString() + " " + text.toStringImpl() + " box=" + box + " hAlign=" + hAlign + " vAlign=" + vAlign + '}';
224 }
225
226}
Note: See TracBrowser for help on using the repository browser.