/*
* This file is part of MazeSolver.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (c) 2014 MazeSolver
* Sergio M. Afonso Fumero <theSkatrak@gmail.com>
* Kevin I. Robayna Hernández <kevinirobaynahdez@gmail.com>
*/
/**
* @file EnvironmentEditionPanel.java
* @date 1/10/2015
*/
package es.ull.mazesolver.gui.environment;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import es.ull.mazesolver.maze.Maze;
import es.ull.mazesolver.util.Direction;
import es.ull.mazesolver.util.Pair;
/**
* Clase que permite dibujar un laberinto, marcando en otro color la pared bajo
* la que se encuentra el cursor en todo momento.
*/
public class EnvironmentEditionPanel extends EnvironmentPanel {
private static final long serialVersionUID = 1L;
private static final double WALL_THICKNESS = 0.15;
private static final double WALL_SELECT_THICKNESS = 0.25;
private Pair <Point, Direction> m_hovered;
/**
* Crea un nuevo panel de dibujo de entornos del entorno especificado.
*
* @param env
* Entorno que se dibujará en el panel.
*/
public EnvironmentEditionPanel (Environment env) {
super(env);
m_hovered = null;
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved (MouseEvent e) {
m_hovered = getWallAt(e.getPoint());
repaint();
super.mouseMoved(e);
}
});
}
/**
* Devuelve la pared que hay bajo las coordenadas de pantalla (local al panel)
* indicadas.
*
* @param pos
* Coordenadas de pantalla.
* @return La celda y dirección en la que se encuentra la pared. Devuelve
* {@code null} si en esa posición no se está seleccionando ninguna pared.
*/
public Pair <Point, Direction> getWallAt (final Point pos) {
Point grid = screenCoordToGrid(pos);
Point grid_scr = gridCoordToScreen(grid);
double cell_sz = getCellSize();
Direction closest_dir = Direction.NONE;
// Miramos si las coordenadas están suficientemente cerca de uno de los
// bordes de la celda
if (pos.y <= grid_scr.y + WALL_SELECT_THICKNESS * cell_sz)
closest_dir = Direction.UP;
else if (pos.y >= grid_scr.y + (1.0 - WALL_SELECT_THICKNESS) * cell_sz)
closest_dir = Direction.DOWN;
else if (pos.x <= grid_scr.x + WALL_SELECT_THICKNESS * cell_sz)
closest_dir = Direction.LEFT;
else if (pos.x >= grid_scr.x + (1.0 - WALL_SELECT_THICKNESS) * cell_sz)
closest_dir = Direction.RIGHT;
Pair <Point, Direction> result = null;
if (closest_dir != Direction.NONE) {
Maze maze = m_env.getMaze();
// Si alguna de las celdas adyacentes a la pared está dentro del
// laberinto, la usamos junto a la dirección para definir la pared
if (maze.containsPoint(grid))
result = new Pair<>(grid, closest_dir);
else {
Point adj = closest_dir.movePoint(grid);
if (maze.containsPoint(adj))
result = new Pair<>(adj, closest_dir.getOpposite());
}
}
return result;
}
/* (non-Javadoc)
* @see es.ull.mazesolver.gui.environment.EnvironmentPanel#paintComponent(java.awt.Graphics)
*/
@Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
if (m_hovered != null) {
Point pos = gridCoordToScreen(m_hovered.first);
Direction dir = m_hovered.second;
double cell_sz = getCellSize();
double wall_sz = WALL_THICKNESS * cell_sz;
g.setColor(Color.RED);
if (dir.isVertical()) {
double y = dir == Direction.UP? pos.y : pos.y + cell_sz;
g.fillRect((int) Math.round(pos.x - wall_sz / 2),
(int) Math.round(y - wall_sz),
(int) Math.round(cell_sz + wall_sz),
(int) Math.round(2 * wall_sz));
}
else {
double x = dir == Direction.LEFT? pos.x : pos.x + cell_sz;
g.fillRect((int) Math.round(x - wall_sz),
(int) Math.round(pos.y - wall_sz / 2),
(int) Math.round(2 * wall_sz),
(int) Math.round(cell_sz + wall_sz));
}
}
}
}