/* * #%L * gitools-ui-platform * %% * Copyright (C) 2013 Universitat Pompeu Fabra - Biomedical Genomics group * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ package org.gitools.ui.platform.imageviewer; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; /** * A status bar implementation that display information based on a pixel of the image. Call the * {@link #setPixel(int, int)} function to specify which pixel it should display. The current implementation shows * the position and color of the pixel; override {@link #updateLabel(java.awt.image.BufferedImage, int, int, int)} to * customize this information. * * @author Kazó Csaba */ public class PixelInfoStatusBar extends StatusBar { private final JPanel statusBar; /** * The label displaying the info text. */ protected final JLabel label; private final Insets statusBarInsets; private PixelModel model; private PropertyChangeListener propertyChangeListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { update(); } }; private final ChangeListener modelListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { update(); } }; /** * Creates a new instance. */ public PixelInfoStatusBar() { statusBar = new JPanel(); statusBar.setBorder(BorderFactory.createEtchedBorder()); label = new JLabel("n/a"); statusBar.add(label); statusBarInsets = statusBar.getInsets(); setModel(new PixelModel()); } /** * Sets the model dictating the pixel shown by this status bar. * * @param newModel the new model * @throws NullPointerException if {@code newModel} is {@code null} */ public final void setModel(PixelModel newModel) { if (newModel == null) throw new NullPointerException(); if (model != newModel) { if (model != null) model.removeChangeListener(modelListener); model = newModel; model.addChangeListener(modelListener); update(); } } /** * Returns the model storing the pixel shown by this status bar. * * @return the current model; never {@code null} */ public PixelModel getModel() { return model; } @Override public final JComponent getComponent() { return statusBar; } /** * Sets the pixel this status bar is to display information on. The values may be arbitrary; you can use negative * values to indicate that there is nothing to display. * * @param x the x coordinate of the pixel * @param y the y coordinate of the pixel */ public void setPixel(int x, int y) { model.set(x, y); } /** * Updates the info label. This function is called when either the selected pixel * or the image shown in the viewer is changed. You can call this method to indicate * that the message should be updated for some different reason. */ protected final void update() { BufferedImage image = getImageViewer() == null ? null : getImageViewer().getImage(); if (image == null || model.isInvalid() || model.getX() >= image.getWidth() || model.getY() >= image.getHeight()) updateLabelNoData(); else updateLabel(image, model.getX(), model.getY(), statusBar.getWidth() - statusBarInsets.left - statusBarInsets.right); } /** * This function updates the contents of the {@link #label} to indicate that no data can be shown. By default, * this function is called by {@code update} when the image is {@code null} or the pixel to be shown is not within * bounds. */ protected void updateLabelNoData() { label.setText("n/a"); } /** * This function updates the contents of the {@link #label}. It is called when the highlighted pixel or the image changes, * and only when the image is not {@code null} and the pixel is within the bounds of the image. If either of these * conditions aren't true, the {@code update} function calls {@link #updateLabelNoData()} instead. * Override it to provide a custom message. * * @param image the current image displayed in the viewer * @param x the x coordinate of the pixel that should be displayed * @param y the y coordinate of the pixel that should be displayed * @param availableWidth the maximum label width that can be displayed; you can use this parameter to specify a shorter * message if there is not enough room */ protected void updateLabel(BufferedImage image, int x, int y, int availableWidth) { if (image.getRaster().getNumBands() == 1) { label.setText(String.format("%d, %d; intensity %d", x, y, image.getRaster().getSample(x, y, 0))); } else if (image.getRaster().getNumBands() == 4) { int rgb = image.getRGB(x, y); Color c = new Color(rgb, true); label.setText(String.format("%d, %d; color %d,%d,%d, alpha %d", x, y, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha())); } else { int rgb = image.getRGB(x, y); Color c = new Color(rgb); label.setText(String.format("%d, %d; color %d,%d,%d", x, y, c.getRed(), c.getGreen(), c.getBlue())); } if (availableWidth < label.getPreferredSize().width) { // not enough space, shorter version is required if (image.getRaster().getNumBands() == 1) { label.setText(String.format("%d, %d; %d", x, y, image.getRaster().getSample(x, y, 0))); } else if (image.getRaster().getNumBands() == 4) { int rgb = image.getRGB(x, y); Color c = new Color(rgb, true); label.setText(String.format("%d, %d; (%d,%d,%d,%d)", x, y, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha())); } else { int rgb = image.getRGB(x, y); Color c = new Color(rgb); label.setText(String.format("%d, %d; (%d,%d,%d)", x, y, c.getRed(), c.getGreen(), c.getBlue())); } } } @Override protected void register(ImageViewer viewer) { viewer.addPropertyChangeListener("image", propertyChangeListener); update(); } @Override protected void unregister(ImageViewer viewer) { viewer.removePropertyChangeListener("image", propertyChangeListener); } }