001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint.styleelement; 003 004import java.awt.Color; 005import java.util.Objects; 006 007import org.openstreetmap.josm.Main; 008import org.openstreetmap.josm.data.osm.OsmPrimitive; 009import org.openstreetmap.josm.data.osm.Relation; 010import org.openstreetmap.josm.data.osm.Way; 011import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; 012import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 013import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer; 014import org.openstreetmap.josm.gui.mappaint.Cascade; 015import org.openstreetmap.josm.gui.mappaint.Environment; 016import org.openstreetmap.josm.gui.mappaint.Keyword; 017import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference; 018import org.openstreetmap.josm.tools.CheckParameterUtil; 019import org.openstreetmap.josm.tools.Utils; 020 021/** 022 * This is the style that defines how an area is filled. 023 */ 024public class AreaElement extends StyleElement { 025 026 /** 027 * If fillImage == null, color is the fill-color, otherwise 028 * an arbitrary color value sampled from the fillImage 029 */ 030 public Color color; 031 032 /** 033 * An image to cover this area. May be null to disable this feature. 034 */ 035 public MapImage fillImage; 036 037 /** 038 * The text that should be written on this area. 039 */ 040 public TextLabel text; 041 042 /** 043 * Fill the area only partially from the borders 044 * <p> 045 * Public access is discouraged. 046 * @see StyledMapRenderer#drawArea(Way, Color, MapImage, Float, Float, boolean, TextLabel) 047 */ 048 public Float extent; 049 050 /** 051 * Areas smaller than this are filled no matter what value {@link #extent} has. 052 * <p> 053 * Public access is discouraged. 054 * @see StyledMapRenderer#drawArea(Way, Color, MapImage, Float, Float, boolean, TextLabel) 055 */ 056 public Float extentThreshold; 057 058 protected AreaElement(Cascade c, Color color, MapImage fillImage, Float extent, Float extentThreshold, TextLabel text) { 059 super(c, 1f); 060 CheckParameterUtil.ensureParameterNotNull(color); 061 this.color = color; 062 this.fillImage = fillImage; 063 this.extent = extent; 064 this.extentThreshold = extentThreshold; 065 this.text = text; 066 } 067 068 /** 069 * Create a new {@link AreaElement} 070 * @param env The current style definitions 071 * @return The area element or <code>null</code> if the area should not be filled. 072 */ 073 public static AreaElement create(final Environment env) { 074 final Cascade c = env.mc.getCascade(env.layer); 075 MapImage fillImage = null; 076 Color color; 077 078 IconReference iconRef = c.get(FILL_IMAGE, null, IconReference.class); 079 if (iconRef != null) { 080 fillImage = new MapImage(iconRef.iconName, iconRef.source, false); 081 082 color = new Color(fillImage.getImage(false).getRGB( 083 fillImage.getWidth() / 2, fillImage.getHeight() / 2) 084 ); 085 086 fillImage.alpha = Math.min(255, Math.max(0, Main.pref.getInteger("mappaint.fill-image-alpha", 255))); 087 Integer pAlpha = Utils.colorFloat2int(c.get(FILL_OPACITY, null, float.class)); 088 if (pAlpha != null) { 089 fillImage.alpha = pAlpha; 090 } 091 } else { 092 color = c.get(FILL_COLOR, null, Color.class); 093 if (color != null) { 094 int alpha = color.getAlpha(); 095 if (alpha == 255) { 096 // Assume alpha value has not been specified by the user if 097 // is set to fully opaque. Use default value in this case. 098 // It is not an ideal solution, but a little tricky to get this 099 // right, especially as named map colors can be changed in 100 // the preference GUI and written to the preferences file. 101 alpha = Math.min(255, Math.max(0, Main.pref.getInteger("mappaint.fillalpha", 50))); 102 } 103 Integer pAlpha = Utils.colorFloat2int(c.get(FILL_OPACITY, null, float.class)); 104 if (pAlpha != null) { 105 alpha = pAlpha; 106 } 107 color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha); 108 } 109 } 110 111 TextLabel text = null; 112 Keyword textPos = c.get(TEXT_POSITION, null, Keyword.class); 113 if (textPos == null || "center".equals(textPos.val)) { 114 text = TextLabel.create(env, PaintColors.AREA_TEXT.get(), true); 115 } 116 117 Float extent = c.get(FILL_EXTENT, null, float.class); 118 Float extentThreshold = c.get(FILL_EXTENT_THRESHOLD, null, float.class); 119 120 if (color != null) 121 return new AreaElement(c, color, fillImage, extent, extentThreshold, text); 122 else 123 return null; 124 } 125 126 @Override 127 public void paintPrimitive(OsmPrimitive osm, MapPaintSettings paintSettings, StyledMapRenderer painter, 128 boolean selected, boolean outermember, boolean member) { 129 Color myColor = color; 130 if (osm instanceof Way) { 131 if (color != null) { 132 if (selected) { 133 myColor = paintSettings.getSelectedColor(color.getAlpha()); 134 } else if (outermember) { 135 myColor = paintSettings.getRelationSelectedColor(color.getAlpha()); 136 } 137 } 138 painter.drawArea((Way) osm, myColor, fillImage, extent, extentThreshold, painter.isInactiveMode() || osm.isDisabled(), text); 139 } else if (osm instanceof Relation) { 140 if (color != null && (selected || outermember)) { 141 myColor = paintSettings.getRelationSelectedColor(color.getAlpha()); 142 } 143 painter.drawArea((Relation) osm, myColor, fillImage, extent, extentThreshold, painter.isInactiveMode() || osm.isDisabled(), text); 144 } 145 } 146 147 @Override 148 public boolean equals(Object obj) { 149 if (this == obj) return true; 150 if (obj == null || getClass() != obj.getClass()) return false; 151 if (!super.equals(obj)) return false; 152 AreaElement that = (AreaElement) obj; 153 return Objects.equals(color, that.color) && 154 Objects.equals(fillImage, that.fillImage) && 155 Objects.equals(text, that.text) && 156 Objects.equals(extent, that.extent) && 157 Objects.equals(extentThreshold, that.extentThreshold); 158 } 159 160 @Override 161 public int hashCode() { 162 return Objects.hash(super.hashCode(), color, fillImage, text, extent, extentThreshold); 163 } 164 165 @Override 166 public String toString() { 167 return "AreaElemStyle{" + super.toString() + "color=" + Utils.toString(color) + 168 " fillImage=[" + fillImage + "]}"; 169 } 170}