001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.bbox; 003 004import java.awt.Color; 005import java.awt.Dimension; 006import java.awt.Font; 007import java.awt.FontMetrics; 008import java.awt.Graphics; 009import java.awt.Graphics2D; 010import java.awt.Point; 011import java.awt.RenderingHints; 012import java.awt.event.MouseAdapter; 013import java.awt.event.MouseEvent; 014import java.awt.event.MouseListener; 015import java.util.Collection; 016 017import javax.swing.ImageIcon; 018import javax.swing.JComponent; 019 020import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 021import org.openstreetmap.josm.tools.CheckParameterUtil; 022import org.openstreetmap.josm.tools.ImageProvider; 023 024public class SourceButton extends JComponent { 025 026 private static final int LAYER_HEIGHT = 20; 027 private static final int LEFT_PADDING = 5; 028 private static final int TOP_PADDING = 5; 029 private static final int BOTTOM_PADDING = 5; 030 031 private TileSource[] sources; 032 033 private final ImageIcon enlargeImage; 034 private final ImageIcon shrinkImage; 035 private final Dimension hiddenDimension; 036 037 // Calculated after component is added to container 038 private int barWidth; 039 private Dimension shownDimension; 040 private Font font; 041 042 private boolean isEnlarged = false; 043 044 private int currentMap; 045 private final SlippyMapBBoxChooser slippyMapBBoxChooser; 046 047 public SourceButton(SlippyMapBBoxChooser slippyMapBBoxChooser, Collection<TileSource> sources) { 048 this.slippyMapBBoxChooser = slippyMapBBoxChooser; 049 setSources(sources); 050 enlargeImage = ImageProvider.get("layer-switcher-maximize"); 051 shrinkImage = ImageProvider.get("layer-switcher-minimize"); 052 053 hiddenDimension= new Dimension(enlargeImage.getIconWidth(), enlargeImage.getIconHeight()); 054 setPreferredSize(hiddenDimension); 055 056 addMouseListener(mouseListener); 057 } 058 059 private final MouseListener mouseListener = new MouseAdapter() { 060 @Override 061 public void mouseReleased(MouseEvent e) { 062 if (e.getButton() == MouseEvent.BUTTON1) { 063 Point point = e.getPoint(); 064 if (isEnlarged) { 065 if (barWidth < point.x && point.y < shrinkImage.getIconHeight()) { 066 toggle(); 067 } else { 068 int result = (point.y - 5) / LAYER_HEIGHT; 069 if (result >= 0 && result < SourceButton.this.sources.length) { 070 SourceButton.this.slippyMapBBoxChooser.toggleMapSource(SourceButton.this.sources[result]); 071 currentMap = result; 072 toggle(); 073 } 074 } 075 } else { 076 toggle(); 077 } 078 } 079 } 080 }; 081 082 /** 083 * Set the tile sources. 084 * @param sources The tile sources to display 085 * @since 6364 086 */ 087 public final void setSources(Collection<TileSource> sources) { 088 CheckParameterUtil.ensureParameterNotNull(sources, "sources"); 089 this.sources = sources.toArray(new TileSource[sources.size()]); 090 shownDimension = null; 091 } 092 093 @Override 094 protected void paintComponent(Graphics graphics) { 095 Graphics2D g = (Graphics2D) graphics.create(); 096 try { 097 calculateShownDimension(); 098 g.setFont(font); 099 if (isEnlarged) { 100 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 101 int radioButtonSize = 10; 102 103 g.setColor(new Color(0, 0, 139, 179)); 104 g.fillRoundRect(0, 0, barWidth + shrinkImage.getIconWidth(), sources.length * LAYER_HEIGHT + TOP_PADDING + BOTTOM_PADDING, 10, 10); 105 for (int i=0; i<sources.length; i++) { 106 g.setColor(Color.WHITE); 107 g.fillOval(LEFT_PADDING, TOP_PADDING + i * LAYER_HEIGHT + 6, radioButtonSize, radioButtonSize); 108 g.drawString(sources[i].getName(), LEFT_PADDING + radioButtonSize + LEFT_PADDING, TOP_PADDING + i * LAYER_HEIGHT + g.getFontMetrics().getHeight()); 109 if (currentMap == i) { 110 g.setColor(Color.BLACK); 111 g.fillOval(LEFT_PADDING + 1, TOP_PADDING + 7 + i * LAYER_HEIGHT, radioButtonSize - 2, radioButtonSize - 2); 112 } 113 } 114 115 g.drawImage(shrinkImage.getImage(), barWidth, 0, null); 116 } else { 117 g.drawImage(enlargeImage.getImage(), 0, 0, null); 118 } 119 } finally { 120 g.dispose(); 121 } 122 } 123 124 public void toggle() { 125 this.isEnlarged = !this.isEnlarged; 126 calculateShownDimension(); 127 setPreferredSize(isEnlarged?shownDimension:hiddenDimension); 128 revalidate(); 129 } 130 131 132 public void setCurrentMap(TileSource tileSource) { 133 for (int i=0; i<sources.length; i++) { 134 if (sources[i].equals(tileSource)) { 135 currentMap = i; 136 return; 137 } 138 } 139 currentMap = 0; 140 } 141 142 private void calculateShownDimension() { 143 if (shownDimension == null) { 144 font = getFont().deriveFont(Font.BOLD).deriveFont(15.0f); 145 int textWidth = 0; 146 FontMetrics fm = getFontMetrics(font); 147 for (TileSource source: sources) { 148 int width = fm.stringWidth(source.getName()); 149 if (width > textWidth) { 150 textWidth = width; 151 } 152 } 153 barWidth = textWidth + 50; 154 shownDimension = new Dimension(barWidth + shrinkImage.getIconWidth(), sources.length * LAYER_HEIGHT + TOP_PADDING + BOTTOM_PADDING); 155 } 156 } 157}