Package guicomponents

Source Code of guicomponents.GButton

/*
  Part of the GUI for Processing library
     http://www.lagers.org.uk/g4p/index.html
  http://gui4processing.googlecode.com/svn/trunk/

  Copyright (c) 2008-11 Peter Lager

  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; either
  version 2.1 of the License, or (at your option) any later version.

  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.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package guicomponents;

import java.awt.Point;
import java.awt.event.MouseEvent;

import processing.core.PApplet;
import processing.core.PImage;

/**
* This class is the Button component.
*
* The button face can have either text or an image or both just
* pick the right constructor.
*
* Three types of event can be generated :-  <br>
* <b> PRESSED  RELEASED  CLICKED </b><br>
*
* To simplify event handling the button only fires off CLICKED events
* if the mouse button is pressed and released over the button face
* (the default behaviour). <br>
*
* Using <pre>button1.fireAllEvents(true);</pre> enables the other 2 events
* for button <b>button1</b>. A PRESSED event is created if the mouse button
* is pressed down over the button face, the CLICKED event is then generated
* if the mouse button is released over the button face. Releasing the
* button off the button face creates a RELEASED event. <br>
*
* The image file can either be a single image which is used for
* all button states, or be a composite of 3 images (tiled horizontally)
* which are used for the different button states OFF, OVER and DOWN
* in which case the image width should be divisible by 3. <br>
* A number of setImages(...) methods exist to set button state images, these
* can be used once the button is created.<br>
*
*
* @author Peter Lager
*
*/
public class GButton extends GComponent {

  // Button status values
  public static final int OFF    = 0;
  public static final int OVER  = 1;
  public static final int DOWN  = 2;

  protected int status;

  protected PImage[] bimage = new PImage[3];
  protected int btnImgWidth = 0;
  protected int imageAlign = GAlign.CENTER;
 
  protected boolean useImages = false;
 
  // Only report CLICKED events
  protected boolean reportAllButtonEvents = false;
 
  // Defines position of image if any
  protected int imgAlignX;
 
  /**
   * Create a button with text only.
   *
   * Height and width may increase depending on initial text a
   *
   * @param theApplet
   * @param text text appearing on the button
   * @param x horz position of button
   * @param y vert position
   * @param width minimum width of button
   * @param height minimum height of button
   */
  public GButton(PApplet theApplet, String text, int x, int y, int width, int height){
    super(theApplet, x, y);
    setText(text);
    buttonCtorCore(width, height);
  }

  /**
   * Create a button with image only.
   *
   * Height and width may increase depending on image size.
   *
   * @param theApplet
   * @param imgFile filename of image to use on the button
   * @param nbrImages number of images in the film strip normally 1 or 3 (OFF OVER DOWN)
   * @param x horz position of button
   * @param y vert position
   * @param width minimum width of button
   * @param height minimum height of button
   */
  public GButton(PApplet theApplet, String imgFile, int nbrImages, int x, int y, int width, int height){
    super(theApplet, x, y);
    setImages(imgFile, nbrImages);
    btnImgWidth = this.getMaxButtonImageWidth();
    buttonCtorCore(width, height);
  }

  /**
   * Create a button with both text and image.
   *
   * Height and width may increase depending on initial text length
   * and image size.
   *
   * @param theApplet
   * @param text text appearing on the button
   * @param imgFile filename of image to use on the button
   * @param nbrImages number of images in the film strip normally 1 or 3 (OFF OVER DOWN)
   * @param x horz position of button
   * @param y vert position
   * @param width minimum width of button
   * @param height minimum height of button
   */
  public GButton(PApplet theApplet, String text, String imgFile, int nbrImages, int x, int y, int width, int height){
    super(theApplet, x, y);
    setImages(imgFile, nbrImages);
    btnImgWidth = getMaxButtonImageWidth();
    setText(text);
    buttonCtorCore(width, height);
  }

  /**
   * Core code for all ctors.
   * @param width button width reqd
   * @param height button height reqd
   */
  private void buttonCtorCore(int width, int height) {
    // Check button is wide and tall enough for both text
    this.width = Math.max(width, textWidth + 2 * PADH);
    this.height = Math.max(height, localFont.getSize() + 2 * PADV);
    border = 1;
    // and now update for image/text combined
    setImageAlign(imageAlign);
    textAlignHorz = GAlign.CENTER;
    textAlignVert = GAlign.MIDDLE;
    calcAlignX();
    calcAlignY();
    createEventHandler(G4P.mainWinApp, "handleButtonEvents", new Class[]{ GButton.class });
    registerAutos_DMPK(true, true, false, false);
    z = Z_SLIPPY;
  }

  /**
   * Set the colors to be used by the GButton without having to create a new
   * color scheme (GCScheme). Use PApplet's color() method to calculate the color
   * values to be passed.<br>
  
   * @param normal
   * @param mouseOver
   * @param pressed
   */
  public void setColours(int normal, int mouseOver, int pressed){
    localColor.btnOff = normal;
    localColor.btnOver = mouseOver;
    localColor.btnDown = pressed;
  }

  /**
   * Get the maximum width of the button images. <br>
   * @return zero if no button images
   */
  protected int getMaxButtonImageWidth(){
    int bw = 0;
    for(int i = 0; i < 3; i++)
      bw = Math.max(bw, ((bimage[i] == null) ? 0 : bimage[i].width));
    useImages = (bw > 0);
    return bw;   
  }
 
  /**
   * Get the maximum height of the button images. <br>
   * @return zero if no button images
   */
  protected int getMaxButtonImageHeight(){
    int bh = 0;
    for(int i = 0; i < 3; i++)
      bh = Math.max(bh, ((bimage[i] == null) ? 0 : bimage[i].height));
    return bh;   
  }
 
  /**
   * Specify the 3 images files to be used to display the button's state.
   *
   * @param ifileNormal
   * @param ifileOver
   * @param ifilePressed
   */
  public void setImages(String ifileNormal, String ifileOver, String ifilePressed){
    bimage[0] = winApp.loadImage(ifileNormal);
    if(bimage[0] == null)
      if(G4P.messages) System.out.println("Can't find normal button image file");
    bimage[1] = winApp.loadImage(ifileOver);
    if(bimage[1] == null)
      if(G4P.messages) System.out.println("Can't find over button image file");
    bimage[2] = winApp.loadImage(ifilePressed);
    if(bimage[2] == null)
      if(G4P.messages) System.out.println("Can't find pressed button image file");
    getMaxButtonImageWidth();
    if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
      imageAlign = GAlign.LEFT;
  }
 
  /**
   * Specify the 3 images files to be used to display the button's state.
   * @param imgFiles an array of filenames
   */
  public void setImages(String[] imgFiles){
    if(imgFiles != null && imgFiles.length > 1){
      setImages(imgFiles[0], imgFiles[1 % imgFiles.length], imgFiles[2 % imgFiles.length]);
      getMaxButtonImageWidth();
      if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
        imageAlign = GAlign.LEFT;
    }
  }
 
  /**
   * Specify the image file that contains the image{s} to be used for the button's state. <br>
   * This image may be a composite of 1 to 3 images tiled horizontally.
   * @param imgFile
   * @param nbrImages in the range 1 - 3
   */
  public void setImages(String imgFile, int nbrImages){
    nbrImages = PApplet.constrain(nbrImages, 1, 3);
    if(imgFile != null && nbrImages > 0){
      PImage img = winApp.loadImage(imgFile);
      if(img == null){
        if(G4P.messages) System.out.println("Can't find button image file");
      }
      else
        setImages(img, nbrImages);
      getMaxButtonImageWidth();
      if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
        imageAlign = GAlign.LEFT;
    }
  }
 
  /**
   * Specify the 3 images to be used to display the button's state.
   * @param imgNormal
   * @param imgOver
   * @param imgPressed
   */
  public void setImages(PImage imgNormal, PImage imgOver, PImage imgPressed){
    bimage[0] = imgNormal;
    bimage[1] = imgOver;
    bimage[2] = imgPressed;
    getMaxButtonImageWidth();
    if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
      imageAlign = GAlign.LEFT;
  }
 
  /**
   * Specify the 3 images to be used to display the button's state.
   * @param images an array of PImages
   */
  public void setImages(PImage[] images){
    if(images != null){
      for(int i = 0; i < images.length ; i++)
        bimage[i] = images[i];
      for(int i = images.length; i < 3; i++)
        bimage[i] = bimage[images.length - 1];
      getMaxButtonImageWidth();
      if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
        imageAlign = GAlign.LEFT;
    }
  }
 
  /**
   * Specify the PImage that contains the image{s} to be used for the button's state. <br>
   * This image may be a composite of 1 to 3 images tiled horizontally.
   * @param img
   * @param nbrImages in the range 1 - 3
   */
  public void setImages(PImage img, int nbrImages){
    if(img != null && nbrImages > 0){
      int iw = img.width / nbrImages;
      for(int i = 0; i < nbrImages;  i++){
        bimage[i] = new PImage(iw, img.height, ARGB);
        bimage[i].copy(img,
            i * iw, 0, iw, img.height,
            0, 0, iw, img.height);
      }
      for(int i = nbrImages; i < 3; i++){
        bimage[i] = bimage[nbrImages - 1];
      }
      getMaxButtonImageWidth();
      if(useImages && imageAlign == GAlign.CENTER && text.length() > 0)
        imageAlign = GAlign.LEFT;
    }
  }
 
  /**
   * Set the color scheme for this button
   */
  public void setColorScheme(int schemeNo){
    localColor = GCScheme.getColor(winApp, schemeNo);
  }

  /**
   * Set the text to appear on the button. This does nothing
   * if the parameter is null or an empty string. <br>
   * If the button has an image with CENTER allignment it is
   * made LEFT alligment.
   * @param text the text to set with alignment
   */
  public void setText(String text) {
    if(text != null && text != ""){
      if(useImages && imageAlign == GAlign.CENTER)
        setImageAlign(GAlign.LEFT);
      this.text = text;
      winApp.textFont(localFont, localFont.getSize());
      textWidth = Math.round(winApp.textWidth(text));
      calcAlignX();
      calcAlignY();
    }
  }

  /**
   * Set the font & size for the button increasing height and
   * width of the button if necessary to display text. <br>
   * It will not shrink if the font size is decreased. 
   * @param fontname the name of the font to use (if not available use default font)
   * @param fontsize the font size to use
   */
  public void setFont(String fontname, int fontsize){
    setFont(fontname, fontsize, true);
  }

  /**
   * Set the font and size for the button. If resize is true then
   * the button size will be increased if necessary to display text.
   * @param fontname the name of the font to use (if not available use default font)
   * @param fontsize the font size to use
   * @param resize
   */
  public void setFont(String fontname, int fontsize, boolean resize){
    int tw = textWidth;
    int fs = (int) localFont.getSize();
    localFont = GFont.getFont(winApp, fontname, fontsize);
    if(resize){
      if(fontsize > fs)
        height += (fontsize - fs);
      setText(text);
      if(textWidth > tw)
        width += (textWidth - tw);
    }
    calcAlignX();
    calcAlignY();
  }

 
  /**
   * Sets the position of the image in relation to the button text
   * provided the text horizontal alignment is GAlign.LEFT or
   * GAlign.RIGHT
   * @param imgAlign either GAlign.LEFT or GAlign.RIGHT
   */
  public void setImageAlign(int imgAlign){
    if(useImages){
      switch(imgAlign){
      case GAlign.LEFT:
        imageAlign = imgAlign;
        imgAlignX = PADH;
        break;
      case GAlign.RIGHT:
        imageAlign = imgAlign;
        imgAlignX = (int) (width - btnImgWidth - PADH);
        break;
      case GAlign.CENTER:
        if(text.length() == 0){
          imageAlign = imgAlign;
          imgAlignX = (int) ((width - btnImgWidth)/2);
        }
        else {
          imageAlign = GAlign.LEFT;
          imgAlignX = PADH;
        }
        break;
      }
    }
    calcAlignX();
  }

  /**
   * Calculate text and image X alignment position
   */
  protected void calcAlignX(){
    int areaWidth = (int) width;
    int imgX = 0;
    if(useImages){
      areaWidth -= btnImgWidth;
      if(imageAlign == GAlign.LEFT)
        imgX = btnImgWidth;
    }
    switch(textAlignHorz){
    case GAlign.LEFT:
      alignX = imgX + border +  PADH;
      break;
    case GAlign.RIGHT:
      alignX = imgX + areaWidth - textWidth - border - PADH;
      break;
    case GAlign.CENTER:
      alignX = imgX + border + PADH + (areaWidth - textWidth)/2;
      break;
    }
  }

  /**
   * Draw the button
   */
  public void draw(){
    if(!visible) return;
   
    winApp.pushStyle();
    winApp.style(G4P.g4pStyle);

    Point pos = new Point(0,0);
    calcAbsPosition(pos);
   
    // Draw button rectangle
    if(border == 0){
      winApp.strokeWeight(0);
      winApp.noStroke();
    }
    else {
      winApp.strokeWeight(border);
      winApp.stroke(localColor.btnBorder);
    }
    switch(status){
    case 0:
      winApp.fill(localColor.btnOff);
      break;
    case 1:
      winApp.fill(localColor.btnOver);
      break;
    case 2:
      winApp.fill(localColor.btnDown);
      break;
    }
    winApp.rect(pos.x,pos.y,width,height);
   
    // Draw image
    if(useImages && bimage != null && bimage[status] != null){
      winApp.image(bimage[status], pos.x + imgAlignX, pos.y+(height-bimage[status].height)/2);
    }
    // Draw text
    winApp.noStroke();
    winApp.fill(localColor.btnFont);
    winApp.textFont(localFont, localFont.getSize());
    winApp.text(text, pos.x + alignX, pos.y + alignY, width, height);
//    winApp.text(text, pos.x + alignX, pos.y + (height - localFont.getFont().getSize())/2 - PADV, width, height);
    winApp.popStyle();
  }

  /**
   * If the parameter is true all 3 event types are generated, if false
   * only CLICKED events are generated (default behaviour).
   * @param all
   */
  public void fireAllEvents(boolean all){
    reportAllButtonEvents = all;
  }

  /**
   * All GUI components are registered for mouseEvents. <br>
   * When a button is clicked on a GButton it generates 3 events (in this order)
   * mouse down, mouse up and mouse pressed. <br>
   * You can test for a particular event type with : <br>
   * <pre>
   *   void handleButtonEvents(GButton button) {
   *    if(button == btnName && button.eventType == GButton.PRESSED){
   *        // code for button click event
   *    }
   * </pre> <br>
   * Where <pre><b>btnName</b></pre> is the GButton identifier (variable name) <br><br>
   *
   * If you only wish to respond to button click events then use the statement <br>
   * <pre>btnName.fireAllEvents(false); </pre><br>
   * This is the default mode.
   */
  public void mouseEvent(MouseEvent event){
    if(!visible || !enabled) return;

    boolean mouseOver = isOver(winApp.mouseX, winApp.mouseY);
    if(mouseOver)
      cursorIsOver = this;
    else if(cursorIsOver == this)
      cursorIsOver = null;

    switch(event.getID()){
    case MouseEvent.MOUSE_PRESSED:
      if(focusIsWith != this && mouseOver && z > focusObjectZ()){
        mdx = winApp.mouseX;
        mdy = winApp.mouseY;
        status = DOWN;
        takeFocus();
        eventType = PRESSED;
        if(reportAllButtonEvents)
          fireEvent();
      }
      break;
    case MouseEvent.MOUSE_CLICKED:
      // No need to test for isOver() since if the component has focus
      // and the mouse has not moved since MOUSE_PRESSED otherwise we
      // would not get the Java MouseEvent.MOUSE_CLICKED event
      if(focusIsWith == this){
        status = OFF;
        loseFocus(null);
//        if(reportAllButtonEvents){
//          eventType = RELEASED;
//          fireEvent();
//        }
        eventType = CLICKED;
        fireEvent();
      }
      break;
    case MouseEvent.MOUSE_RELEASED: 
      // if the mouse has moved then release focus otherwise
      // MOUSE_CLICKED will handle it
      if(focusIsWith == this && mouseHasMoved(winApp.mouseX, winApp.mouseY)){
        loseFocus(null);
        if(isOver(winApp.mouseX, winApp.mouseY)){
          eventType = CLICKED;
          fireEvent();
        }
        else {
          if(reportAllButtonEvents){
            eventType = RELEASED;
            fireEvent();
          }
        }
        status = OFF;
      }
      break;
    case MouseEvent.MOUSE_MOVED:
      // If dragged state will stay as DOWN
      if(isOver(winApp.mouseX, winApp.mouseY))
        status = OVER;
      else
        status = OFF;
    }
  }

}
TOP

Related Classes of guicomponents.GButton

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.