/* 
 * This code is part of Project Waterloo from King's College London
 * 
 *
 * Copyright King's College London  2011-
 * 
 * @author Malcolm Lidierth, King's College London  [Contact]
 * 
 * Project Waterloo 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 3 of the License, or
 * (at your option) any later version.
 *
 * Project Waterloo 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 program.  If not, see .
 *
 */
package kcl.waterloo.graphics;

import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import kcl.waterloo.graphics.plots2D.GJPlotInterface;
import kcl.waterloo.math.ArrayUtils;

/**
 * Color bar. Provides a key for interpreting the color levels in a plot.
 *
 * @author ML
 */
public class GJColorBar extends GJRoi implements ActionListener {

    /**
     * The plot with which this color bar is associated.
     */
    private GJPlotInterface parentPlot;
    /**
     * Pop up menu. Publicly accessible via getPopup so user settable/editable.
     */
    private JPopupMenu popup;

    /**
     * Enum specifying possible orientations: VERTICAL or HORIZONTAL.
     */
    public enum ORIENTATION {

        /**
         * Vertically oriented.
         */
        VERTICAL,
        /**
         * Horizontally oriented.
         */
        HORIZONTAL
    }

    /**
     * Current orientation
     */
    private ORIENTATION orientation = ORIENTATION.VERTICAL;

    /**
     * Enum specifying possible label positions: CENTER or BORDER.
     */
    public enum LABELPOSITION {

        /**
         * Label for the Nth color will be drawn at the center of the color box.
         */
        CENTER,
        /**
         * Label for the Nth color will be drawn at the border of the Nth with
         * the N+1th color box.
         */
        BORDER
    }

    /**
     * Labels for the color boxes in the color bar.
     *
     */
    private String[] labels = null;
    /**
     * Position on the labels.
     */
    private LABELPOSITION labelPosition = LABELPOSITION.BORDER;
    private int labelInterval = 1;

    public GJColorBar() {
        super();
        setBorder(null);
        removeIcons();
        setBackgroundPainted(false);
        addPopUp();
        minSiz = 20;
    }

    /**
     * Factory method for creating an instance in the center of the specified
     * graph.
     *
     * @param gr the target graph
     * @return
     */
    public static GJColorBar createInstance(GJPlotInterface plot) {
        GJAbstractGraph gr = (GJAbstractGraph) plot.getParentGraph();
        Rectangle2D r = gr.getAxesBounds();
        return createInstance(plot, new Rectangle2D.Double(r.getX() + r.getWidth() - (0.15 * r.getWidth()),
                r.getY() + r.getHeight() - (0.5 * r.getHeight()),
                0.05 * r.getWidth(),
                0.4 * r.getHeight()));
    }

    /**
     * Factory method for creating an instance.
     *
     * @param plot
     * @param r a Rectangle2D in axes units
     * @return
     */
    public static GJColorBar createInstance(final GJPlotInterface plot, final Rectangle2D.Double r) {
        final GJAbstractGraph gr = (GJAbstractGraph) plot.getParentGraph();
        final GJColorBar colorbar = new GJColorBar();
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                colorbar.parentPlot = plot;
                gr.add(colorbar);
                colorbar.setAxesRectangle(r);
                if (gr.getGraphContainer() != null) {
                    gr.getGraphContainer().addComponentListener(colorbar);
                    gr.getGraphContainer().addPropertyChangeListener(colorbar);
                }
                gr.addPropertyChangeListener(colorbar);
                colorbar.setFont(gr.getFont().deriveFont(8));
                gr.repaint();
            }
        });
        return colorbar;
    }

    /**
     * @return the parentPlot
     */
    public GJPlotInterface getParentPlot() {
        return parentPlot;
    }

    /**
     * @param parentPlot the parentPlot to set
     */
    public void setParentPlot(GJPlotInterface p) {
        if (parentPlot != null && !p.getParentGraph().equals(parentPlot.getParentGraph())) {
            ((GJAbstractGraph) p.getParentGraph()).add(this);
        }
        parentPlot = p;
    }

    /**
     * @return the orientation
     */
    public ORIENTATION getOrientation() {
        return orientation;
    }

    /**
     * @param orientation the orientation to set
     */
    public void setOrientation(ORIENTATION orientation) {
        //ORIENTATION old = getOrientation();
        this.orientation = orientation;
        setPixelRectangle(new Rectangle2D.Double(getX(), getY(), getHeight(), getWidth()));
        //updateConstraints();
        revalidate();
        //this.firePropertyChange("orientation", old, orientation);
    }

    /**
     * @return the labels
     */
    public String[] getLabels() {
        return labels;
    }

    /**
     * @param labels the labels to set
     */
    public void setLabels(String[] labels) {
        this.labels = labels;
    }

    /**
     * @param labels the double[] values for the labels to set
     */
    public void setLabels(double[] labels) {
        setLabels(ArrayUtils.boxed(labels), "%3.2f");
    }

    /**
     * @param labels the labels to set
     */
    public void setLabels(double[] labels, String format) {
        setLabels(ArrayUtils.boxed(labels), format);
    }

    /**
     * @param labels the Double[] values for the labels to set
     */
    public void setLabels(Double[] labels) {
        setLabels(labels, "%3.2f");
    }

    /**
     * @param labels the Double[] values for the labels to set
     */
    public void setLabels(Double[] labels, String format) {
        this.labels = new String[labels.length];
        for (int k = 0; k < labels.length; k++) {
            if (labels[k].isNaN()) {
                this.labels[k] = "";
            } else {
                this.labels[k] = String.format(format, labels[k]);
            }
        }
    }

    /**
     * @return the labelPosition
     */
    public LABELPOSITION getLabelPosition() {
        return labelPosition;
    }

    /**
     * @param labelPosition the labelPosition to set
     */
    public void setLabelPosition(LABELPOSITION labelPosition) {
        this.labelPosition = labelPosition;
    }

    @Override
    public final void paintComponent(Graphics g) {
        if (parentPlot.getFill() != null && parentPlot.getFill().size() > 0) {
            Graphics2D g2 = (Graphics2D) g.create();

            paintBackground(g2);

            double inc;
            Rectangle2D bounds = getBounds();
            Rectangle2D r = new Rectangle2D.Double(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight());

            FontMetrics metrics = g2.getFontMetrics();
            int maxStringWidth = 0;
            int stringAscent = metrics.getAscent();
            if (labels != null) {
                for (int k = 0; k < labels.length; k++) {
                    if (!labels[k].isEmpty()) {
                        maxStringWidth = Math.max(maxStringWidth, metrics.stringWidth(labels[k]));
                    }
                }
            }

            switch (orientation) {
                case VERTICAL:
                    inc = (double) getHeight() / (double) parentPlot.getMultiplexLength();
                    if (labels == null) {
                        r.setRect(0, r.getHeight() - inc, r.getWidth(), inc);
                    } else {
                        r.setRect(0, r.getHeight() - inc, Math.max(r.getWidth() / 4d, r.getWidth() - 1.2 * maxStringWidth), inc);
                    }
                    for (int k = 0; k < parentPlot.getMultiplexLength(); k++) {
                        g2.setPaint(parentPlot.getFill().get(k));
                        g2.fill(r);
                        if (labels != null && k < labels.length && (Math.IEEEremainder((double) k, (double) labelInterval) == 0)) {
                            if (!labels[k].isEmpty()) {
                                g2.setPaint(getForeground());
                                if (labelPosition == LABELPOSITION.CENTER) {
                                    g2.drawString(labels[k], (float) (r.getWidth() + 2d), (float) (r.getY() + inc - stringAscent / 2d));
                                } else {
                                    if (k < labels.length - 1) {
                                        g2.drawString(labels[k], (float) (r.getWidth() + 2d), (float) (r.getY() + stringAscent / 2d));
                                    }
                                }
                            }
                        }
                        r.setRect(0, r.getY() - inc, r.getWidth(), inc);
                    }
                    break;
                case HORIZONTAL:
                    inc = (double) getWidth() / (double) parentPlot.getMultiplexLength();
                    if (labels == null) {
                        r.setRect(0, 0, inc, getHeight());
                    } else {
                        r.setRect(0, 0, inc, getHeight() / 4d);
                    }
                    AffineTransform af = g2.getTransform();
                    for (int k = 0; k < parentPlot.getMultiplexLength(); k++) {
                        g2.setPaint(parentPlot.getFill().get(k));
                        g2.fill(r);
                        if (labels != null && k < labels.length && (Math.IEEEremainder((double) k, (double) labelInterval) == 0)) {
                            if (!labels[k].isEmpty()) {
                                g2.setPaint(getForeground());
                                if (labelPosition == LABELPOSITION.CENTER) {
                                    g2.rotate(Math.PI / 2,
                                            (float) (r.getX() + inc / 2d - stringAscent / 2d),
                                            (float) (r.getHeight() + 2d));
                                    g2.drawString(labels[k], (float) (r.getX() + inc / 2d - stringAscent / 2d),
                                            (float) (r.getHeight() + 2d));
                                } else {
                                    if (k < labels.length - 1) {
                                        g2.rotate(Math.PI / 2,
                                                (float) (r.getX() + inc - stringAscent / 2d),
                                                (float) (r.getHeight() + 2d));
                                        g2.drawString(labels[k], (float) (r.getX() + inc - stringAscent / 2d),
                                                (float) (r.getHeight() + 2d));
                                    }
                                }
                            }
                        }
                        r.setRect(r.getX() + inc, 0, inc, r.getHeight());
                        g2.setTransform(af);
                    }
            }
            g2.dispose();
        }
    }

    private void addPopUp() {
        popup = new JPopupMenu();
        JMenu menu = new JMenu("Alignment");
        JMenuItem menuItem = menu.add(new JMenuItem("Vertical"));
        menuItem.setActionCommand("Vertical");
        menuItem.addActionListener(this);
        menuItem = menu.add(new JMenuItem("Horizontal"));
        menuItem.setActionCommand("Horizontal");
        menuItem.addActionListener(this);
        popup.add(menu);

        menu = new JMenu("Color Scheme");
        popup.add(menu);

        MouseListener popupListener = new PopupListener();
        addMouseListener(popupListener);
        popup.addMouseListener(popupListener);
    }

    class PopupListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            showPopup(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            showPopup(e);

        }

        private void showPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
                popup.show(e.getComponent(),
                        e.getX(), e.getY());
            }
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Vertical")) {
            setOrientation(ORIENTATION.VERTICAL);
        } else if (e.getActionCommand().equals("Horizontal")) {
            setOrientation(ORIENTATION.HORIZONTAL);
        }
    }

    /**
     * @return the labelInterval
     */
    public int getLabelInterval() {
        return labelInterval;
    }

    /**
     * @param labelInterval the labelInterval to set
     */
    public void setLabelInterval(int labelInterval) {
        this.labelInterval = labelInterval;
    }
}

 

Ads help maintain this website.