- Timestamp:
- 2017-01-06T21:06:38+01:00 (8 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
r11425 r11434 17 17 import java.awt.event.MouseAdapter; 18 18 import java.awt.event.MouseEvent; 19 import java.awt.event.MouseMotionAdapter; 19 20 import java.awt.image.BufferedImage; 20 21 import java.beans.PropertyChangeEvent; … … 98 99 99 100 private MouseAdapter mouseAdapter; 101 private MouseMotionAdapter mouseMotionAdapter; 100 102 private MapModeChangeListener mapModeListener; 103 104 /** Mouse position where the last image was selected. */ 105 private Point lastSelPos; 106 107 /** 108 * Image cycle mode flag. 109 * It is possible that a mouse button release triggers multiple mouseReleased() events. 110 * To prevent the cycling in such a case we wait for the next mouse button press event 111 * before it is cycled to the next image. 112 */ 113 private boolean cycleModeArmed; 101 114 102 115 /** … … 468 481 } 469 482 483 /** 484 * Paint one image. 485 * @param e Image to be painted 486 * @param mv Map view 487 * @param clip Bounding rectangle of the current clipping area 488 * @param tempG Temporary offscreen buffer 489 */ 490 private void paintImage(ImageEntry e, MapView mv, Rectangle clip, Graphics2D tempG) { 491 if (e.getPos() == null) { 492 return; 493 } 494 Point p = mv.getPoint(e.getPos()); 495 if (e.hasThumbnail()) { 496 Dimension d = scaledDimension(e.getThumbnail()); 497 if (d != null) { 498 Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 499 if (clip.intersects(target)) { 500 tempG.drawImage(e.getThumbnail(), target.x, target.y, target.width, target.height, null); 501 } 502 } 503 } else { // thumbnail not loaded yet 504 icon.paintIcon(mv, tempG, 505 p.x - icon.getIconWidth() / 2, 506 p.y - icon.getIconHeight() / 2); 507 } 508 } 509 470 510 @Override 471 511 public void paint(Graphics2D g, MapView mv, Bounds bounds) { … … 495 535 if (data != null) { 496 536 for (ImageEntry e : data) { 497 if (e.getPos() == null) { 498 continue; 499 } 500 Point p = mv.getPoint(e.getPos()); 501 if (e.hasThumbnail()) { 502 Dimension d = scaledDimension(e.getThumbnail()); 503 if (d != null) { 504 Rectangle target = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 505 if (clip.intersects(target)) { 506 tempG.drawImage(e.getThumbnail(), target.x, target.y, target.width, target.height, null); 507 } 508 } 509 } else { // thumbnail not loaded yet 510 icon.paintIcon(mv, tempG, 511 p.x - icon.getIconWidth() / 2, 512 p.y - icon.getIconHeight() / 2); 513 } 537 paintImage(e, mv, clip, tempG); 538 } 539 if (currentPhoto >= 0 && currentPhoto < data.size()) { 540 // Make sure the selected image is on top in case multiple images overlap. 541 paintImage(data.get(currentPhoto), mv, clip, tempG); 514 542 } 515 543 } … … 602 630 603 631 /** 632 * Show current photo on map and in image viewer. 633 */ 634 public void showCurrentPhoto() { 635 clearOtherCurrentPhotos(); 636 if (currentPhoto >= 0) { 637 ImageViewerDialog.showImage(this, data.get(currentPhoto)); 638 } else { 639 ImageViewerDialog.showImage(this, null); 640 } 641 updateOffscreenBuffer = true; 642 Main.map.repaint(); 643 } 644 645 /** 604 646 * Shows next photo. 605 647 */ … … 610 652 currentPhoto = data.size() - 1; 611 653 } 612 ImageViewerDialog.showImage(this, data.get(currentPhoto));613 654 } else { 614 655 currentPhoto = -1; 615 656 } 616 Main.map.repaint();657 showCurrentPhoto(); 617 658 } 618 659 … … 626 667 currentPhoto = 0; 627 668 } 628 ImageViewerDialog.showImage(this, data.get(currentPhoto));629 669 } else { 630 670 currentPhoto = -1; 631 671 } 632 Main.map.repaint();672 showCurrentPhoto(); 633 673 } 634 674 … … 639 679 if (data != null && !data.isEmpty()) { 640 680 currentPhoto = 0; 641 ImageViewerDialog.showImage(this, data.get(currentPhoto));642 681 } else { 643 682 currentPhoto = -1; 644 683 } 645 Main.map.repaint();684 showCurrentPhoto(); 646 685 } 647 686 … … 652 691 if (data != null && !data.isEmpty()) { 653 692 currentPhoto = data.size() - 1; 654 ImageViewerDialog.showImage(this, data.get(currentPhoto));655 693 } else { 656 694 currentPhoto = -1; 657 695 } 658 Main.map.repaint();696 showCurrentPhoto(); 659 697 } 660 698 … … 670 708 currentPhoto = data.size() - 1; 671 709 } 672 if (currentPhoto >= 0) { 673 ImageViewerDialog.showImage(this, data.get(currentPhoto)); 674 } else { 675 ImageViewerDialog.showImage(this, null); 676 } 677 updateOffscreenBuffer = true; 678 Main.map.repaint(); 710 showCurrentPhoto(); 679 711 } 680 712 } … … 703 735 currentPhoto = data.size() - 1; 704 736 } 705 if (currentPhoto >= 0) {706 ImageViewerDialog.showImage(this, data.get(currentPhoto));707 } else {708 ImageViewerDialog.showImage(this, null);709 }710 737 711 738 if (Utils.deleteFile(toDelete.getFile())) { … … 720 747 } 721 748 722 updateOffscreenBuffer = true; 723 Main.map.repaint(); 749 showCurrentPhoto(); 724 750 } 725 751 } … … 744 770 745 771 /** 772 * Check if the position of the mouse event is within the rectangle of the photo icon or thumbnail. 773 * @param idx Image index, range 0 .. size-1 774 * @param evt Mouse event 775 * @return {@code true} if the photo matches the mouse position, {@code false} otherwise 776 */ 777 private boolean isPhotoIdxUnderMouse(int idx, MouseEvent evt) { 778 if (idx >= 0 && data != null && idx < data.size()) { 779 ImageEntry img = data.get(idx); 780 if (img.getPos() != null) { 781 Point imgCenter = Main.map.mapView.getPoint(img.getPos()); 782 Rectangle imgRect; 783 if (useThumbs && img.hasThumbnail()) { 784 Dimension imgDim = scaledDimension(img.getThumbnail()); 785 if (imgDim != null) { 786 imgRect = new Rectangle(imgCenter.x - imgDim.width / 2, 787 imgCenter.y - imgDim.height / 2, 788 imgDim.width, imgDim.height); 789 } else { 790 imgRect = null; 791 } 792 } else { 793 imgRect = new Rectangle(imgCenter.x - icon.getIconWidth() / 2, 794 imgCenter.y - icon.getIconHeight() / 2, 795 icon.getIconWidth(), icon.getIconHeight()); 796 } 797 if (imgRect != null && imgRect.contains(evt.getPoint())) { 798 return true; 799 } 800 } 801 } 802 return false; 803 } 804 805 /** 806 * Returns index of the image that matches the position of the mouse event. 807 * @param evt Mouse event 808 * @param cycle Set to {@code true} to cycle through the photos at the 809 * current mouse position if multiple icons or thumbnails overlap. 810 * If set to {@code false} the topmost photo will be used. 811 * @return Image index at mouse position, range 0 .. size-1, 812 * or {@code -1} if there is no image at the mouse position 813 */ 814 private int getPhotoIdxUnderMouse(MouseEvent evt, boolean cycle) { 815 if (data != null) { 816 if (cycle && currentPhoto >= 0) { 817 // Cycle loop is forward as that is the natural order. 818 // Loop 1: One after current photo up to last one. 819 for (int idx = currentPhoto + 1; idx < data.size(); ++idx) { 820 if (isPhotoIdxUnderMouse(idx, evt)) { 821 return idx; 822 } 823 } 824 // Loop 2: First photo up to current one. 825 for (int idx = 0; idx <= currentPhoto; ++idx) { 826 if (isPhotoIdxUnderMouse(idx, evt)) { 827 return idx; 828 } 829 } 830 } else { 831 // Check for current photo first, i.e. keep it selected if it is under the mouse. 832 if (currentPhoto >= 0 && isPhotoIdxUnderMouse(currentPhoto, evt)) { 833 return currentPhoto; 834 } 835 // Loop from last to first to prefer topmost image. 836 for (int idx = data.size() - 1; idx >= 0; --idx) { 837 if (isPhotoIdxUnderMouse(idx, evt)) { 838 return idx; 839 } 840 } 841 } 842 } 843 return -1; 844 } 845 846 /** 847 * Returns index of the image that matches the position of the mouse event. 848 * The topmost photo is picked if multiple icons or thumbnails overlap. 849 * @param evt Mouse event 850 * @return Image index at mouse position, range 0 .. size-1, 851 * or {@code -1} if there is no image at the mouse position 852 */ 853 private int getPhotoIdxUnderMouse(MouseEvent evt) { 854 return getPhotoIdxUnderMouse(evt, false); 855 } 856 857 /** 746 858 * Returns the image that matches the position of the mouse event. 859 * The topmost photo is picked of multiple icons or thumbnails overlap. 747 860 * @param evt Mouse event 748 861 * @return Image at mouse position, or {@code null} if there is no image at the mouse position … … 750 863 */ 751 864 public ImageEntry getPhotoUnderMouse(MouseEvent evt) { 752 if (data != null) { 753 for (int idx = data.size() - 1; idx >= 0; --idx) { 754 ImageEntry img = data.get(idx); 755 if (img.getPos() == null) { 756 continue; 757 } 758 Point p = Main.map.mapView.getPoint(img.getPos()); 759 Rectangle r; 760 if (useThumbs && img.hasThumbnail()) { 761 Dimension d = scaledDimension(img.getThumbnail()); 762 if (d != null) 763 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 764 else 765 r = null; 766 } else { 767 r = new Rectangle(p.x - icon.getIconWidth() / 2, 768 p.y - icon.getIconHeight() / 2, 769 icon.getIconWidth(), 770 icon.getIconHeight()); 771 } 772 if (r != null && r.contains(evt.getPoint())) { 773 return img; 774 } 775 } 776 } 777 return null; 865 int idx = getPhotoIdxUnderMouse(evt); 866 if (idx >= 0) { 867 return data.get(idx); 868 } else { 869 return null; 870 } 778 871 } 779 872 … … 849 942 if (isVisible() && isMapModeOk()) { 850 943 Main.map.mapView.repaint(); 944 cycleModeArmed = true; 851 945 } 852 946 } … … 859 953 return; 860 954 861 for (int i = data.size() - 1; i >= 0; --i) { 862 ImageEntry e = data.get(i); 863 if (e.getPos() == null) { 864 continue; 865 } 866 Point p = Main.map.mapView.getPoint(e.getPos()); 867 Rectangle r; 868 if (useThumbs && e.hasThumbnail()) { 869 Dimension d = scaledDimension(e.getThumbnail()); 870 if (d != null) 871 r = new Rectangle(p.x - d.width / 2, p.y - d.height / 2, d.width, d.height); 872 else 873 r = null; 874 } else { 875 r = new Rectangle(p.x - icon.getIconWidth() / 2, 876 p.y - icon.getIconHeight() / 2, 877 icon.getIconWidth(), 878 icon.getIconHeight()); 879 } 880 if (r != null && r.contains(ev.getPoint())) { 881 clearOtherCurrentPhotos(); 882 currentPhoto = i; 883 ImageViewerDialog.showImage(GeoImageLayer.this, e); 884 Main.map.repaint(); 885 break; 886 } 887 } 955 Point mousePos = ev.getPoint(); 956 boolean cycle = cycleModeArmed && lastSelPos != null && lastSelPos.equals(mousePos); 957 int idx = getPhotoIdxUnderMouse(ev, cycle); 958 if (idx >= 0) { 959 lastSelPos = mousePos; 960 cycleModeArmed = false; 961 currentPhoto = idx; 962 showCurrentPhoto(); 963 } 964 } 965 }; 966 967 mouseMotionAdapter = new MouseMotionAdapter() { 968 @Override 969 public void mouseMoved(MouseEvent evt) { 970 lastSelPos = null; 971 } 972 973 @Override 974 public void mouseDragged(MouseEvent evt) { 975 lastSelPos = null; 888 976 } 889 977 }; … … 892 980 if (newMapMode == null || isSupportedMapMode(newMapMode)) { 893 981 Main.map.mapView.addMouseListener(mouseAdapter); 982 Main.map.mapView.addMouseMotionListener(mouseMotionAdapter); 894 983 } else { 895 984 Main.map.mapView.removeMouseListener(mouseAdapter); 985 Main.map.mapView.removeMouseMotionListener(mouseMotionAdapter); 896 986 } 897 987 }; … … 918 1008 stopLoadThumbs(); 919 1009 Main.map.mapView.removeMouseListener(mouseAdapter); 1010 Main.map.mapView.removeMouseMotionListener(mouseMotionAdapter); 920 1011 MapFrame.removeMapModeChangeListener(mapModeListener); 921 1012 currentPhoto = -1;
Note:
See TracChangeset
for help on using the changeset viewer.