home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Micrsoft / SAMPLES / VJ6SAMPL.EXE / EyeControl / EyeControl.java < prev    next >
Encoding:
Java Source  |  1998-02-24  |  12.0 KB  |  389 lines

  1.  
  2. /*  Copyright (C) Microsoft Corporation, 1996-1998.  All rights reserved.
  3.  
  4.   This source code is intended only as a supplement to Microsoft
  5.   Visual J++ 6.0.  See this product's on-line documentation for detailed   
  6.   information regarding Microsoft code samples.
  7.  
  8. */
  9.  
  10. //EyeControl.java
  11. import wfc.ui.*;
  12. import wfc.core.*;
  13. import wfc.app.*;
  14.  
  15. public class EyeControl extends wfc.ui.Control
  16. {
  17.   private Container components = new Container();
  18.   private boolean hasFocus;
  19.   /*
  20.    * The default update frequency is 50ms
  21.    */
  22.   private Integer interval=new Integer(50);
  23.   /*
  24.    * The default color for the "iris" is blue
  25.    */
  26.   private Color irisColor = wfc.ui.Color.BLUE;
  27.   private boolean leftButtonDown=false;
  28.   private Point leftCenter;
  29.   private Point leftCurrent;
  30.   private Bitmap offscreenImage;
  31.   private int pupilRadius;
  32.   private Rectangle rect;
  33.   private boolean rightButtonDown=false;
  34.   private Point rightCenter;
  35.   private Point rightCurrent;
  36.   private int shortRadius;
  37.   private Timer timer;
  38.   
  39.   /**
  40.    * Creates an EyeControl object.
  41.    */
  42.     public EyeControl()
  43.     {
  44.     super();
  45.     setTabStop(true);
  46.     setStyle(STYLE_OPAQUE, true);
  47.     /*
  48.      * The timer is used to track the mouse cursor while it is not over
  49.      * our client area
  50.      */
  51.     timer = new Timer(components);
  52.     timer.setInterval(interval.intValue());
  53.     timer.addOnTimer (new EventHandler(this.EyeControl_Timer));
  54.  
  55.     /*
  56.      * create event handlers for the events which we care about
  57.      */
  58.     this.addOnPaint(new PaintEventHandler(this.EyeControl_Paint));
  59.     this.addOnMouseMove (new MouseEventHandler(this.EyeControl_MouseMove));
  60.     this.addOnMouseUp (new MouseEventHandler(this.EyeControl_MouseUp));
  61.     this.addOnMouseDown (new MouseEventHandler(this.EyeControl_MouseDown));
  62.     this.addOnGotFocus(new EventHandler(this.EyeControl_GotFocus));
  63.     this.addOnLostFocus(new EventHandler(this.EyeControl_LostFocus));
  64.     this.addOnResize(new EventHandler(this.EyeControl_Resize));
  65.  
  66.     /*
  67.      * the default size of our control is 64x64
  68.      */
  69.     setBounds(0, 0, 64, 64);
  70.     timer.setEnabled(true);
  71.   }
  72.  
  73.   /**
  74.    * Handles the gotFocus event.
  75.    * 
  76.    * @param sender The sending object of the event
  77.    * @param e The Event
  78.    */
  79.   private void EyeControl_GotFocus(Object sender, Event e)
  80.   {
  81.     hasFocus = true;
  82.     invalidate();
  83.   }
  84.  
  85.   /**
  86.    * Handles the lostFocus event.
  87.    * 
  88.    * @param sender The sending object of the event
  89.    * @param e The Event
  90.    */
  91.   private void EyeControl_LostFocus(Object sender, Event e)
  92.   {
  93.     hasFocus = false;
  94.     invalidate();
  95.   }
  96.  
  97.   /**
  98.    * Handles the mouseDown event.
  99.    * 
  100.    * @param sender The sending object of the event
  101.    * @param e The MouseEvent
  102.    */
  103.   private void EyeControl_MouseDown(Object sender, MouseEvent e)
  104.   {
  105.     /*
  106.      * if one of the mouse buttons went down, update the status
  107.      * of our tracking variables and force a repaint of the window
  108.      */
  109.     wfc.win32.Windows.SetFocus(getHandle());
  110.     leftButtonDown = ((e.button & (MB_LEFT | MB_MIDDLE)) != 0) || leftButtonDown;
  111.     rightButtonDown = ((e.button & (MB_RIGHT | MB_MIDDLE)) != 0) || rightButtonDown;
  112.     invalidate();
  113.   }
  114.  
  115.   /**
  116.    * Handles the mouseMove event.
  117.    * 
  118.    * @param sender The sending object of the event
  119.    * @param e The MouseEvent
  120.    */
  121.   private void EyeControl_MouseMove(Object sender, MouseEvent e)
  122.   {
  123.     if (updateCoordinates(e.x,e.y))
  124.       invalidate();
  125.   }
  126.   
  127.   /**
  128.    * Handles the mouseUp event.
  129.    * 
  130.    * @param sender The sending object of the event
  131.    * @param e The MouseEvent
  132.    */
  133.   private void EyeControl_MouseUp(Object sender, MouseEvent e)
  134.   {
  135.     /*
  136.      * if one of the mouse buttons went up, update the status
  137.      * of our tracking variables and force a repaint of the window
  138.      */
  139.     if (leftButtonDown)
  140.       leftButtonDown = (e.button & (MB_LEFT | MB_MIDDLE)) == 0;
  141.     if (rightButtonDown)
  142.       rightButtonDown = (e.button & (MB_RIGHT | MB_MIDDLE)) == 0;
  143.     invalidate();
  144.   }
  145.  
  146.   /**
  147.    * Handles the paint event.
  148.    * 
  149.    * @param sender The sending object of the event
  150.    * @param e The PaintEvent
  151.    */
  152.     private void EyeControl_Paint(Object sender, PaintEvent e)
  153.     {
  154.     /*
  155.      * do all of the painting onto the offscreen offscreenImage. When we are done
  156.      * we will bitBlt() that offscreenImage onto our client area
  157.      */
  158.     Graphics g = offscreenImage.getGraphics();
  159.     /*
  160.      * fill in the background
  161.      */
  162.     g.setPen(Pen.NULL);
  163.     g.setBrush(e.graphics.getBrush());
  164.     g.drawRect(rect);
  165.  
  166.     /*
  167.      * if we have the focus, draw the focus rect
  168.      */
  169.     if (hasFocus)
  170.       g.drawFocusRect(rect);
  171.     
  172.     /*
  173.      * draw the eye ellipses in white
  174.      */
  175.     g.setBrush(Brush.WHITE);
  176.     g.setPen(Pen.BLACK);
  177.     g.drawEllipse(0,0,rect.width/2,rect.height);
  178.     g.drawEllipse(rect.width/2,0,rect.width/2,rect.height);
  179.  
  180.     /*
  181.      * draw either the pupil or a line (indicating the eye is closed)
  182.      * depending on the state of the left/right mouse button
  183.      */
  184.     if (leftButtonDown)
  185.     {
  186.       g.setPen(Pen.BLACK);
  187.       g.drawLine(0,rect.height/2,rect.width/2,rect.height/2);
  188.     }
  189.     else
  190.     {
  191.       g.setPen(new Pen(irisColor));
  192.       g.setBrush(new Brush(irisColor));
  193.       g.drawEllipse(leftCurrent.x-pupilRadius,leftCurrent.y-pupilRadius,pupilRadius*2,pupilRadius*2);
  194.       g.setBrush(Brush.BLACK);
  195.       g.setPen(Pen.BLACK);
  196.       g.drawEllipse(leftCurrent.x-(pupilRadius/2),leftCurrent.y-(pupilRadius/2),pupilRadius,pupilRadius);
  197.     }
  198.     /*
  199.      * lather, rinse, and repeat for the right eye
  200.      */
  201.     if (rightButtonDown)
  202.     {
  203.       g.setPen(Pen.BLACK);
  204.       g.drawLine(rect.width/2,rect.height/2,rect.width,rect.height/2);
  205.     }
  206.     else      
  207.     {
  208.       g.setPen(new Pen(irisColor));
  209.       g.setBrush(new Brush(irisColor));
  210.       g.drawEllipse(rightCurrent.x-pupilRadius,rightCurrent.y-pupilRadius,pupilRadius*2,pupilRadius*2);
  211.       g.setBrush(Brush.BLACK);
  212.       g.setPen(Pen.BLACK);
  213.       g.drawEllipse(rightCurrent.x-(pupilRadius/2),rightCurrent.y-(pupilRadius/2),pupilRadius,pupilRadius);
  214.     }
  215.     
  216.     /*
  217.      * blt the offscreen offscreenImage onto the screen
  218.      */
  219.     e.graphics.drawImage(offscreenImage, 0,0);
  220.     }
  221.  
  222.   /**
  223.    * Handles the resize event
  224.    * 
  225.    * @param sender The sending object of the event
  226.    * @param e The Event
  227.    */
  228.   private void EyeControl_Resize(Object sender, Event e)
  229.   {
  230.     rect = getBounds();
  231.     rect.x = rect.y = 0;
  232.     offscreenImage = new Bitmap(rect.width,rect.height);
  233.     /*
  234.      * calculate the new center points for the eyes
  235.      */
  236.     leftCenter = leftCurrent = new Point(rect.width/4, rect.height/2);
  237.     rightCenter = rightCurrent = new Point(leftCurrent.x * 3, leftCurrent.y);
  238.     /*
  239.      * calculate the new minor axis and the new radius of the pupil
  240.      */
  241.     shortRadius = Math.max(0, Math.min(rect.width/2, rect.height))/2;
  242.     pupilRadius = shortRadius / 3;
  243.     shortRadius = Math.max(0, Math.min(rect.width/2, rect.height) - (pupilRadius*2))/2-1;
  244.   }
  245.   
  246.   /**
  247.    * Handles the timer event. Updates the current coordinates of the mouse cursor
  248.    * while it is not over our client area.
  249.    * 
  250.    * @param sender The sending object of the event
  251.    * @param e The event
  252.    * @see EyeControl_MouseDown(Object, MouseEvent)
  253.    * @see EyeControl_MouseMove(Object, MouseEvent)
  254.    * @see EyeControl_MouseUp(Object, MouseEvent)
  255.    * @see updateCoordinates(int, int)
  256.    */
  257.   private void EyeControl_Timer(Object sender, Event e)
  258.   {
  259.     Point p = pointToClient(Cursor.getPosition());
  260.     /*
  261.      * if the cursor position, converted to client coordinates, is outside
  262.      * of the client area, then calcluate the new location for the pupils
  263.      * to be. If it is inside of the client area, the onMouseMove() event
  264.      * handler will deal with the new positions.
  265.      */
  266.     if (!(p.x >= 0 && p.y >= 0 && p.x <= rect.width && p.y <= rect.height))
  267.     {
  268.       boolean ld, rd;
  269.       ld = ((getMouseButtons() & (MB_LEFT | MB_MIDDLE)) != 0);
  270.       rd = ((getMouseButtons() & (MB_RIGHT | MB_MIDDLE)) != 0);
  271.       /*
  272.        * if the new coordinates are different than the old coordinates
  273.        * for the pupils or if one of the mouse button states changed,
  274.        * redraw the window
  275.        */
  276.       if (updateCoordinates(p.x, p.y) || ld != leftButtonDown || rd != rightButtonDown)
  277.       {
  278.         leftButtonDown = ld;
  279.         rightButtonDown = rd;
  280.         invalidate();
  281.       }
  282.     }
  283.   }
  284.   
  285.   /**
  286.    * Retrieves the color for the "iris" part of the eye
  287.    * 
  288.    * @returns a <b>Color</b> object representing the color of the "iris" part of the eye.
  289.    */
  290.   public Color getIrisColor() { return new Color(irisColor.getRGB()); }
  291.   
  292.   /**
  293.    * Retrieves the frequency for the control's timer
  294.    * 
  295.    * @returns how often the control checks the cursor's location. 
  296.    */
  297.   public Integer getUpdateInterval() { return interval; }
  298.   
  299.   /**
  300.    * Sets the color for the "iris" part of the eye
  301.    * 
  302.    * @param c The Color object representing the new color for the eye
  303.    */
  304.   public void setIrisColor(Color c) { irisColor = new Color(c.getRGB()); }
  305.   
  306.   /**
  307.    * Sets the frequency for the control's timer
  308.    * 
  309.    * @param i The frequency in milliseconds the control checks the cursor's location.
  310.    */
  311.   public void setUpdateInterval(Integer i) { interval = i; }
  312.  
  313.   /**
  314.    * Updates the location to draw the "iris" and "pupil" part of the eye.
  315.    * 
  316.    * @param mx The cursor's x coordinate
  317.    * @param my The cursor's y coordinate
  318.    * @returns <b>true</b> if the caller should call invalidate(); <b>false</b> otherwise.
  319.    */
  320.   private boolean updateCoordinates(int mx, int my)
  321.   {
  322.     Point rn,ln;
  323.     int dx,dy;
  324.     /*
  325.      * calculate the longRadius using Pythagorous
  326.      */
  327.     int longRadius = Math.max(1,(int)Math.sqrt(Math.pow(mx-leftCenter.x,2) + Math.pow(my-leftCenter.y,2)));
  328.     /*
  329.      * dx and dy represent the distances from the center point of the
  330.      * eye to a point on a circle of radius shortRadius
  331.      */
  332.     dx = ((mx - leftCenter.x)*shortRadius)/longRadius;
  333.     dy = ((my - leftCenter.y)*shortRadius)/longRadius;
  334.     /*
  335.      * if the mouse is inside of the circle inscribed by shortRadius
  336.      * track the pupil to that point, otherwise, track to a point on
  337.      * the circle
  338.      */
  339.     if (longRadius < shortRadius)
  340.       ln = new Point(mx,my);
  341.     else
  342.       ln = new Point(leftCenter.x+dx,leftCenter.y+dy);
  343.     
  344.     /*
  345.      * lather, rinse, and repeat for the right eye
  346.      */
  347.     longRadius = Math.max(1,(int)Math.sqrt(Math.pow(mx-rightCenter.x,2) + Math.pow(my-rightCenter.y,2)));
  348.     dx = ((mx - rightCenter.x)*shortRadius)/longRadius;
  349.     dy = ((my - rightCenter.y)*shortRadius)/longRadius;
  350.     if (longRadius < shortRadius)
  351.       rn = new Point(mx,my);
  352.     else
  353.       rn = new Point(rightCenter.x+dx,rightCenter.y+dy);
  354.     /*
  355.      * if either of the center-points for the pupils changed,
  356.      * update our tracking variables and return true. Callers
  357.      * of this method are responsible for calling invalidate().
  358.      */
  359.     if (!leftCurrent.equals(ln) || !rightCurrent.equals(rn))
  360.     {
  361.       leftCurrent = ln; rightCurrent = rn;
  362.       return true;
  363.     }
  364.     return false;
  365.   }
  366.   
  367.   public static class ClassInfo extends Control.ClassInfo
  368.   {
  369.     public static final PropertyInfo irisColor = new PropertyInfo(
  370.       EyeControl.class, "irisColor", wfc.ui.Color.class,
  371.       CategoryAttribute.Appearance,
  372.       new DefaultValueAttribute(wfc.ui.Color.BLUE),
  373.       new DescriptionAttribute("The color of the Iris part of the eye"));
  374.  
  375.     public static final PropertyInfo updateInterval = new PropertyInfo(
  376.       EyeControl.class, "updateInterval", Integer.class,
  377.       CategoryAttribute.Behavior,
  378.       new DefaultValueAttribute(new Integer(50)),
  379.       new DescriptionAttribute("The frequency in milliseconds in which the eyes check the cursor position"));
  380.  
  381.     public void getProperties(IProperties props)
  382.     {
  383.       super.getProperties(props);
  384.       props.add(irisColor);
  385.       props.add(updateInterval);
  386.     }
  387.   }
  388. }
  389.