/* * @(#)DraggingArea.java Version 1.0 98/03/12 * * Copyright (c) 1998 by Huahai Yang * * Use at your own risk. I do not guarantee the fitness of this * software for any purpose, and I do not accept responsibility for * any damage you do to yourself or others by using this software. * This file may be distributed freely, provided its contents * are not tampered with in any way. * */ import java.awt.*; import java.applet.*; import java.awt.event.*; import java.util.*; import java.lang.Math; /** * Main playing area. Cards and operators are put on it and can be * dragged around. Card deck is also put on it and caculate solutions * in a seperate thread. */ public class DraggingArea extends Panel implements Runnable { Thread dragThread; Applet applet; Dimension offScreenDimension; Image offScreenImage; Graphics offScreenGraphics; Image[] cardImages, operatorImages; Image cardDeckImage; MediaTracker tracker; int imageCount; CardDeck cardDeck; PlayingStatus status; Card [] currentCards; Operator [] operators; DraggingSlot [] draggingSlots; Vector dragImages; DraggingImage theMoving; Point grabPoint; Cursor defaultCursor, handCursor; int updateLeft, updateTop, updateRight, updateBottom; boolean animating; public DraggingArea() { setLayout(null); setForeground(new Color(0)); setBackground(new Color(32768)); handCursor = new Cursor(Cursor.HAND_CURSOR); defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR); addMouseListener(new MyMouseAdapter()); addMouseMotionListener(new MyMouseMotionAdapter()); } // constructor public void start() { applet = (Applet)getParent(); loadAllImages(); status = new PlayingStatus(); status.addObserver((Arithmetic24)applet); status.set(PlayingStatus.WAITING); animating = false; dragImages = new Vector(); theMoving = null; grabPoint = new Point(); // add cardDeck and run a seperate thread to calculate all of // this deck's 13 deal's solutions cardDeck = new CardDeck(30, 10, cardDeckImage, this); dragImages.addElement(cardDeck); // create offscreen context Dimension d = size(); if ( (offScreenGraphics == null) || (d.width != offScreenDimension.width) || (d.height != offScreenDimension.height) ) { offScreenDimension = d; offScreenImage = createImage(d.width, d.height); offScreenGraphics = offScreenImage.getGraphics(); } // if resetClip(); // add slots addSlots(); currentCards = new Card [4]; operators = new Operator [18]; // add operators, each operator has 3 copies // arrange operaters this way: // + * ( // - / ) int count = 0; for(int i = 0; i < 3; i++) { for(int j = 0; j < 6; j++) { dragImages.addElement( operators[count++] = new Operator( j, 510 + j / 2 * 30, 15 + j % 2 * 45, operatorImages[j], this ) ); } // for j } // for i if (dragThread == null) { dragThread = new Thread(this, "Dragging"); dragThread.start(); } // if } // start /** * put operaters back to original positions */ public void arrangeOperators() { for(int i = 0; i < 13; i++) { if(draggingSlots[i] instanceof OperatorSlot) { draggingSlots[i].empty(); } // if } // for for(int i = 0; i < 18; i++) { operators[i]. setLocation(510 + i % 6 / 2 * 30, 15 + i % 6 % 2 * 45); } // for } //arrangeOperators // solts arranged like this: // o c o o c o o o c o o c o // "o" is operator slot, "c" is card slot protected void addSlots() { int widthPointer; DraggingSlot slotPointer = null; draggingSlots = new DraggingSlot [13]; slotPointer = draggingSlots[0] = new OperatorSlot(10, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[1] = new CardSlot(widthPointer + 6, 130); widthPointer = slotPointer.getLocation().x + CardSlot.WIDTH; slotPointer = draggingSlots[2] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[3] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[4] = new CardSlot(widthPointer + 6, 130); widthPointer = slotPointer.getLocation().x + CardSlot.WIDTH; slotPointer = draggingSlots[5] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[6] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[7] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[8] = new CardSlot(widthPointer + 6, 130); widthPointer = slotPointer.getLocation().x + CardSlot.WIDTH; slotPointer = draggingSlots[9] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[10] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; slotPointer = draggingSlots[11] = new CardSlot(widthPointer + 6, 130); widthPointer = slotPointer.getLocation().x + CardSlot.WIDTH; slotPointer = draggingSlots[12] = new OperatorSlot(widthPointer + 6, 160); widthPointer = slotPointer.getLocation().x + OperatorSlot.WIDTH; } // addSlots /** * stop the running of dragging area */ public void stop() { animating = false; cardDeck.stop(); dragImages.removeAllElements(); if (dragThread != null) { dragThread.stop(); dragThread = null; } //if } // stop public void run() { Thread myThread = Thread.currentThread(); while (dragThread == myThread) { if( animating ) { presentSolution(); } // if else { try { clipRepaint(); Thread.sleep(200L); } // try catch(InterruptedException e) { } // catch } // else } // while } // run public Dimension getPreferredSize() { return getMinimumSize(); } // getPreferredSize public Dimension getMinimumSize() { return new Dimension(640, 250); } // getMinimumSize public Vector userCreatedExpression() { Vector expression = new Vector(); DraggingImage image = null; for(int i = 0; i < 13; i ++) { image = draggingSlots[i].getHoldenImage(); if(image != null) { if(image instanceof Card) expression.addElement(((Card)image).getValue()); else expression.addElement(((Operator)image).getValue()); } // if else { expression.addElement(new Character(' ')); } // if } // for return expression; } // userCreatedExpression // full expression should has at least 4 cards, 3 operators public boolean isFullExpression() { int cardCount = 0, operatorCount = 0; DraggingImage image = null; for(int i = 0; i < 13; i ++) { image = draggingSlots[i].getHoldenImage(); if(image != null) { if(image instanceof Card) cardCount++; else operatorCount++; } // if } // for return ( cardCount > 3 && operatorCount > 2 ); } // isFullExpression public Vector currentSolution() { return ( cardDeck.currentSolution() ); } // currentSolution public void beginAnimation() { animating = true; } //beginAnimation public void endAnimation() { animating = false; } //endAnimation public void setStatus(int value) { status.set(value); } //setStatus /** * presents correct solution in animation */ public void presentSolution() { int speed = 20, //move 20 pixels each time startX, startY, endX, endY, steps, stepX, stepY; double distance; Point location; Dimension size; DraggingSlot slot = null; Vector solution = null; solution = currentSolution(); Object element = null; resetClip(); clearSlots(); clipRepaint(); try { Thread.sleep(200L); } // try catch(InterruptedException e) { } // catch for(int i = 0; i < 13; i++) { slot = draggingSlots[i]; element = solution.elementAt(i); if( element instanceof Integer ) { for(int j = 0; j < 4; j++) { if( !(currentCards[j].isSettled()) && currentCards[j].getCardValue() == ((Integer)element).intValue() ) { theMoving = currentCards[j]; break; } // if } // for j } // if is card else { boolean isOperator = false; for(int j = 0; j < 18; j++) { if( !(operators[j].isSettled()) && operators[j].getOpSymbol() == ((Character)element).charValue() ) { theMoving = operators[j]; isOperator = true; break; } //if } // for j // is white space, skip if(!isOperator) continue; } // else is character //put theMoving on top dragImages.removeElement(theMoving); dragImages.addElement(theMoving); location = theMoving.getLocation(); size = theMoving.getSize(); //initiate clipping area updateLeft = location.x; updateTop = location.y; updateRight = updateLeft + size.width; updateBottom = updateTop + size.height; //start point of animation startX = location.x; startY = location.y; //end point of animation location = slot.getLocation(); endX = location.x; endY = location.y; distance = Math.sqrt( (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY) ); //steps needed moving from start point to the end point steps = (int)(distance / speed); if(steps != 0) { stepX = (endX - startX) / steps; stepY = (endY - startY) / steps; } // if else { stepX = 0; stepY = 0; } //else //animation loop for(int s = 0; s < steps; s++) { theMoving.setLocation(startX + stepX * s, startY + stepY * s); clipRepaint(); try { Thread.sleep(100L); } // try catch(InterruptedException e) { } // catch } // for slot.fillWith(theMoving); resetClip(); clipRepaint(); ((Arithmetic24)applet).soundList.playClip( ((Arithmetic24)applet).fillSlotSound ); try { Thread.sleep(200L); } // try catch(InterruptedException e) { } // catch } // for theMoving = null; animating = false; resetClip(); } //presentSolution public void clearSlots() { for(int i = 0; i < 13; i++) { draggingSlots[i].empty(); } //for for(int i = 0; i < 18; i++) { operators[i].setLocation(510 + i % 6 / 2 * 30, 15 + i % 6 % 2 * 45); } // for } //clearSlots public void removeCards() { // empty card slots for(int i = 0; i < 13; i++) { if(draggingSlots[i] instanceof CardSlot) { draggingSlots[i].empty(); } // if } // for for(int i = 0; i < 4; i++) { if(currentCards[i] != null) { dragImages.removeElement(currentCards[i]); } //if } // for clipRepaint(); } // removeCards public void addCards() { for(int j = 0; j < 4; j++) { currentCards[j].setLocation( 150 + j * 80, 10 ); dragImages.addElement( currentCards[j] ); } // for } // addCards /* * track all card and operator images loading */ public void loadAllImages() { tracker = new MediaTracker(this); cardImages = new Image[52]; operatorImages = new Image[6]; imageCount = 0; // track card images for(int i = 0; i < 4; i++) { for(int j = 1; j <= 13; j++) { cardImages[imageCount] = applet.getImage( applet.getCodeBase(), "image/" + Card.SUIT_NAMES[i] + "-" + j + ".GIF" ); tracker.addImage(cardImages[imageCount], imageCount); imageCount++; } // for j } // for i // track operator images for(int i = 0; i < 6; i++) { operatorImages[i] = applet.getImage( applet.getCodeBase(), "image/" + Operator.OP_NAMES[i] + ".GIF" ); tracker.addImage(operatorImages[i], imageCount); imageCount++; } // for i // track cardDeck image cardDeckImage = applet.getImage( applet.getCodeBase(), "image/CardSet.GIF" ); tracker.addImage(cardDeckImage, imageCount); imageCount++; // begin loading tracker.checkAll(true); } // loadAllImages public synchronized void resetClip() { updateLeft = updateTop = 0; updateRight = getSize().width; updateBottom = getSize().height; } // resetClip public void paint(Graphics g) { g.setClip(updateLeft, updateTop, updateRight - updateLeft, updateBottom - updateTop); //Paint the image onto the screen. g.drawImage(offScreenImage, 0, 0, this); //set update area again. if(theMoving != null) { Point location = theMoving.getLocation(); Dimension size = theMoving.getSize(); updateLeft = location.x; updateTop = location.y; updateRight = updateLeft + size.width; updateBottom = updateTop + size.height; } // if } // paint /** * use double-buffering and clipping to update dragging area */ public synchronized void update(Graphics g) { // if not all image loaded, show status bar if(!tracker.checkAll(true)) { int loadedCount = 0; for(int i = 0; i < imageCount; i++) { if(tracker.statusID(i, true) == 8) loadedCount++; //System.out.println(loadedCount); } int barWidth = size().width - 100; int fillWidth = (barWidth * loadedCount) / imageCount; offScreenGraphics.setColor(Color.yellow); offScreenGraphics.drawString("Loading images:", 50, size().height - 50); offScreenGraphics.drawRect(50, size().height - 30, barWidth, 15); offScreenGraphics.fillRect(50, size().height - 30, fillWidth, 15); paint(g); return; } //if // clip, only draw changed area offScreenGraphics.setClip(updateLeft, updateTop, updateRight - updateLeft, updateBottom - updateTop); // Erase the previous image. offScreenGraphics.setColor(getBackground()); offScreenGraphics.fillRect(0, 0, size().width, size().height); // draw all things drawDragSlots(offScreenGraphics); drawDragImages(offScreenGraphics); paint(g); } // update /** * Updates the clip area, then request repaint */ public synchronized void clipRepaint() { if(theMoving != null) { Point location = theMoving.getLocation(); Dimension size = theMoving.getSize(); // enlarge update area to include newly changed area updateLeft = Math.min(updateLeft, location.x); updateTop = Math.min(updateTop, location.y); updateRight = Math.max(updateRight, location.x + size.width); updateBottom = Math.max(updateBottom, location.y + size.height); } // if repaint(); } //clipRepaint // draw all the slots protected void drawDragSlots(Graphics g) { for( int i = 0; i < 13; i++ ) { draggingSlots[i].paint(g); } // for } // drawDragSlots // draw all of the dragging images protected void drawDragImages(Graphics g) { for(Enumeration e = dragImages.elements(); e.hasMoreElements(); ) { ((DraggingImage)e.nextElement()).paint(g); } // for } // drawDragImages // inner class to handle mouse events class MyMouseAdapter extends MouseAdapter { public void mousePressed(MouseEvent event) { if( animating ) return; for( int i = dragImages.size() - 1; i >= 0; i-- ) { DraggingImage d = (DraggingImage)dragImages.elementAt(i); if( d.contains(event.getX(), event.getY()) ) { if( d.isDraggable() ) { theMoving = d; synchronized(dragImages) { //put the dragged on top dragImages.removeElement(theMoving); dragImages.addElement(theMoving); } //synchronized grabPoint.x = event.getX() - d.getLocation().x; grabPoint.y = event.getY() - d.getLocation().y; updateLeft = d.getLocation().x; updateTop = d.getLocation().y; updateRight = updateLeft + d.getSize().width; updateBottom = updateTop + d.getSize().height; } // if else { // clicked on deck if( d == cardDeck && ((CardDeck)d).isClickable() ) { ((Arithmetic24)applet).soundList.playClip( ((Arithmetic24)applet).clickDeckSound ); removeCards(); arrangeOperators(); currentCards = ((CardDeck)d).deal(); if( currentCards == null ) { // finished a round // TO DO: record user name if his score is // high, some networking staff needed dragImages.removeElement( cardDeck ); status.set(PlayingStatus.ROUND_OVER); } //if else { addCards(); ((CardDeck)d).disableClick(); status.set(PlayingStatus.DEALED); } // else clipRepaint(); } // if*/ } // else return; } // if } // for } // mousePressed public void mouseReleased(MouseEvent event) { if( animating ) return; if( theMoving == null ) return; boolean isOnSlot = false; for(int i = 0; i < 13; i++) { DraggingSlot slot = draggingSlots[i]; if( slot.underneath(theMoving) ) { int slotType, imageType; if(slot instanceof CardSlot) slotType = ((CardSlot)slot).getType(); else slotType = ((OperatorSlot)slot).getType(); if(theMoving instanceof Card) imageType = ((Card)theMoving).getType(); else imageType = ((Operator)theMoving).getType(); if( slotType != imageType ) continue; if( slot.isEmpty() ) { if(theMoving.isSettled()) { //remove from original slot theMoving.getSlot().empty(); } // if slot.fillWith(theMoving); ((Arithmetic24)applet).soundList.playClip( ((Arithmetic24)applet).fillSlotSound ); } // if slot empty else { if(theMoving != slot.getHoldenImage()) { slot.kickOff(theMoving); if(theMoving.isSettled()) { theMoving.getSlot().empty(); } // if } // if else slot.fillWith(theMoving); } // else isOnSlot = true; break; } // if underneath } // for if( !isOnSlot ) { if( theMoving.isSettled() ) { //remove from the original slot theMoving.getSlot().empty(); } // if } // if resetClip(); clipRepaint(); theMoving = null; } // mouseReleased } // MyMouseAdapter class MyMouseMotionAdapter extends MouseMotionAdapter { public synchronized void mouseDragged(MouseEvent event) { if( animating ) return; if(theMoving != null) { theMoving.setLocation( event.getX() - grabPoint.x, event.getY() - grabPoint.y ); clipRepaint(); } // if } // mouseDrgged public void mouseMoved(MouseEvent event) { if( animating ) return; for( Enumeration e = dragImages.elements(); e.hasMoreElements(); ) { DraggingImage d = (DraggingImage)e.nextElement(); if( d.contains(event.getX(), event.getY()) ) { setCursor(handCursor); return; } // if } // for if(getCursor() != defaultCursor) setCursor(defaultCursor); } // mouseMoved } // MyMouseMotionAdapter } // DraggingArea