package org.jabref.gui.util.component; import java.awt.Component; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicLabelUI; /** * A UI delegate for JLabel that rotates the label 90° * <P> * Extends {@link BasicLabelUI}. * <P> * The only difference between the appearance of labels in the Basic and Metal L&Fs is the manner in which diabled text * is painted. As VerticalLabelUI does not override the method paintDisabledText, this class can be adapted for Metal * L&F by extending MetalLabelUI instead of BasicLabelUI. * <P> * No other changes are required. * * @author Darryl */ public class VerticalLabelUI extends BasicLabelUI { private final boolean clockwise; // see comment in BasicLabelUI private Rectangle verticalViewR = new Rectangle(); private Rectangle verticalIconR = new Rectangle(); private Rectangle verticalTextR = new Rectangle(); /** * Constructs a <code>VerticalLabelUI</code> with the desired rotation. * <P> * @param clockwise true to rotate clockwise, false for anticlockwise */ public VerticalLabelUI(boolean clockwise) { this.clockwise = clockwise; } /** * Overridden to always return -1, since a vertical label does not have a * meaningful baseline. * * @see ComponentUI#getBaseline(JComponent, int, int) */ @Override public int getBaseline(JComponent c, int width, int height) { super.getBaseline(c, width, height); return -1; } /** * Overridden to always return Component.BaselineResizeBehavior.OTHER, * since a vertical label does not have a meaningful baseline * * @see ComponentUI#getBaselineResizeBehavior(javax.swing.JComponent) */ @Override public Component.BaselineResizeBehavior getBaselineResizeBehavior(JComponent c) { super.getBaselineResizeBehavior(c); return Component.BaselineResizeBehavior.OTHER; } /** * Transposes the view rectangles as appropriate for a vertical view * before invoking the super method and copies them after they have been * altered by {@link SwingUtilities#layoutCompoundLabel(FontMetrics, String, * Icon, int, int, int, int, Rectangle, Rectangle, Rectangle, int)} */ @Override protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, Icon icon, Rectangle viewR, Rectangle iconR, Rectangle textR) { String result = text; verticalViewR = transposeRectangle(viewR, verticalViewR); verticalIconR = transposeRectangle(iconR, verticalIconR); verticalTextR = transposeRectangle(textR, verticalTextR); result = super.layoutCL(label, fontMetrics, result, icon, verticalViewR, verticalIconR, verticalTextR); copyRectangle(verticalViewR, viewR); copyRectangle(verticalIconR, iconR); copyRectangle(verticalTextR, textR); return result; } /** * Transforms the Graphics for vertical rendering and invokes the * super method. */ @Override public void paint(Graphics g, JComponent c) { Graphics2D g2 = (Graphics2D) g.create(); if (clockwise) { g2.rotate(Math.PI / 2, c.getSize().width / 2.0, c.getSize().width / 2.0); } else { g2.rotate(-Math.PI / 2, c.getSize().height / 2.0, c.getSize().height / 2.0); } super.paint(g2, c); } /** * Returns a Dimension appropriate for vertical rendering * * @see ComponentUI#getPreferredSize(javax.swing.JComponent) */ @Override public Dimension getPreferredSize(JComponent c) { return transposeDimension(super.getPreferredSize(c)); } /** * Returns a Dimension appropriate for vertical rendering * * @see ComponentUI#getMaximumSize(javax.swing.JComponent) */ @Override public Dimension getMaximumSize(JComponent c) { return transposeDimension(super.getMaximumSize(c)); } /** * Returns a Dimension appropriate for vertical rendering * * @see ComponentUI#getMinimumSize(javax.swing.JComponent) */ @Override public Dimension getMinimumSize(JComponent c) { return transposeDimension(super.getMinimumSize(c)); } private static Dimension transposeDimension(Dimension from) { return new Dimension(from.height, from.width + 2); } private static Rectangle transposeRectangle(Rectangle from, Rectangle to) { Rectangle destination = to; if (destination == null) { destination = new Rectangle(); } destination.x = from.y; destination.y = from.x; destination.width = from.height; destination.height = from.width; return destination; } private static void copyRectangle(Rectangle from, Rectangle to) { if (to == null) { return; } to.x = from.x; to.y = from.y; to.width = from.width; to.height = from.height; } }