/* * Copyright (C) 2014 James Lawrence. * * This file is part of GrimEdi. * * GrimEdi 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/>. */ package com.sqrt4.grimedi.ui.component; import com.sqrt.liblab.threed.Angle; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.*; import java.util.LinkedList; import java.util.List; /** * Created by James on 01/10/2014. */ public class RadialAngleChooser extends JPanel implements MouseListener, MouseWheelListener, MouseMotionListener { private final List<ChangeListener> listeners = new LinkedList<>(); // angle, between -180 and 180 private float angle; public RadialAngleChooser() { addMouseListener(this); addMouseWheelListener(this); addMouseMotionListener(this); } public void setAngle(float angle) { this.angle = Angle.normalize(angle, -180f); repaint(); if(listeners.isEmpty()) return; ChangeEvent ce = new ChangeEvent(this); synchronized (listeners) { for (ChangeListener cl : listeners) { cl.stateChanged(ce); } } } public float getAngle() { return angle; } public void addChangeListener(ChangeListener cl) { synchronized (listeners) { listeners.add(cl); } } public void removeChangeListener(ChangeListener cl) { synchronized (listeners) { listeners.remove(cl); } } public void paint(Graphics g) { super.paint(g); Color fg = isEnabled()? getForeground(): getBackground().darker(); g.setColor(fg); // Draw circle final int border = 4; Dimension d = getSize(); int diam = Math.min(d.width, d.height) - border; int dX = d.width - diam; int dY = d.height - diam; int x = dX == 0? 0: dX/2; int y = dY == 0? 0: dY/2; g.drawOval(x, y, diam, diam); // Draw indicator int r = diam/2; int cX = d.width/2; int cY = d.height/2; double rad = Math.toRadians(angle); int eX = cX + (int) (Math.sin(rad) * r); int eY = cY - (int) (Math.cos(rad) * r); g.drawLine(cX, cY, eX, eY); } private void setAngleFromMouse(MouseEvent e) { if(!isEnabled()) return; int x = e.getX(); int y = e.getY(); int cX = getWidth()/2; int cY = getHeight()/2; double deg = Math.toDegrees(Math.atan2(y - cY, x - cX)) + 90; setAngle((float) deg); } @Override public void mouseClicked(MouseEvent e) { setAngleFromMouse(e); } @Override public void mousePressed(MouseEvent e) { setAngleFromMouse(e); } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseWheelMoved(MouseWheelEvent e) { if (e.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) return; int i = e.getUnitsToScroll(); setAngle(angle + i); } @Override public void mouseDragged(MouseEvent e) { setAngleFromMouse(e); } @Override public void mouseMoved(MouseEvent e) { } }