001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.mappaint.styleelement; 003 004import java.util.Objects; 005 006import org.openstreetmap.josm.data.osm.IPrimitive; 007import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings; 008import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors; 009import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer; 010import org.openstreetmap.josm.gui.mappaint.Cascade; 011import org.openstreetmap.josm.gui.mappaint.Environment; 012import org.openstreetmap.josm.gui.mappaint.Keyword; 013import org.openstreetmap.josm.gui.mappaint.styleelement.placement.CompletelyInsideAreaStrategy; 014import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy; 015 016/** 017 * The text that is drawn for a way/area. It may be drawn along the outline or onto the way. 018 * 019 * @since 11722 020 */ 021public class TextElement extends StyleElement { 022 023 private final TextLabel text; 024 /** 025 * The position strategy for this text label. 026 */ 027 private final PositionForAreaStrategy labelPositionStrategy; 028 029 /** 030 * Create a new way/area text element definition 031 * @param c The cascade 032 * @param text The text 033 * @param labelPositionStrategy The position in the area. 034 */ 035 protected TextElement(Cascade c, TextLabel text, PositionForAreaStrategy labelPositionStrategy) { 036 super(c, 4.9f); 037 this.text = Objects.requireNonNull(text, "text"); 038 this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy"); 039 } 040 041 /** 042 * Gets the strategy that defines where to place the label. 043 * @return The strategy. Never null. 044 * @since 12475 045 */ 046 public PositionForAreaStrategy getLabelPositionStrategy() { 047 return labelPositionStrategy; 048 } 049 050 /** 051 * Create a new text element 052 * @param env The environment to read the text data from 053 * @return The text element or <code>null</code> if it could not be created. 054 */ 055 public static TextElement create(final Environment env) { 056 TextLabel text = TextLabel.create(env, PaintColors.TEXT.get(), false); 057 if (text == null) 058 return null; 059 final Cascade c = env.getCascade(); 060 061 Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class); 062 PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword); 063 position = position.withAddedOffset(TextLabel.getTextOffset(c)); 064 065 return new TextElement(c, text, position); 066 } 067 068 /** 069 * JOSM traditionally adds both line and content text elements if a fill style was set. 070 * 071 * For now, we simulate this by generating a TextElement if no text-position was provided. 072 * @param env The environment to read the text data from 073 * @return The text element or <code>null</code> if it could not be created. 074 */ 075 public static TextElement createForContent(Environment env) { 076 final Cascade c = env.getCascade(); 077 Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class); 078 if (positionKeyword != null) { 079 return null; // No need for this hack. 080 } 081 082 TextLabel text = TextLabel.create(env, PaintColors.TEXT.get(), true); 083 if (text == null) { 084 return null; 085 } 086 return new TextElement(c, text, CompletelyInsideAreaStrategy.INSTANCE); 087 } 088 089 @Override 090 public void paintPrimitive(IPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter, 091 boolean selected, boolean outermember, boolean member) { 092 painter.drawText(primitive, text, getLabelPositionStrategy()); 093 } 094 095 @Override 096 public boolean equals(Object obj) { 097 if (this == obj) return true; 098 if (obj == null || getClass() != obj.getClass()) return false; 099 if (!super.equals(obj)) return false; 100 TextElement that = (TextElement) obj; 101 return Objects.equals(labelPositionStrategy, that.labelPositionStrategy) 102 && Objects.equals(text, that.text); 103 } 104 105 @Override 106 public int hashCode() { 107 return Objects.hash(super.hashCode(), text, labelPositionStrategy); 108 } 109 110 @Override 111 public String toString() { 112 return "TextElement{" + super.toString() + "text=" + text + " labelPositionStrategy=" + labelPositionStrategy + '}'; 113 } 114}