package test08;

//? class ColorShape

/**	File:	ShapeDraw.java
	
	@author Dr. Eck
	modifier yanushka

	The software contains the following classes:
	    Main
	    ShapeDraw extends JPanel
	    DrawingArea extends JPanel

	Main creates a JFrame object containing a ShapeDraw object.
	ShapeDraw manages a DrawingArea with a button for each concrete shape
	    and a JComboBox of colors.
	DrawingArea manages a collection of Shape objects using mouse events.

	The software uses 4 items in the package java.awt.geom.
	Shape is an interface. The abstract classes Rectangle2D, Ellipse2D and 
	RoundRectangle2D implement the Shape interface. The class Polygon
	in the package java.awt also implements the Shape interface.

	The software has no inner classes. Dr. Eck's version uses inner classes.
	His version also contains his own abstract class Shape with subclasses 
	of RectShape, OvalShape and RoundRectShape.
*/

import java.util.ArrayList;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
 
/**	The class Main constructs a JFrame object containing a ShapeDraw
	object.
*/
class Main {
 public static void main( String [] args ) {
     JFrame window = new JFrame( "Simple ShapeDraw" );
	ShapeDraw	shape = new ShapeDraw();
	shape.setOpaque( true );
     window.setContentPane( shape );
     window.setSize( new Dimension( 600, 400 ) );
     window.setLocation( 150, 100 );
     window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
     window.setVisible( true );
 }
}    

/**	The class ShapeDraw is a simple drawing program that lets the client 
	add shapes to a drawing area and drag them around. Java's classes
	Rectangle2D, Ellipse2D, RoundRectangle2D and Polygon implement the
	Shape interface.
*/
public class ShapeDraw extends JPanel {

 private static final String [] NAMES_COLORS = 
 { "Red", "Green", "Blue", "Cyan", "Magenta", "Pink", "Yellow", "Black", 
	"Gray", "Orange", "Light Gray" },
				   BUTTONS = 
	{ "Rect", "Oval", "RoundRect", "Polygon" };

 private JComboBox< String > colorChoice;  // the color selection menu

/**	Construct a ShapeDraw object.
     Set up the GUI, with a drawing area plus a row of controls below the
     drawing area. The controls include three buttons which are used
     to add shapes to the drawing area and a menu that is used to select
     the color of the shape when it is created. The constructor also
     sets up listeners to handle events from the controls.
*/
 public ShapeDraw() {  

     setBackground( Color.LIGHT_GRAY );

     DrawingArea canvas = new DrawingArea( this );  // create the canvas

     colorChoice = new JComboBox< String >( NAMES_COLORS );  
	    // color choice menu
     colorChoice.addActionListener( canvas );

     JPanel bottom = new JPanel();   // a JPanel to hold the control buttons
     bottom.setLayout( new GridLayout( 1, 4, 3, 3 ) );
	for ( int i = 0; i < BUTTONS.length; i++ ) {
	    // buttons for adding shapes
         JButton button = new JButton( BUTTONS[ i ] ); 
         button.addActionListener( canvas );
	    bottom.add( button );
	}
     bottom.add( colorChoice );

     setLayout( new BorderLayout( 3, 3 ) );
	//	Add canvas and bottom.
     add( canvas, BorderLayout.CENTER );
     add( bottom, BorderLayout.SOUTH );
 }

/**	@return the JComboBox attribute
*/
 public JComboBox getJComboBox() {
	return colorChoice;
 }
}

/** 	The DrawingArea class defines the drawing area.
	It represents a canvas that can display colored shapes and
	The client can drag a shape around. It uses an off-screen image in
	an ArrayList< Shape > object to make the dragging look as smooth 
	as possible.
*/
class DrawingArea extends JPanel
	    implements ActionListener, MouseListener, MouseMotionListener {

 private static final Color [] COLORS = 
 { Color.red, Color.green, Color.blue, Color.cyan, Color.magenta, Color.pink,
	Color.yellow, Color.black, Color.gray, Color.orange, Color.lightGray };

 private ShapeDraw 	shapeDraw;
 private ArrayList< Shape > shapes; 
 private ArrayList< Color > colors; 
 private Color 	currentColor;
	// current color; when a shape is created, this is its color

/**	Construct a DrawingArea object linked to the parameter.
	@param sd a ShapeDraw object 
	Set background color to white.
	Set up listeners to respond to mouse actions.
*/
 public DrawingArea( ShapeDraw sd ) {
	shapeDraw = sd;
	shapes = new ArrayList< Shape >();
	colors = new ArrayList< Color >();
	currentColor = Color.red;
     setBackground( Color.white );
     addMouseListener( this );
     addMouseMotionListener( this );
 }   

/**	Customize Java's paintComponent() method.
     @param g a Graphics object for drawing
	Draw each shape in the ArrayList attribute.
*/
 public void paintComponent( Graphics g ) {
     g.setColor( Color.WHITE );
     g.fillRect( 0, 0, getSize().width, getSize().height );
	Graphics2D 	g2 = ( Graphics2D )g;
	// Note: Antialiasing produces better shapes but reduces speed.
	g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, 
			 	RenderingHints.VALUE_ANTIALIAS_ON );
	int i = 0;
     for ( Shape s : shapes ) {
	    g2.setColor( colors.get( i++ ) );
         g2.fill( s );
	    g2.setColor( Color.black );
         g2.draw( s );
	}
	// Draw a black border around the edge of the drawing area.
     g.setColor( Color.BLACK );  
     g.drawRect( 0, 0, getWidth() - 1, getHeight() - 1 );
 }   

/**	Respond to action events. Each of the three shape-adding buttons and a
	selection from the color menu sends an action event to this canvas. 
	Respond by adding the appropriate shape to the canvas.
*/
 public void actionPerformed( ActionEvent evt ) {
     if ( evt.getSource() instanceof JComboBox ) {
	    JComboBox	colorChoice = shapeDraw.getJComboBox();
	    currentColor = COLORS[ colorChoice.getSelectedIndex() ];
     } else {
         String command = evt.getActionCommand();
         if ( command.equals( "Rect" ) )
             addShape( "Rect" );
         else if ( command.equals( "Oval" ) )
             addShape( "Oval" );
         else if ( command.equals( "RoundRect" ) )
             addShape( "RoundRect" );
         else if ( command.equals( "Polygon" ) )
             addShape( "Polygon" );
     }
 }

/** 	Add the shape to the canvas and set its size, position and color 
	randomly. Then redraw the canvas to show the newly added shape.
*/
 public void addShape( String command ) {
     // Randomize shape.
     int	width = getWidth(),
		height = getHeight(),
		left = 3 + ( int )( width * Math.random() / 2 ),
		top = 3 + ( int )( height * Math.random() / 2 ),
		shapeW = Math.min( 80, 
			     20 + ( int )( ( width - left ) * Math.random() ) ),
		shapeH = Math.min( 50, 
			     20 + ( int )( ( height - top ) * Math.random() ) ),
		arcW = Math.max( shapeW / 10, 20 ),
		arcH = Math.max( shapeH / 10, 20 );
	Shape	shape = null;
	if ( command.equals( "Rect" ) )
         shape = new Rectangle2D.Double( left, top, shapeW, shapeH );
	else if ( command.equals( "RoundRect" ) )
         shape = new RoundRectangle2D.Double( left, top, shapeW, shapeH, 
						 arcW, arcH );
	else if ( command.equals( "Oval" ) )
         shape = new Ellipse2D.Double( left, top, shapeW, shapeH );
	else if ( command.equals( "Polygon" ) )
	    shape = makePolygon();

	if ( shape != null ) {
         shapes.add( shape );
	    colors.add( currentColor );
	}
     repaint();
 }

 private Polygon makePolygon() {
	int 	n = 3 + ( int )( 8 * Math.random() ),
		side = 20 + ( int )( 40 * Math.random() ),
         	width = getWidth(),
		height = getHeight(),
		xCtr = 20 + ( int )( ( width - side ) * Math.random() ),
		yCtr = 20 + ( int )( ( height - side ) * Math.random() );
	Polygon	poly = new Polygon();
	double	angle = 0,
		delAngle = 2 * Math.PI / n;

	for ( int i = 0; i < n; i++, angle += delAngle )
	    poly.addPoint( xCtr + ( int )( side * Math.cos( angle ) ),
			   yCtr - ( int )( side * Math.sin( angle ) ) );
			   
	return poly;
 }

//	The rest of this class implements dragging. 

 private Shape shapeBeingDragged = null;  
/** 	This is null unless a shape is being dragged. A non-null value signals 
 	that dragging is in progress and indicates which shape is being dragged.
*/

 private int prevDragX;  
 private int prevDragY;  
/** 	During dragging, these record the x and y coordinates of the
	previous position of the mouse.
*/

/**	Respond to a mouse pressed event.
	@param evt a MouseEvent object.
	Find the shape on which the client has clicked, if any.  
	If there is a shape at the position where the mouse was clicked, then
	start dragging it. If the client was holding down the shift key, 
	then bring the dragged shape to the front, in front of all the other 
	shapes.
*/
 public void mousePressed( MouseEvent evt ) {
     int x = evt.getX();  // x-coordinate of point where mouse was clicked
     int y = evt.getY();  // y-coordinate of point 
	int	shapeCount = shapes.size();
	boolean	looking = true;
	// Check shapes from front to back.
     for ( int i = shapeCount - 1; ( i >= 0 ) && looking; i-- ) {  
         Shape s = shapes.get( i );
         if ( s.contains( x, y ) ) {
             shapeBeingDragged = s;
             prevDragX = x;
             prevDragY = y;
             if ( evt.isShiftDown() ) { 
		    // Move shape s on top of all the other shapes by
		    // moving s to the end of the list.
		    int ndx = shapes.indexOf( s );
		    // System.out.println( s + " " + ndx );
		    shapes.remove( s );
		    Color c = colors.get( ndx );
		    colors.remove( ndx );
		    shapes.add( s );
		    colors.add( c );
		    // Repaint the canvas to show s in front of other shapes.
                 repaint();  
             }
             looking = false;
         }
     }
 }

/**	Respond to a mouse dragged event.
	@param evt a MouseEvent object.
	Client has moved the mouse. Move the dragged shape by the same amount.
*/
 public void mouseDragged( MouseEvent evt ) {
     int x = evt.getX();
     int y = evt.getY();
     if ( shapeBeingDragged != null ) {
         // shapeBeingDragged.moveBy( x - prevDragX, y - prevDragY );
         move( shapeBeingDragged, x - prevDragX, y - prevDragY );
         prevDragX = x;
         prevDragY = y;
	    // Redraw the canvas to show shape in new position.
         repaint();      
     }
 }

/**	Move the Shape s in the x direction dx pixels and in the y direction
	dy pixels.
	@param s a Shape object to move
	@param dx an integer for the number of pixels to move horizontally
	@param dy an integer for the number of pixels to move vertically
*/
 private void move( Shape s, int dx, int dy ) {
	if ( s instanceof Rectangle2D ) {
	    Rectangle2D r = ( Rectangle2D )s;
	    r.setFrame( r.getX() + dx, r.getY() + dy, 
			r.getWidth(), r.getHeight () );
	} else if ( s instanceof RoundRectangle2D ) {
	    RoundRectangle2D r = ( RoundRectangle2D )s;
	    r.setFrame( r.getX() + dx, r.getY() + dy, 
			r.getWidth(), r.getHeight () );
	} else if ( s instanceof Ellipse2D ) {
	    Ellipse2D r = ( Ellipse2D )s;
	    r.setFrame( r.getX() + dx, r.getY() + dy, 
			r.getWidth(), r.getHeight () );
	} else if ( s instanceof Polygon ) {
	    Polygon r = ( Polygon )s;
	    r.translate( dx, dy );
	}
 }

/**	Respond to a mouse released event.
	@param evt a MouseEvent object.
	Client has released the mouse. Move the dragged shape then set
	shapeBeingDragged to null to indicate that dragging is over.
*/
 public void mouseReleased( MouseEvent evt ) {
     int x = evt.getX();
     int y = evt.getY();
     if ( shapeBeingDragged != null ) {
         // shapeBeingDragged.moveBy( x - prevDragX, y - prevDragY );
	    move( shapeBeingDragged, x - prevDragX, y - prevDragY );
         shapeBeingDragged = null;
         repaint();
     }
 }

//Other methods required for MouseListener and MouseMotionListener interfaces.
 public void mouseEntered( MouseEvent evt ) {}   
 public void mouseExited( MouseEvent evt ) {}    
 public void mouseMoved( MouseEvent evt ) {}
 public void mouseClicked( MouseEvent evt ) {}
}