Ticket #5570: opacity.diff
| File opacity.diff, 18.7 KB (added by , 15 years ago) |
|---|
-
src/org/openstreetmap/josm/gui/MapView.java
package org.openstreetmap.josm.gui; 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.AlphaComposite; 6 7 import java.awt.Color; 7 8 import java.awt.Graphics; 8 9 import java.awt.Graphics2D; … … public class MapView extends NavigatableComponent implements PropertyChangeListe 183 184 private BufferedImage offscreenBuffer; 184 185 // Layers that wasn't changed since last paint 185 186 private final List<Layer> nonChangedLayers = new ArrayList<Layer>(); 187 private Layer changedLayer; 186 188 private int lastViewID; 187 189 private boolean paintPreferencesChanged = true; 188 190 private Rectangle lastClipBounds = new Rectangle(); … … public class MapView extends NavigatableComponent implements PropertyChangeListe 439 441 return ret; 440 442 } 441 443 444 private void paintLayer(Layer layer, Graphics2D g, Bounds box) { 445 if (layer.getOpacity() < 1) { 446 g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float)layer.getOpacity())); 447 } 448 layer.paint(g, this, box); 449 g.setPaintMode(); 450 } 451 442 452 /** 443 453 * Draw the component. 444 454 */ … … public class MapView extends NavigatableComponent implements PropertyChangeListe 453 463 454 464 int nonChangedLayersCount = 0; 455 465 for (Layer l: visibleLayers) { 456 if (l.isChanged() ) {466 if (l.isChanged() || l == changedLayer) { 457 467 break; 458 468 } else { 459 469 nonChangedLayersCount++; … … public class MapView extends NavigatableComponent implements PropertyChangeListe 489 499 g2.fillRect(0, 0, getWidth(), getHeight()); 490 500 491 501 for (int i=0; i<nonChangedLayersCount; i++) { 492 visibleLayers.get(i).paint(g2, this, box);502 paintLayer(visibleLayers.get(i),g2, box); 493 503 } 494 504 } else { 495 505 // Maybe there were more unchanged layers then last time - draw them to buffer … … public class MapView extends NavigatableComponent implements PropertyChangeListe 497 507 Graphics2D g2 = nonChangedLayersBuffer.createGraphics(); 498 508 g2.setClip(g.getClip()); 499 509 for (int i=nonChangedLayers.size(); i<nonChangedLayersCount; i++) { 500 visibleLayers.get(i).paint(g2, this, box);510 paintLayer(visibleLayers.get(i),g2, box); 501 511 } 502 512 } 503 513 } 504 514 505 515 nonChangedLayers.clear(); 516 changedLayer = null; 506 517 for (int i=0; i<nonChangedLayersCount; i++) { 507 518 nonChangedLayers.add(visibleLayers.get(i)); 508 519 } … … public class MapView extends NavigatableComponent implements PropertyChangeListe 513 524 tempG.drawImage(nonChangedLayersBuffer, 0, 0, null); 514 525 515 526 for (int i=nonChangedLayersCount; i<visibleLayers.size(); i++) { 516 visibleLayers.get(i).paint(tempG, this, box);527 paintLayer(visibleLayers.get(i),tempG, box); 517 528 } 518 529 519 530 for (MapViewPaintable mvp : temporaryLayers) { … … public class MapView extends NavigatableComponent implements PropertyChangeListe 782 793 public void propertyChange(PropertyChangeEvent evt) { 783 794 if (evt.getPropertyName().equals(Layer.VISIBLE_PROP)) { 784 795 repaint(); 796 } else if (evt.getPropertyName().equals(Layer.OPACITY_PROP)) { 797 Layer l = (Layer)evt.getSource(); 798 if (l.isVisible()) { 799 changedLayer = l; 800 repaint(); 801 } 785 802 } else if (evt.getPropertyName().equals(OsmDataLayer.REQUIRES_SAVE_TO_DISK_PROP) 786 803 || evt.getPropertyName().equals(OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP)) { 787 804 OsmDataLayer layer = (OsmDataLayer)evt.getSource(); -
src/org/openstreetmap/josm/gui/dialogs/LayerListDialog.java
import javax.swing.JComponent; 30 30 import javax.swing.JLabel; 31 31 import javax.swing.JMenuItem; 32 32 import javax.swing.JPanel; 33 import javax.swing.JPopupMenu; 33 34 import javax.swing.JScrollPane; 35 import javax.swing.JSlider; 34 36 import javax.swing.JTable; 35 37 import javax.swing.JTextField; 36 38 import javax.swing.JViewport; 37 39 import javax.swing.KeyStroke; 38 40 import javax.swing.ListSelectionModel; 39 41 import javax.swing.UIManager; 42 import javax.swing.event.ChangeEvent; 43 import javax.swing.event.ChangeListener; 40 44 import javax.swing.event.ListSelectionEvent; 41 45 import javax.swing.event.ListSelectionListener; 42 46 import javax.swing.event.TableModelEvent; … … public class LayerListDialog extends ToggleDialog { 107 111 /** the list of layers (technically its a JTable, but appears like a list) */ 108 112 private LayerList layerList; 109 113 114 private SideButton opacityButton; 115 110 116 ActivateLayerAction activateLayerAction; 111 117 112 118 protected JPanel createButtonPanel() { … … public class LayerListDialog extends ToggleDialog { 152 158 adaptTo(deleteLayerAction, selectionModel); 153 159 buttonPanel.add(new SideButton(deleteLayerAction, false)); 154 160 161 //-- layer opacity action 162 LayerOpacityAction layerOpacityAction = new LayerOpacityAction(); 163 adaptTo(layerOpacityAction, selectionModel); 164 opacityButton = new SideButton(layerOpacityAction); 165 buttonPanel.add(opacityButton); 166 155 167 return buttonPanel; 156 168 } 157 169 … … public class LayerListDialog extends ToggleDialog { 184 196 layerList.getColumnModel().getColumn(0).setPreferredWidth(12); 185 197 layerList.getColumnModel().getColumn(0).setResizable(false); 186 198 layerList.getColumnModel().getColumn(1).setCellRenderer(new LayerVisibleCellRenderer()); 187 layerList.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(new LayerVisibleCheckBox()));199 layerList.getColumnModel().getColumn(1).setCellEditor(new LayerVisibleCellEditor(new LayerVisibleCheckBox())); 188 200 layerList.getColumnModel().getColumn(1).setMaxWidth(16); 189 201 layerList.getColumnModel().getColumn(1).setPreferredWidth(16); 190 202 layerList.getColumnModel().getColumn(1).setResizable(false); … … public class LayerListDialog extends ToggleDialog { 199 211 KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK), 200 212 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), 201 213 KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), 202 })214 }) 203 215 { 204 216 layerList.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, new Object()); 205 217 } … … public class LayerListDialog extends ToggleDialog { 278 290 */ 279 291 protected void adaptTo(final IEnabledStateUpdating listener, LayerListModel listModel) { 280 292 listModel.addTableModelListener( 281 new TableModelListener() {293 new TableModelListener() { 282 294 283 @Override 284 public void tableChanged(TableModelEvent e) { 285 listener.updateEnabledState(); 295 @Override 296 public void tableChanged(TableModelEvent e) { 297 listener.updateEnabledState(); 298 } 286 299 } 287 }288 300 ); 289 301 } 290 302 … … public class LayerListDialog extends ToggleDialog { 445 457 } 446 458 } 447 459 460 public final class LayerOpacityAction extends AbstractAction implements IEnabledStateUpdating, LayerAction { 461 private Layer layer; 462 private JPopupMenu popup; 463 private JSlider slider = new JSlider(JSlider.VERTICAL); 464 465 /** 466 * Creates a {@see LayerOpacityAction} which allows to chenge the 467 * opacity of one or more layers. 468 * 469 * @param layer the layer. Must not be null. 470 * @exception IllegalArgumentException thrown, if layer is null 471 */ 472 public LayerOpacityAction(Layer layer) throws IllegalArgumentException { 473 this(); 474 putValue(NAME, tr("Opacity")); 475 CheckParameterUtil.ensureParameterNotNull(layer, "layer"); 476 this.layer = layer; 477 updateEnabledState(); 478 } 479 480 /** 481 * Creates a {@see ShowHideLayerAction} which will toggle the visibility of 482 * the currently selected layers 483 * 484 */ 485 public LayerOpacityAction() { 486 putValue(SHORT_DESCRIPTION, tr("Adjust opacity of the layer.")); 487 putValue(SMALL_ICON, ImageProvider.get("dialogs/layerlist", "transparency")); 488 updateEnabledState(); 489 490 popup = new JPopupMenu(); 491 slider.addChangeListener(new ChangeListener() { 492 @Override 493 public void stateChanged(ChangeEvent e) { 494 setOpacity((double)slider.getValue()/100); 495 } 496 }); 497 popup.add(slider); 498 } 499 500 private void setOpacity(double value) { 501 if (!isEnabled()) return; 502 if (layer != null) { 503 layer.setOpacity(value); 504 } else { 505 for(Layer layer: model.getSelectedLayers()) { 506 layer.setOpacity(value); 507 } 508 } 509 } 510 511 private double getOpacity() { 512 if (layer != null) 513 return layer.getOpacity(); 514 else { 515 double opacity = 0; 516 List<Layer> layers = model.getSelectedLayers(); 517 for(Layer layer: layers) { 518 opacity += layer.getOpacity(); 519 } 520 return opacity / layers.size(); 521 } 522 } 523 524 @Override 525 public void actionPerformed(ActionEvent e) { 526 slider.setValue((int)Math.round(getOpacity()*100)); 527 popup.show(opacityButton, 0, opacityButton.getHeight()); 528 } 529 530 @Override 531 public void updateEnabledState() { 532 if (layer == null) { 533 setEnabled(! getModel().getSelectedLayers().isEmpty()); 534 } else { 535 setEnabled(true); 536 } 537 } 538 539 @Override 540 public Component createMenuComponent() { 541 return new JMenuItem(this); 542 } 543 544 @Override 545 public boolean supportLayers(List<Layer> layers) { 546 return true; 547 } 548 549 @Override 550 public boolean equals(Object obj) { 551 return obj instanceof LayerOpacityAction; 552 } 553 554 @Override 555 public int hashCode() { 556 return getClass().hashCode(); 557 } 558 } 559 448 560 /** 449 561 * The action to activate the currently selected layer 450 562 */ … … public class LayerListDialog extends ToggleDialog { 634 746 } 635 747 636 748 private static class LayerVisibleCheckBox extends JCheckBox { 749 private final ImageIcon icon_eye; 750 private final ImageIcon icon_eye_translucent; 751 private boolean isTranslucent; 637 752 public LayerVisibleCheckBox() { 638 753 setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); 639 ImageIcon eye = ImageProvider.get("dialogs/layerlist", "eye"); 640 ImageIcon eye_off = ImageProvider.get("dialogs/layerlist", "eye-off"); 641 setIcon(eye_off); 642 setSelectedIcon(eye); 643 setRolloverIcon(eye_off); 644 setRolloverSelectedIcon(eye); 754 icon_eye = ImageProvider.get("dialogs/layerlist", "eye"); 755 icon_eye_translucent = ImageProvider.get("dialogs/layerlist", "eye-translucent"); 756 setIcon(ImageProvider.get("dialogs/layerlist", "eye-off")); 645 757 setPressedIcon(ImageProvider.get("dialogs/layerlist", "eye-pressed")); 758 setSelectedIcon(icon_eye); 759 isTranslucent = false; 760 } 761 762 public void setTranslucent(boolean isTranslucent) { 763 if (this.isTranslucent == isTranslucent) return; 764 if (isTranslucent) { 765 setSelectedIcon(icon_eye_translucent); 766 } else { 767 setSelectedIcon(icon_eye); 768 } 769 this.isTranslucent = isTranslucent; 770 } 771 772 public void updateStatus(Layer layer) { 773 boolean visible = layer.isVisible(); 774 setSelected(visible); 775 setTranslucent(layer.getOpacity()<1.0); 776 setToolTipText(visible ? tr("layer is currently visible (click to hide layer)") : tr("layer is currently hidden (click to show layer)")); 646 777 } 647 778 } 648 779 … … public class LayerListDialog extends ToggleDialog { 662 793 } 663 794 664 795 private static class LayerVisibleCellRenderer implements TableCellRenderer { 665 JCheckBox cb;796 LayerVisibleCheckBox cb; 666 797 public LayerVisibleCellRenderer() { 667 cb = new LayerVisibleCheckBox();798 this.cb = new LayerVisibleCheckBox(); 668 799 } 669 800 670 801 @Override 671 802 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 672 boolean visible = (Boolean) value; 673 cb.setSelected(visible); 674 cb.setToolTipText(visible ? tr("layer is currently visible (click to hide layer)") : tr("layer is currently hidden (click to show layer)")); 803 cb.updateStatus((Layer)value); 675 804 return cb; 676 805 } 677 806 } 678 807 679 private static class LayerNameCellRenderer extends DefaultTableCellRenderer { 808 private static class LayerVisibleCellEditor extends DefaultCellEditor { 809 LayerVisibleCheckBox cb; 810 public LayerVisibleCellEditor(LayerVisibleCheckBox cb) { 811 super(cb); 812 this.cb = cb; 813 } 814 815 @Override 816 public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { 817 cb.updateStatus((Layer)value); 818 return cb; 819 } 820 } 821 822 private static class LayerNameCellRenderer extends DefaultTableCellRenderer { 680 823 681 824 protected boolean isActiveLayer(Layer layer) { 682 825 if (Main.map == null) return false; … … public class LayerListDialog extends ToggleDialog { 1141 1284 public Object getValueAt(int row, int col) { 1142 1285 switch (col) { 1143 1286 case 0: return getLayers().get(row) == getActiveLayer(); 1144 case 1: return getLayers().get(row) .isVisible();1287 case 1: return getLayers().get(row); 1145 1288 case 2: return getLayers().get(row); 1146 1289 default: throw new RuntimeException(); 1147 1290 } … … public class LayerListDialog extends ToggleDialog { 1168 1311 case 2: 1169 1312 l.setName((String) value); 1170 1313 break; 1171 default: throw new RuntimeException();1314 default: throw new RuntimeException(); 1172 1315 } 1173 1316 fireTableCellUpdated(row, col); 1174 1317 } -
src/org/openstreetmap/josm/gui/layer/Layer.java
abstract public class Layer implements Destroyable, MapViewPaintable { 69 69 } 70 70 71 71 static public final String VISIBLE_PROP = Layer.class.getName() + ".visible"; 72 static public final String OPACITY_PROP = Layer.class.getName() + ".opacity"; 72 73 static public final String NAME_PROP = Layer.class.getName() + ".name"; 73 74 74 75 … … abstract public class Layer implements Destroyable, MapViewPaintable { 82 83 private boolean visible = true; 83 84 84 85 /** 86 * The opacity of the layer. 87 * 88 */ 89 private double opacity = 1; 90 91 /** 85 92 * The layer should be handled as a background layer in automatic handling 86 93 * 87 94 */ … … abstract public class Layer implements Destroyable, MapViewPaintable { 110 117 * Paint the dataset using the engine set. 111 118 * @param mv The object that can translate GeoPoints to screen coordinates. 112 119 */ 120 @Override 113 121 abstract public void paint(Graphics2D g, MapView mv, Bounds box); 114 122 /** 115 123 * Return a representative small image for this layer. The image must not … … abstract public class Layer implements Destroyable, MapViewPaintable { 159 167 * to the layerlist dialog, because there may be no such dialog yet (loaded 160 168 * via command line parameter). 161 169 */ 170 @Override 162 171 public void destroy() {} 163 172 164 173 public File getAssociatedFile() { return associatedFile; } … … abstract public class Layer implements Destroyable, MapViewPaintable { 215 224 * @param visible true, if the layer is visible; false, otherwise. 216 225 */ 217 226 public void setVisible(boolean visible) { 218 boolean oldValue = this.visible;227 boolean oldValue = isVisible(); 219 228 this.visible = visible; 220 if (oldValue != this.visible) { 221 fireVisibleChanged(oldValue, this.visible); 229 if (visible && opacity == 0) { 230 setOpacity(1); 231 } else if (oldValue != isVisible()) { 232 fireVisibleChanged(oldValue, isVisible()); 222 233 } 223 234 } 224 235 … … abstract public class Layer implements Destroyable, MapViewPaintable { 227 238 * @return true if this layer is visible. False, otherwise. 228 239 */ 229 240 public boolean isVisible() { 230 return visible; 241 return visible && opacity != 0; 242 } 243 244 public double getOpacity() { 245 return opacity; 246 } 247 248 public void setOpacity(double opacity) { 249 if (!(opacity >= 0 && opacity <= 1)) 250 throw new IllegalArgumentException("Opacity value must be between 0 and 1"); 251 double oldOpacity = getOpacity(); 252 boolean oldVisible = isVisible(); 253 this.opacity = opacity; 254 if (oldOpacity != getOpacity()) { 255 fireOpacityChanged(oldOpacity, getOpacity()); 256 } 257 if (oldVisible != isVisible()) { 258 fireVisibleChanged(oldVisible, isVisible()); 259 } 231 260 } 232 261 233 262 /** … … abstract public class Layer implements Destroyable, MapViewPaintable { 266 295 } 267 296 268 297 /** 298 * fires a property change for the property {@see #OPACITY_PROP} 299 * 300 * @param oldValue the old value 301 * @param newValue the new value 302 */ 303 protected void fireOpacityChanged(double oldValue, double newValue) { 304 propertyChangeSupport.firePropertyChange(OPACITY_PROP, oldValue, newValue); 305 } 306 307 /** 269 308 * 270 309 * 271 310 * @return True if layer was changed since last paint
