source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java@ 4327

Last change on this file since 4327 was 4327, checked in by xeen, 13 years ago

updates visual appearance of highlights and adds them to select and delete action

in more detail:

  • add target highlighting to select action
  • add target cursor to select action
  • add target highlighting to delete action
  • unify ctrl/alt/shift modifier detection in MapMode actions
  • highlights are now a halo around the way/node instead of a color change
  • default highlight color is now the same as the select color (red)
  • ability to highlight WaySegments and VirtualNodes
  • various style/whitespace nits
  • fixes #2411

This patch touches a lot of areas, so please report any regressions in the map mode
tools. Also please add a comment to #2411 if you find to highlighting in select
mode distracting, so it can be fine tuned (or turned off by default).

  • Property svn:eol-style set to native
File size: 11.8 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.util.Arrays;
9
10import org.openstreetmap.josm.data.osm.Node;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.data.osm.Way;
13import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
14import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
15import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
16import org.openstreetmap.josm.tools.Utils;
17
18public class LineElemStyle extends ElemStyle {
19
20 public static LineElemStyle createSimpleLineStyle(Color color, boolean isAreaEdge) {
21 MultiCascade mc = new MultiCascade();
22 Cascade c = mc.getOrCreateCascade("default");
23 c.put("width", Keyword.DEFAULT);
24 c.put("color", color != null ? color : PaintColors.UNTAGGED.get());
25 if (isAreaEdge) {
26 c.put("z-index", -3f);
27 }
28 return createLine(new Environment(null, mc, "default", null));
29 }
30 public static final LineElemStyle UNTAGGED_WAY = createSimpleLineStyle(null, false);
31
32 private BasicStroke line;
33 public Color color;
34 public Color dashesBackground;
35 public int offset;
36 public float realWidth; // the real width of this line in meter
37
38 private BasicStroke dashesLine;
39
40 protected LineElemStyle(Cascade c, BasicStroke line, Color color, BasicStroke dashesLine, Color dashesBackground, int offset, float realWidth) {
41 super(c, 0f);
42 this.line = line;
43 this.color = color;
44 this.dashesLine = dashesLine;
45 this.dashesBackground = dashesBackground;
46 this.offset = offset;
47 this.realWidth = realWidth;
48 }
49
50 public static LineElemStyle createLine(Environment env) {
51 return createImpl(env, false);
52 }
53
54 public static LineElemStyle createCasing(Environment env) {
55 LineElemStyle casing = createImpl(env, true);
56 if (casing != null) {
57 casing.z_index += -100;
58 casing.isModifier = true;
59 }
60 return casing;
61 }
62
63 private static LineElemStyle createImpl(Environment env, boolean casing) {
64 Cascade c = env.mc.getCascade(env.layer);
65 Cascade c_def = env.mc.getCascade("default");
66
67 String prefix = casing ? "casing-" : "";
68
69 Float width;
70 if (casing) {
71 Float widthOnDefault = getWidth(c_def, "width", null);
72 Float widthLine = getWidth(c, "width", widthOnDefault);
73 width = getWidth(c, "casing-width", widthLine);
74 } else {
75 Float widthOnDefault = getWidth(c_def, "width", null);
76 width = getWidth(c, "width", widthOnDefault);
77 }
78
79 if (width == null)
80 return null;
81
82 float realWidth = c.get(prefix + "real-width", 0f, Float.class);
83 if (realWidth > 0 && MapPaintSettings.INSTANCE.isUseRealWidth()) {
84
85 /* if we have a "width" tag, try use it */
86 String widthTag = env.osm.get("width");
87 if(widthTag == null) {
88 widthTag = env.osm.get("est_width");
89 }
90 if(widthTag != null) {
91 try {
92 realWidth = Float.valueOf(widthTag);
93 }
94 catch(NumberFormatException nfe) {
95 }
96 }
97 }
98
99 Color color = c.get(prefix + "color", null, Color.class);
100 if (!casing && color == null) {
101 color = c.get("fill-color", null, Color.class);
102 }
103 if (color == null) {
104 color = PaintColors.UNTAGGED.get();
105 }
106
107 int alpha = 255;
108 Integer pAlpha = Utils.color_float2int(c.get("opacity", null, Float.class));
109 if (pAlpha != null) {
110 alpha = pAlpha;
111 }
112 color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
113
114 float[] dashes = c.get(prefix + "dashes", null, float[].class);
115 if (dashes != null) {
116 boolean hasPositive = false;
117 for (float f : dashes) {
118 if (f > 0) {
119 hasPositive = true;
120 }
121 if (f < 0) {
122 dashes = null;
123 break;
124 }
125 }
126 if (!hasPositive || (dashes != null && dashes.length == 0)) {
127 dashes = null;
128 }
129 }
130 float dashesOffset = c.get(prefix + "dashes-offset", 0f, Float.class);
131 Color dashesBackground = c.get(prefix + "dashes-background-color", null, Color.class);
132 if (dashesBackground != null) {
133 pAlpha = Utils.color_float2int(c.get(prefix + "dashes-background-opacity", null, Float.class));
134 if (pAlpha != null) {
135 alpha = pAlpha;
136 }
137 dashesBackground = new Color(dashesBackground.getRed(), dashesBackground.getGreen(),
138 dashesBackground.getBlue(), alpha);
139 }
140
141 Integer cap = null;
142 Keyword capKW = c.get(prefix + "linecap", null, Keyword.class);
143 if (capKW != null) {
144 if (equal(capKW.val, "none")) {
145 cap = BasicStroke.CAP_BUTT;
146 } else if (equal(capKW.val, "round")) {
147 cap = BasicStroke.CAP_ROUND;
148 } else if (equal(capKW.val, "square")) {
149 cap = BasicStroke.CAP_SQUARE;
150 }
151 }
152 if (cap == null) {
153 cap = dashes != null ? BasicStroke.CAP_BUTT : BasicStroke.CAP_ROUND;
154 }
155
156 Integer join = null;
157 Keyword joinKW = c.get(prefix + "linejoin", null, Keyword.class);
158 if (joinKW != null) {
159 if (equal(joinKW.val, "round")) {
160 join = BasicStroke.JOIN_ROUND;
161 } else if (equal(joinKW.val, "miter")) {
162 join = BasicStroke.JOIN_MITER;
163 } else if (equal(joinKW.val, "bevel")) {
164 join = BasicStroke.JOIN_BEVEL;
165 }
166 }
167 if (join == null) {
168 join = BasicStroke.JOIN_ROUND;
169 }
170
171 float miterlimit = c.get(prefix + "miterlimit", 10f, Float.class);
172 if (miterlimit < 1f) {
173 miterlimit = 10f;
174 }
175
176 BasicStroke line = new BasicStroke(width, cap, join, miterlimit, dashes, dashesOffset);
177 BasicStroke dashesLine = null;
178
179 float offset = c.get("offset", 0f, Float.class);
180
181 if (dashes != null && dashesBackground != null) {
182 float[] dashes2 = new float[dashes.length];
183 System.arraycopy(dashes, 0, dashes2, 1, dashes.length - 1);
184 dashes2[0] = dashes[dashes.length-1];
185 dashesLine = new BasicStroke(width, cap, join, miterlimit, dashes2, dashes2[0] + dashesOffset);
186 }
187
188 return new LineElemStyle(c, line, color, dashesLine, dashesBackground, (int) offset, realWidth);
189 }
190
191 @Override
192 public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member) {
193 Way w = (Way)primitive;
194 /* show direction arrows, if draw.segment.relevant_directions_only is not set,
195 the way is tagged with a direction key
196 (even if the tag is negated as in oneway=false) or the way is selected */
197 boolean showOrientation = !isModifier && (selected || paintSettings.isShowDirectionArrow()) && !paintSettings.isUseRealWidth();
198 boolean showOneway = !isModifier && !selected &&
199 !paintSettings.isUseRealWidth() &&
200 paintSettings.isShowOnewayArrow() && w.hasDirectionKeys();
201 boolean onewayReversed = w.reversedDirection();
202 /* head only takes over control if the option is true,
203 the direction should be shown at all and not only because it's selected */
204 boolean showOnlyHeadArrowOnly = showOrientation && !selected && paintSettings.isShowHeadArrowOnly();
205 Node lastN;
206
207 Color myDashedColor = dashesBackground;
208 BasicStroke myLine = line, myDashLine = dashesLine;
209 if (realWidth > 0 && paintSettings.isUseRealWidth() && !showOrientation) {
210 float myWidth = (int) (100 / (float) (painter.getCircum() / realWidth));
211 if (myWidth < line.getLineWidth()) {
212 myWidth = line.getLineWidth();
213 }
214 myLine = new BasicStroke(myWidth, line.getEndCap(), line.getLineJoin(),
215 line.getMiterLimit(), line.getDashArray(), line.getDashPhase());
216 if (dashesLine != null) {
217 myDashLine = new BasicStroke(myWidth, dashesLine.getEndCap(), dashesLine.getLineJoin(),
218 dashesLine.getMiterLimit(), dashesLine.getDashArray(), dashesLine.getDashPhase());
219 }
220 }
221
222 Color myColor = color;
223 if (selected) {
224 myColor = paintSettings.getSelectedColor(color.getAlpha());
225 } else if (member) {
226 myColor = paintSettings.getRelationSelectedColor(color.getAlpha());
227 } else if(w.isDisabled()) {
228 myColor = paintSettings.getInactiveColor();
229 myDashedColor = paintSettings.getInactiveColor();
230 }
231
232 painter.drawWay(w, myColor, myLine, myDashLine, myDashedColor, offset, showOrientation,
233 showOnlyHeadArrowOnly, showOneway, onewayReversed);
234
235 if(paintSettings.isShowOrderNumber()) {
236 int orderNumber = 0;
237 lastN = null;
238 for(Node n : w.getNodes()) {
239 if(lastN != null) {
240 orderNumber++;
241 painter.drawOrderNumber(lastN, n, orderNumber, myColor);
242 }
243 lastN = n;
244 }
245 }
246 }
247
248 @Override
249 public boolean isProperLineStyle() {
250 return !isModifier;
251 }
252
253 @Override
254 public boolean equals(Object obj) {
255 if (obj == null || getClass() != obj.getClass())
256 return false;
257 if (!super.equals(obj))
258 return false;
259 final LineElemStyle other = (LineElemStyle) obj;
260 return equal(line, other.line) &&
261 equal(color, other.color) &&
262 equal(dashesLine, other.dashesLine) &&
263 equal(dashesBackground, other.dashesBackground) &&
264 offset == other.offset &&
265 realWidth == other.realWidth;
266 }
267
268 @Override
269 public int hashCode() {
270 int hash = super.hashCode();
271 hash = 29 * hash + line.hashCode();
272 hash = 29 * hash + color.hashCode();
273 hash = 29 * hash + (dashesLine != null ? dashesLine.hashCode() : 0);
274 hash = 29 * hash + (dashesBackground != null ? dashesBackground.hashCode() : 0);
275 hash = 29 * hash + offset;
276 hash = 29 * hash + Float.floatToIntBits(realWidth);
277 return hash;
278 }
279
280 @Override
281 public String toString() {
282 return "LineElemStyle{" + super.toString() + "width=" + line.getLineWidth() +
283 " realWidth=" + realWidth + " color=" + Utils.toString(color) +
284 " dashed=" + Arrays.toString(line.getDashArray()) +
285 (line.getDashPhase() == 0f ? "" : " dashesOffses=" + line.getDashPhase()) +
286 " dashedColor=" + Utils.toString(dashesBackground) +
287 " linejoin=" + linejoinToString(line.getLineJoin()) +
288 " linecap=" + linecapToString(line.getEndCap()) +
289 (offset == 0 ? "" : " offset=" + offset) +
290 '}';
291 }
292
293 public String linejoinToString(int linejoin) {
294 switch (linejoin) {
295 case BasicStroke.JOIN_BEVEL: return "bevel";
296 case BasicStroke.JOIN_ROUND: return "round";
297 case BasicStroke.JOIN_MITER: return "miter";
298 default: return null;
299 }
300 }
301 public String linecapToString(int linecap) {
302 switch (linecap) {
303 case BasicStroke.CAP_BUTT: return "none";
304 case BasicStroke.CAP_ROUND: return "round";
305 case BasicStroke.CAP_SQUARE: return "square";
306 default: return null;
307 }
308 }
309}
Note: See TracBrowser for help on using the repository browser.