No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MapZoomControls.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package org.insa.graphics.drawing.components;
  2. import java.awt.BasicStroke;
  3. import java.awt.Color;
  4. import java.awt.Component;
  5. import java.awt.Cursor;
  6. import java.awt.Graphics2D;
  7. import java.awt.Image;
  8. import java.awt.Point;
  9. import java.awt.Rectangle;
  10. import java.awt.event.ActionEvent;
  11. import java.awt.event.ActionListener;
  12. import java.awt.event.MouseAdapter;
  13. import java.awt.event.MouseEvent;
  14. import java.awt.image.ImageObserver;
  15. import java.io.IOException;
  16. import java.util.ArrayList;
  17. import java.util.List;
  18. import javax.imageio.ImageIO;
  19. public class MapZoomControls {
  20. // Default ID for action events
  21. private static final int ZOOM_IN_ACTION_ID = 0x1;
  22. private static final String ZOOM_IN_ACTION_NAME = "ZoomIn";
  23. private static final int ZOOM_OUT_ACTION_ID = 0x2;
  24. private static final String ZOOM_OUT_ACTION_NAME = "ZoomOut";
  25. // Height
  26. private static final int DEFAULT_HEIGHT = 20;
  27. // Default spacing between mark
  28. private static final int DEFAULT_SPACING = 4;
  29. // Zoom ticks ratio from height (not the current one)
  30. private static final double ZOOM_TICK_HEIGHT_RATIO = 0.3;
  31. // Zoom ticks color
  32. private static final Color ZOOM_TICK_COLOR = Color.GRAY;
  33. // Current zoom ticks ratio from height
  34. private static final double CURRENT_ZOOM_TICK_HEIGHT_RATIO = 0.8;
  35. // Zoom ticks color
  36. private static final Color CURRENT_ZOOM_TICK_COLOR = new Color(25, 25, 25);
  37. // Use half mark or not
  38. private boolean halfMark = true;
  39. private int currentLevel = 0;
  40. private final int minLevel, maxLevel;
  41. // Zoom in/out image and their rectangles.
  42. private final Image zoomIn, zoomOut;
  43. private final Rectangle zoomInRect = new Rectangle(0, 0, 0, 0),
  44. zoomOutRect = new Rectangle(0, 0, 0, 0);
  45. // List of listeners
  46. private final List<ActionListener> zoomInListeners = new ArrayList<>();
  47. private final List<ActionListener> zoomOutListeners = new ArrayList<>();
  48. public MapZoomControls(Component component, final int defaultZoom, final int minZoom,
  49. final int maxZoom) throws IOException {
  50. zoomIn = ImageIO.read(getClass().getResourceAsStream("/zoomIn.png"))
  51. .getScaledInstance(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Image.SCALE_SMOOTH);
  52. zoomOut = ImageIO.read(getClass().getResourceAsStream("/zoomOut.png"))
  53. .getScaledInstance(DEFAULT_HEIGHT, DEFAULT_HEIGHT, Image.SCALE_SMOOTH);
  54. this.currentLevel = defaultZoom;
  55. this.minLevel = minZoom;
  56. this.maxLevel = maxZoom;
  57. component.addMouseMotionListener(new MouseAdapter() {
  58. @Override
  59. public void mouseMoved(MouseEvent e) {
  60. if (zoomInRect.contains(e.getPoint()) || zoomOutRect.contains(e.getPoint())) {
  61. component.setCursor(new Cursor(Cursor.HAND_CURSOR));
  62. }
  63. else {
  64. component.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
  65. }
  66. }
  67. });
  68. component.addMouseListener(new MouseAdapter() {
  69. @Override
  70. public void mouseClicked(MouseEvent e) {
  71. if (zoomInRect.contains(e.getPoint()) && currentLevel < maxLevel) {
  72. currentLevel += 1;
  73. for (ActionListener al: zoomInListeners) {
  74. al.actionPerformed(
  75. new ActionEvent(this, ZOOM_IN_ACTION_ID, ZOOM_IN_ACTION_NAME));
  76. }
  77. }
  78. else if (zoomOutRect.contains(e.getPoint()) && currentLevel > minLevel) {
  79. currentLevel -= 1;
  80. for (ActionListener al: zoomOutListeners) {
  81. al.actionPerformed(
  82. new ActionEvent(this, ZOOM_OUT_ACTION_ID, ZOOM_OUT_ACTION_NAME));
  83. }
  84. }
  85. component.repaint();
  86. }
  87. });
  88. }
  89. /**
  90. * Add a zoom-in listener.
  91. *
  92. * @param listener Zoom-in listener to add to this MapZoomControls instance.
  93. */
  94. public void addZoomInListener(ActionListener listener) {
  95. this.zoomInListeners.add(listener);
  96. }
  97. /**
  98. * Add a zoom-out listener.
  99. *
  100. * @param listener Zoom-out listener to add to this MapZoomControls instance.
  101. */
  102. public void addZoomOutListener(ActionListener listener) {
  103. this.zoomOutListeners.add(listener);
  104. }
  105. /**
  106. * @return the current zoom level.
  107. */
  108. public int getZoomLevel() {
  109. return this.currentLevel;
  110. }
  111. /**
  112. * Set the current zoom level without requesting a redraw.
  113. *
  114. * @param level Zoom level to set.
  115. */
  116. public void setZoomLevel(int level) {
  117. this.currentLevel = level;
  118. }
  119. /**
  120. * @return Height of this "component" when drawn.
  121. */
  122. public int getHeight() {
  123. return DEFAULT_HEIGHT;
  124. }
  125. /**
  126. * @return Width of this "component" when drawn.
  127. */
  128. public int getWidth() {
  129. return DEFAULT_HEIGHT + 2 + (this.maxLevel - this.minLevel) * DEFAULT_SPACING + 1 + 2
  130. + DEFAULT_HEIGHT;
  131. }
  132. /**
  133. * Check if a point is contained inside an element of this zoom controls, useful
  134. * to avoid spurious click listeners.
  135. *
  136. * @param point Point to check.
  137. *
  138. * @return true if the given point correspond to an element of this zoom
  139. * controls.
  140. */
  141. public boolean contains(Point point) {
  142. return zoomInRect.contains(point) || zoomOutRect.contains(point);
  143. }
  144. protected void draw(Graphics2D g, int xoffset, int yoffset, ImageObserver observer) {
  145. int height = getHeight();
  146. // Draw icon
  147. g.drawImage(zoomOut, xoffset, yoffset, observer);
  148. zoomOutRect.setBounds(xoffset, yoffset, DEFAULT_HEIGHT, DEFAULT_HEIGHT);
  149. g.setStroke(new BasicStroke(1));
  150. // Draw ticks
  151. xoffset += DEFAULT_HEIGHT + 2;
  152. g.setColor(ZOOM_TICK_COLOR);
  153. g.drawLine(xoffset, yoffset + height / 2,
  154. xoffset + (this.maxLevel - this.minLevel) * DEFAULT_SPACING + 1,
  155. yoffset + height / 2);
  156. for (int i = 0; i <= (this.maxLevel - this.minLevel); i += halfMark ? 2 : 1) {
  157. g.drawLine(xoffset + i * DEFAULT_SPACING,
  158. yoffset + (int) (height * (1 - ZOOM_TICK_HEIGHT_RATIO) / 2),
  159. xoffset + i * DEFAULT_SPACING,
  160. yoffset + (int) (height * (1 + ZOOM_TICK_HEIGHT_RATIO) / 2));
  161. }
  162. // Draw current ticks
  163. g.setColor(CURRENT_ZOOM_TICK_COLOR);
  164. g.drawLine(xoffset + (currentLevel - this.minLevel) * DEFAULT_SPACING,
  165. yoffset + (int) (height * (1 - CURRENT_ZOOM_TICK_HEIGHT_RATIO) / 2),
  166. xoffset + (currentLevel - this.minLevel) * DEFAULT_SPACING,
  167. yoffset + (int) (height * (1 + CURRENT_ZOOM_TICK_HEIGHT_RATIO) / 2));
  168. xoffset += (this.maxLevel - this.minLevel) * DEFAULT_SPACING + 1 + 2;
  169. g.drawImage(zoomIn, xoffset, yoffset, observer);
  170. zoomInRect.setBounds(xoffset, yoffset, DEFAULT_HEIGHT, DEFAULT_HEIGHT);
  171. }
  172. }