Package winterwell.utils.gui

Source Code of winterwell.utils.gui.GuiUtils$EventHandler

/**
*
*/
package winterwell.utils.gui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.WindowConstants;

import winterwell.utils.IORException;
import winterwell.utils.MathUtils;
import winterwell.utils.Utils;
import winterwell.utils.WrappedException;
import winterwell.utils.io.FileUtils;
import winterwell.utils.web.WebUtils;

class BlockingImageObserver implements ImageObserver {

  private boolean block = true;

  public synchronized void block() {
    while (block) {
      try {
        wait();
      } catch (InterruptedException e) {
        // ignore
      }
    }
  }

  @Override
  public synchronized boolean imageUpdate(Image img, int infoflags, int x,
      int y, int width, int height) {
    block = false;
    notifyAll();
    return (infoflags & (ALLBITS | ABORT)) == 0;
  }

}

/**
*
* For standard dialogs (apart from file selection), see {@link JOptionPane}
*
* @author daniel
*
*/
public class GuiUtils {

  public static interface EventHandler {

    void onClick(JComponent clicked);

  }

  /** Winterwell's less corporate blue **/
  public static Color WINTERWELL_BLUE = getColor("#0096bb");

  /** Winterwell's corporate pink **/
  public static Color WINTERWELL_PINK = getColor("#e14184");

  /**
   * Mnenomic for {@link JOptionPane#showInputDialog(Object)}
   *
   * @param question
   * @return
   */
  public static String askUser(String question) {
    return JOptionPane.showInputDialog(question);
  }

  // .showOptionDialog(null, options, question, 0, 0, null, options, options);
  // JDialog dialog = new JDialog();
  // dialog.setTitle(question);
  // Box box = Box.createVerticalBox();
  // box.add(new JLabel(question));
  // Box optionsBox = Box.createHorizontalBox();
  // for (final String string : options) {
  // JButton button = new JButton(string);
  // button.setAction(new AbstractAction(){
  // @Override
  // public void actionPerformed(ActionEvent e) {
  // answer = string;
  // }
  // });
  // }
  // box.add(optionsBox);
  // dialog.add(box);
  // dialog.setVisible(true);
  // return null;
  // }

  /**
   * Block this thread whilst the given frame is open. Useful in interactive
   * tests for holding open a display. If {@link GuiUtils#isInteractive()} is
   * false, this will return immediately.
   *
   * @param frame
   */
  public static void blockWhileOpen(JFrame frame) {
    if (!GuiUtils.isInteractive())
      return;
    while (frame.isVisible()) {
      Utils.sleep(200);
    }
  }

  /**
   * Mnenomic for {@link JOptionPane#showConfirmDialog(Component, Object)}
   *
   * @param question
   * @return true if OK
   */
  public static boolean confirm(String msg) {
    int opt = JOptionPane.showConfirmDialog(null, msg);
    return opt == JOptionPane.OK_OPTION;
  }

  public static BufferedImage copy(Image img) {
    int type = img instanceof BufferedImage ? ((BufferedImage) img)
        .getType() : BufferedImage.TYPE_INT_ARGB;
    BufferedImage copy = new BufferedImage(getWidth(img), getHeight(img),
        type);
    Graphics g = copy.getGraphics();
    g.drawImage(img, 0, 0, null);
    g.dispose();
    return copy;
  }

  /**
   *
   * @param fade
   *            [0,1] 0=a, 1=b
   * @param a
   * @param b
   * @return a colour partway between a and b
   *
   * @testedby {@link GuiUtilsTest#testFade()}
   */
  public static Color fade(double fade, Color a, Color b) {
    assert a != null && b != null;
    assert MathUtils.isProb(fade) : fade;
    if (fade == 0)
      return a;
    if (fade == 1)
      return b;
    int[] argba = new int[] { a.getRed(), a.getGreen(), a.getBlue(),
        a.getAlpha() };
    int[] brgba = new int[] { b.getRed(), b.getGreen(), b.getBlue(),
        b.getAlpha() };
    int[] rgba = new int[4];
    for (int i = 0; i < 4; i++) {
      rgba[i] = (int) Math.round((1 - fade) * argba[i] + fade * brgba[i]);
    }
    return new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
  }

  public static Rectangle getBoundingRectangle(Image img) {
    int w = getWidth(img);
    int h = getHeight(img);
    return new Rectangle(w, h);
  }

  /**
   * Get a color from a web-style RGB hex string e.g. #ffff00. The string may
   * optionally begin with a '#' character.
   *
   * @see WebUtils#color2html(Color)
   * @testedby {@link GuiUtilsTest#testHexColor}
   */
  public static Color getColor(String hex) {
    if (hex.startsWith("#")) {
      hex = hex.substring(1);
    }
    return new Color(Integer.parseInt(hex, 16));
  }

  private static int getHeight(Image img) {
    int v = img.getHeight(null);
    if (v != -1)
      return v;
    // handle the case where the image is still being loaded
    BlockingImageObserver observer = new BlockingImageObserver();
    img.getHeight(observer);
    observer.block();
    return getHeight(img);
  }

  public static BufferedImage getImage(JComponent panel) {
    assert panel.getWidth() != 0 && panel.getHeight() != 0;
    panel.doLayout(); // This seems necessary to draw without displaying
              // anything
    BufferedImage img = new BufferedImage(panel.getWidth(),
        panel.getHeight(), BufferedImage.TYPE_INT_ARGB);
    Graphics g = img.getGraphics();
    panel.paint(g);
    g.dispose();
    return img;
  }

  /**
   *
   * @param whiteness
   *            [0,1], 0 indicates black, 1 white
   * @return a randomly chosen colour of roughly the given level of
   *         light/darkness
   */
  public static Color getRandomColour(double whiteness) {
    assert MathUtils.isProb(whiteness) : whiteness;
    // This is not perfect but what the hell
    Random rnd = Utils.getRandom();
    float r = rnd.nextFloat();
    float g = rnd.nextFloat();
    float b = rnd.nextFloat();
    float sum = r + g + b;
    float s = 3 / sum;
    return new Color(Math.min(r / s, 1), Math.min(g / s, 1), Math.min(
        b / s, 1));
  }

  private static int getWidth(Image img) {
    int v = img.getWidth(null);
    if (v != -1)
      return v;
    // handle the case where the image is still being loaded
    BlockingImageObserver observer = new BlockingImageObserver();
    img.getWidth(observer);
    observer.block();
    return img.getHeight(null);
  }

  /**
   * @return true if you there is a user you can ask for input. true by
   *         default.
   *         <p>
   *         This is set by the environment variable WINTERWELL_HEADLESS, with
   *         WINTERWELL_HEADLESS=true meaning interactive is false. See
   *         http://blog.plover.com/prog/sh-flags.html
   *         <p>
   *         If not set, it uses {@link GraphicsEnvironment#isHeadless()}
   */
  public static boolean isInteractive() {
    String envVar = System.getProperty("WINTERWELL_HEADLESS");
    if (envVar == null)
      return !GraphicsEnvironment.isHeadless();
    return !envVar.toLowerCase().equals("true");
  }

  public static BufferedImage load(File imgFile) throws WrappedException {
    assert imgFile.exists() : imgFile.getPath()
        + " does not exist! absolute-path=" + imgFile.getAbsolutePath();
    try {
      return ImageIO.read(imgFile);
    } catch (IOException e) {
      throw new IORException(imgFile + " caused " + e);
    }
  }

  /**
   * Because I find Swing's action setup confusing. So this tries to be more
   * like JavaScript
   *
   * @param button
   * @param eventHandler
   * @return
   */
  public static JButton onClick(final JButton button,
      final EventHandler eventHandler) {
    button.setAction(new AbstractAction() {
      /**
       *
       */
      private static final long serialVersionUID = 1L;

      @Override
      public void actionPerformed(ActionEvent e) {
        eventHandler.onClick(button);
      }
    });
    return button;
  }

  public static JFrame popup(Component component, String title) {
    JFrame frame = new JFrame(title);
    frame.add(component);
    frame.pack();
    frame.validate();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    return frame;
  }

  /**
   * Display in a popup frame.
   *
   * @param img
   * @param title
   * @return the frame, which should now be visible
   */
  public static JFrame popup(Image img, String title) {
    assert img != null;
    JFrame frame = new JFrame(title);
    ImageIcon icon = new ImageIcon(img);
    frame.add(new JLabel(icon));
    frame.pack();
    frame.validate();
    frame.setVisible(true);
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    return frame;
  }

  public static void popupAndBlock(Image img) {
    JFrame f = popup(img, "");
    blockWhileOpen(f);
  }

  /**
   * Save a JComponent (e.g. a JFreeChart) as an image.
   *
   * @param panel
   *            the panle to save
   * @param file
   *            This will determine the format (e.g. "myfile.gif" will result
   *            in a gif file)
   * @throws IORException
   *             If something goes wrong
   * @see #saveImage(Image, File) which this method wraps
   */
  public static void saveAsImage(JComponent panel, File file) {
    BufferedImage img = getImage(panel);
    saveImage(img, file);
  }

  /**
   *
   * @param image
   *            The image to save
   * @param file
   *            This will determine the format (e.g. "myfile.gif" will result
   *            in a gif file)
   * @throws IORException
   *             If something goes wrong
   * @see #saveImageToStream(Image, String, OutputStream) which this method
   *      wraps
   */
  public static void saveImage(Image image, File file)
      throws WrappedException {
    try {
      String formatName = FileUtils.getType(file);
      FileOutputStream fout = new FileOutputStream(file);
      saveImageToStream(image, formatName, fout);
      // FileUtils.close(fout);
    } catch (IOException e) {
      throw new IORException(e);
    }
  }

  /**
   * Save an image to an OutputStream
   *
   * @param img
   * @param formatName
   *            E.g. "gif"
   * @param stream
   *            Save to this stream and close it
   * @see #saveImage(Image, File)
   */
  public static void saveImageToStream(Image img, String formatName,
      OutputStream stream) {
    try {
      // Get a RenderedImage
      RenderedImage rImg;
      if (img instanceof RenderedImage) {
        rImg = (RenderedImage) img;
      } else {
        BufferedImage bImg = new BufferedImage(getWidth(img),
            getHeight(img), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bImg.createGraphics();
        boolean ok = g.drawImage(img, 0, 0, null);
        if (!ok) { // handle the case where the image is still being
              // loaded
          BlockingImageObserver observer = new BlockingImageObserver();
          g.drawImage(img, 0, 0, observer);
          observer.block();
          g.drawImage(img, 0, 0, null); // ??Why is this necessary?
        }
        g.dispose();
        rImg = bImg;
      }
      // Write and close
      ImageIO.write(rImg, formatName, stream);
      FileUtils.close(stream);
    } catch (IOException e) {
      throw new IORException(e);
    }
  }

  /**
   * TODO how is scaling done? is it smart or dumb?
   *
   * @param img
   * @param out
   *            Draw over this
   */
  public static void scaleImage(Image img, BufferedImage out) {
    Graphics2D g = out.createGraphics();
    int width = out.getWidth();
    int height = out.getHeight();
    BlockingImageObserver observer = new BlockingImageObserver();
    boolean ok = g.drawImage(img, 0, 0, width, height, observer);
    if (!ok) { // handle the case where the image is still being loaded
      observer.block();
    }
    g.dispose();
  }

  /**
   * Create a copy of an image, scaled to the given size.
   *
   * @param img
   * @param width
   * @param height
   * @return
   */
  public static BufferedImage scaleImage(Image img, int width, int height) {
    assert width > 0 && height > 0 && img != null;
    int type = BufferedImage.TYPE_INT_ARGB;
    if (img instanceof BufferedImage) {
      type = ((BufferedImage) img).getType();
      if (type == BufferedImage.TYPE_CUSTOM) {
        type = BufferedImage.TYPE_INT_ARGB;
      }
    }
    BufferedImage bImg = new BufferedImage(width, height, type);
    scaleImage(img, bImg);
    return bImg;
  }

  /**
   *
   * @param msg
   * @param dir
   *            The starting directory. null for the user's directory
   * @return selected file or null
   */
  public static File selectFile(String msg, File dir) {
    JFileChooser fc = new JFileChooser();
    fc.setCurrentDirectory(dir);
    fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    // fc.setAcceptAllFileFilterUsed(true);
    // if (regexFilter!=null)
    // fc.setFileFilter(FileUtils.getRegexFilter(regexFilter));
    int ok = fc.showDialog(null, msg);
    if (ok == JFileChooser.APPROVE_OPTION)
      return fc.getSelectedFile();
    return null;
  }

}
TOP

Related Classes of winterwell.utils.gui.GuiUtils$EventHandler

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.