/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.mapedit.gui; import illarion.mapedit.data.Map; import illarion.mapedit.events.map.*; import illarion.mapedit.render.RendererManager; import illarion.mapedit.tools.ToolManager; import illarion.mapedit.util.MouseButton; import illarion.mapedit.util.SwingLocation; import illarion.mapedit.util.Vector2i; import org.bushe.swing.event.EventBus; import org.bushe.swing.event.annotation.AnnotationProcessor; import org.bushe.swing.event.annotation.EventSubscriber; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The map panel is the area, on which the map is rendered. * * @author Tim */ public class MapPanel extends JPanel implements MouseWheelListener, MouseMotionListener, MouseListener, ComponentListener { private static final Logger LOGGER = LoggerFactory.getLogger(MapPanel.class); @Nonnull private final RendererManager rendererManager; @Nonnull private final Rectangle dirty; private boolean canDrag; private boolean isDragging; private int clickX; private int clickY; private int downClickX; private int downClickY; @Nonnull private final ToolManager toolManager; private final GuiController controller; public MapPanel(GuiController controller) { this.controller = controller; rendererManager = new RendererManager(); toolManager = new ToolManager(controller); dirty = new Rectangle(getWidth(), getHeight()); addMouseWheelListener(this); addMouseMotionListener(this); addMouseListener(this); addComponentListener(this); AnnotationProcessor.process(this); } @Override public void paintComponent(Graphics gt) { Graphics2D g = (Graphics2D) gt; g.setColor(Color.BLACK); g.fillRect(0, 0, getWidth(), getHeight()); List<Map> maps = new ArrayList<>(controller.getMaps()); Collections.sort(maps, (map1, map2) -> Integer.compare(map1.getZ(), map2.getZ())); maps.stream().filter(Map::isVisible).forEach(map -> rendererManager.render(map, getVisibleRect(), g)); dirty.x = 0; dirty.y = 0; dirty.width = 0; dirty.height = 0; } @Override public void mouseWheelMoved(@Nonnull MouseWheelEvent e) { if (controller.isMapLoaded()) { if (e.getWheelRotation() < 0) { rendererManager.zoomIn(new Vector2i(e.getX(), e.getY())); } else if (e.getWheelRotation() > 0) { rendererManager.zoomOut(new Vector2i(e.getX(), e.getY())); } } } @Override public void mouseDragged(@Nonnull MouseEvent e) { publishMapPosition(e); Map selected = controller.getSelected(); if (!canDrag || !controller.isMapLoaded() || (selected == null)) { return; } MouseButton btn = MouseButton.fromAwt(e.getModifiers()); if (btn == MouseButton.RightButton) { rendererManager.changeTranslation(e.getX() - clickX, e.getY() - clickY); } else { isDragging = true; if (btn == MouseButton.LeftButton) { int x = getMapCoordinateX(clickX, clickY, 0); int y = getMapCoordinateY(clickX, clickY, 0); int startX = getMapCoordinateX(downClickX, downClickY, 0); int startY = getMapCoordinateY(downClickX, downClickY, 0); if (selected.contains(x, y)) { EventBus.publish(new MapDraggedEvent(x, y, startX, startY, btn, selected)); } } } EventBus.publish(new RepaintRequestEvent()); clickX = e.getX(); clickY = e.getY(); } private void publishMapPosition(@Nonnull MouseEvent e) { Map selectedMap = controller.getSelected(); if (selectedMap == null) { return; } int mapX = getMapCoordinateX(e.getX(), e.getY(), selectedMap.getX()); int mapY = getMapCoordinateY(e.getX(), e.getY(), selectedMap.getY()); int worldX = selectedMap.getX() + mapX; int worldY = selectedMap.getY() + mapY; int worldZ = selectedMap.getZ(); EventBus.publish(new MapPositionEvent(mapX, mapY, worldX, worldY, worldZ)); } @Override public void mouseMoved(@Nonnull MouseEvent e) { publishMapPosition(e); } @Override public void mouseClicked(@Nonnull MouseEvent e) { Map selected = controller.getSelected(); if (selected == null) { return; } int x = getMapCoordinateX(e.getX(), e.getY(), selected.getX()); int y = getMapCoordinateY(e.getX(), e.getY(), selected.getY()); if (selected.contains(x, y)) { EventBus.publish(new MapClickedEvent(x, y, MouseButton.fromAwt(e.getModifiers()), selected)); } } @Override public void mousePressed(@Nonnull MouseEvent e) { if (canDrag && controller.isMapLoaded()) { clickX = e.getX(); clickY = e.getY(); downClickX = e.getX(); downClickY = e.getY(); } } @Override public void mouseReleased(@Nonnull MouseEvent e) { if (isDragging) { Map selected = controller.getSelected(); if (selected != null) { int x1 = getMapCoordinateX(downClickX, downClickY, selected.getX()); int y1 = getMapCoordinateY(downClickX, downClickY, selected.getY()); int x2 = getMapCoordinateX(e.getX(), e.getY(), selected.getX()); int y2 = getMapCoordinateY(e.getX(), e.getY(), selected.getY()); if ((x1 != x2) || (y1 != y2)) { EventBus.publish(new MapDragFinishedEvent(x1, y1, x2, y2, selected)); } } } isDragging = false; } private int getMapCoordinateX(int x, int y, int offset) { return SwingLocation.mapCoordinateX(x, y, rendererManager.getTranslationX(), rendererManager.getTranslationY(), rendererManager.getZoom()) - offset; } private int getMapCoordinateY(int x, int y, int offset) { return SwingLocation.mapCoordinateY(x, y, rendererManager.getTranslationX(), rendererManager.getTranslationY(), rendererManager.getZoom()) - offset; } @Override public void mouseEntered(MouseEvent e) { canDrag = true; } @Override public void mouseExited(MouseEvent e) { canDrag = false; } @Nonnull public RendererManager getRenderManager() { return rendererManager; } @Override public void componentResized(ComponentEvent e) { rendererManager.setPanelViewport(getVisibleRect()); } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { rendererManager.setPanelViewport(getVisibleRect()); } @Override public void componentHidden(ComponentEvent e) { } @EventSubscriber public void onRepaintRequest(@Nonnull RepaintRequestEvent e) { e.doRepaint(this); } }