/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotoolkit.gui.swing.render3d.control; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import org.geotoolkit.display3d.scene.camera.TrackBallCamera; /** * @author Thomas Rouby (Geomatys) */ public class JMoveControlDecoration extends JComponent implements PropertyChangeListener { private final TrackBallCamera camera; private static final int ARROW_SIZE = 8; private static final int RADIUS = 25; private static final int[] MARGIN = new int[]{17,5,17,5}; // left, bottom, right, top private static final int[] CENTER = new int[]{MARGIN[0]+RADIUS, MARGIN[3]+RADIUS}; // CENTER on X, on Y private static final int[] SIZE = new int[]{MARGIN[0]+MARGIN[2]+RADIUS*2, MARGIN[1]+MARGIN[3]+RADIUS*2}; // WIDTH, HEIGHT private final Color teinteDark; private final Color teinteLight; private final Color text1; private final Color text2; private final Shape cercle; private final Shape arrow; private final BufferedImage buffer = new BufferedImage(SIZE[0], SIZE[1], BufferedImage.TYPE_INT_ARGB); private boolean mustUpdate = true; /** * -1 = no button * 0 = top * 1 = right * 2 = down * 3 = left */ private short overButton = -1; public JMoveControlDecoration(TrackBallCamera camera) { this.camera = camera; this.camera.addPropertyChangeListener(this); teinteDark = Color.LIGHT_GRAY; teinteLight = Color.WHITE; text1 = Color.DARK_GRAY; text2 = Color.GRAY; addMouseListener(mouseListener); addMouseMotionListener(mouseMotionListener); setOpaque(false); cercle = new java.awt.geom.Ellipse2D.Float(CENTER[0]-RADIUS, CENTER[1]-RADIUS, RADIUS*2, RADIUS*2); arrow = new Polygon(new int[]{0, ARROW_SIZE, ARROW_SIZE / 2 }, new int[]{ARROW_SIZE , ARROW_SIZE , 0}, 3); } @Override public void propertyChange(PropertyChangeEvent evt) { //camera event } @Override protected void paintComponent(final Graphics g) { super.paintComponent(g); final Graphics2D g2d = (Graphics2D) g; final Rectangle clip = g2d.getClipBounds(); if(!clip.intersects(0,0,SIZE[0],SIZE[1])) return; if(mustUpdate){ final Graphics2D g2 = buffer.createGraphics(); g2.setStroke(new BasicStroke(1)); g2.setFont(g2d.getFont().deriveFont(Font.BOLD)); g2.setBackground(new Color(0f,0f,0f,0f)); g2.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); g2.setRenderingHints(g2d.getRenderingHints()); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final float[] dist = {0.5f, 1.0f}; final Color[] colors = {teinteLight, teinteDark}; final RadialGradientPaint paint = new RadialGradientPaint(new Point2D.Float(CENTER[0], CENTER[1]), RADIUS, dist, colors); g2.setPaint(paint); g2.fillOval(CENTER[0]-RADIUS, CENTER[1]-RADIUS, RADIUS*2, RADIUS*2); //draw arrows final int topX = CENTER[0] - ARROW_SIZE/2; final int topY = CENTER[1] - (int)(0.8*RADIUS); g2.translate(topX,topY); g2.setColor((overButton==0) ? text1 : text2); g2.fill(arrow); g2.translate( -topX, -topY); g2.rotate(Math.PI/2, CENTER[0], CENTER[1]); g2.translate(topX, topY); g2.setColor((overButton==1) ? text1 : text2); g2.fill(arrow); g2.translate( -topX, -topY); g2.rotate(Math.PI/2, CENTER[0], CENTER[1]); g2.translate(topX, topY); g2.setColor((overButton==2) ? text1 : text2); g2.fill(arrow); g2.translate( -topX, -topY); g2.rotate(Math.PI/2, CENTER[0], CENTER[1]); g2.translate(topX, topY); g2.setColor((overButton==3) ? text1 : text2); g2.fill(arrow); g2.translate( -topX, -topY); g2.rotate(Math.PI/2, CENTER[0], CENTER[1]); mustUpdate = false; } g2d.drawImage(buffer, 0, 0, this); g2d.dispose(); } private void moveUp(){ camera.moveFront(10.0f*(float)camera.getViewScale(camera.getLength())); } private void moveDown(){ camera.moveBack(10.0f*(float)camera.getViewScale(camera.getLength())); } private void moveLeft(){ camera.moveLeft(10.0f*(float)camera.getViewScale(camera.getLength())); } private void moveRight(){ camera.moveRight(10.0f*(float)camera.getViewScale(camera.getLength())); } @Override public boolean contains(final int x, final int y) { return cercle.contains(x,y); } private final MouseListener mouseListener = new MouseListener() { @Override public void mouseClicked(final MouseEvent e) { } @Override public void mousePressed(final MouseEvent e) { final Point mouse = e.getPoint(); if(!cercle.contains(mouse)) return; final double tx = mouse.x - CENTER[0] ; final double ty = mouse.y - CENTER[1] ; if(Math.abs(tx)!=Math.abs(ty)) { if (tx>ty && -tx>ty) { moveUp(); } else if (tx<ty && -tx<ty) { moveDown(); } else if (tx<ty && -tx>ty) { moveLeft(); } else if (tx>ty && -tx<ty) { moveRight(); } camera.updateCameraElevation(); } } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { if(overButton !=-1){ overButton = -1; mustUpdate = true; repaint(cercle.getBounds()); } } }; private final MouseMotionListener mouseMotionListener = new MouseMotionListener() { @Override public void mouseDragged(final MouseEvent e) { } @Override public void mouseMoved(final MouseEvent e) { final Point mouse = e.getPoint(); if(cercle.contains(mouse)){ final double tx = mouse.x - CENTER[0] ; final double ty = mouse.y - CENTER[1] ; final int oldOver = overButton; if (tx>ty && -tx>ty) { overButton = 0; } else if (tx<ty && -tx<ty) { overButton = 2; } else if (tx<ty && -tx>ty) { overButton = 3; } else if (tx>ty && -tx<ty) { overButton = 1; } if(oldOver != overButton){ mustUpdate = true; repaint(cercle.getBounds()); } } else if (overButton != -1){ overButton = -1; mustUpdate = true; repaint(cercle.getBounds()); } } }; @Override public Dimension getPreferredSize() { return new Dimension(buffer.getWidth(),buffer.getHeight()); } @Override public Dimension getSize() { return getPreferredSize(); } @Override public Dimension getSize(final Dimension rv) { if(rv != null){ rv.height = buffer.getHeight(); rv.width = buffer.getWidth(); return rv; }else{ return getSize(); } } @Override public int getWidth() { return this.getSize().width; } @Override public int getHeight() { return this.getSize().height; } }