/* * org.openmicroscopy.shoola.util.ui.tdialog.TitlePainter * *------------------------------------------------------------------------------ * Copyright (C) 2006 University of Dundee. All rights reserved. * * * 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 2 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, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package org.openmicroscopy.shoola.util.ui.tdialog; //Java imports import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; //Third-party libraries //Application-internal dependencies /** * Paints the title string on the {@link TitleBar} of the {@link TinyDialog}. * * @author Jean-Marie Burel      * <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> * @author <br>Andrea Falconi      * <a href="mailto:a.falconi@dundee.ac.uk"> * a.falconi@dundee.ac.uk</a> * @version 2.2 * <small> * (<b>Internal version:</b> $Revision: 4695 $ $Date: 2006-12-15 17:08:05 +0000 (Fri, 15 Dec 2006) $) * </small> * @since OME2.2 */ class TitlePainter { /** Color to draw the line 1 in the pattern. */ private static final Color ROW_1 = new Color (227, 245, 238); /** Color to draw the line 2 in the pattern. */ private static final Color ROW_2 = new Color(242, 252, 248); /** Color to draw the line 3 in the pattern. */ private static final Color ROW_3 = new Color(253, 251, 251); /** The string to paint. */ private String title; /** The font to use for painting. */ private Font font; /** * Tells if the current {@link #font} will fit into the specified height. * That is, if the maximum height that text rendered in the current * {@link #font} on the given graphics context would occupy is less or * equal to <code>availHeight</code>. * * @param availHeight The available height in which the font should fit. * @param g2D The graphics context in which the font will be rendered. * @return <code>true</code> if the current {@link #font} fits into the * <code>availHeight</code>, <code>false</code> otherwise. */ private boolean isFontSuitable(int availHeight, Graphics2D g2D) { FontMetrics fm = g2D.getFontMetrics(font); int maxH = fm.getMaxAscent()+fm.getMaxDescent(); return (maxH <= availHeight); } /** * Sets {@link #font} to a derived font such that {@link #title} can be * rendered on the given graphics context within the specified height. * * @param availHeight The available height in which {@link #title} should * fit. * @param g2D The graphics context in which {@link #title} will be rendered. */ private void ensureSuitableFont(int availHeight, Graphics2D g2D) { float size = font.getSize2D(); while (1 < size && !isFontSuitable(availHeight, g2D)) { size -= 0.5f; font = font.deriveFont(size); } } //NOTE: After the first invocation of doPaint, the font won't change. //In fact, the available height is always the same -- is the height //of the title bar, which is fixed. /** * Creates a substring from {@link #title} such that it'll fit the * <code>availWidth</code>. * * @param availWidth The available width in which the returned string * should fit. * @param g2D The graphics context in which the string will be rendered. * @return A substring of title that fits <code>availWidth</code>. If * no substring would fit, then <code>"..."</code> is returned. */ private String getDisplayTitle(int availWidth, Graphics2D g2D) { FontMetrics fm = g2D.getFontMetrics(); int len = title.length(), i; for (i = 0; i < len; ++i) { Rectangle2D bounds = fm.getStringBounds(title.substring(0, i), g2D); if (availWidth < bounds.getWidth()) break; } if (i == len) return title; //It all fits. ("" is irrelevant.) //If we're here, then i<len. So the loop exited b/c of the break. if (i <= 3) //"abc" or less doesn't fit; "..." is the best we can try then. //If it doesn't fit, don't care: g2D was clipped to availWidth. return "..."; //We have "abcd" at least and not all fits. We know that title[0,i] //surely fits. But it's kinda ugly to truncate text like that. We //want to add "..." to make it better looking. We know 3 < i and so //we can do title[0,i-3], which fits because title[0,i] does. Let's //try to append "..." to it. Even though we can be sure title[0,i-3] //+"..." will fit, we don't care: g2D was clipped to availWidth. return title.substring(0, i-3)+"..."; } /** * Creates a new instance to paint the specified <code>title</code>. * The <code>fontProto</code> is used to derive a font with the same * attributes, but with a size suitable for painting. That is, a size * such that the <code>title</code>'s height won't exceed the height * of the available painting area. * * @param fontProto The font prototype to derive the a suitable font for * painting. Mustn't be <code>null</code>. */ TitlePainter(Font fontProto) { if (fontProto == null) throw new NullPointerException("No font proto."); font = fontProto; title = ""; } /** * Sets the title string. * * @param t The string to paint. If <code>null</code>, nothing will * be painted. */ void setTitle(String t) { if (t == null) t = ""; title = t; } /** * Derives the default font of the painter. * * @param style The new style to set. */ void setFontStyle(int style) { font = font.deriveFont(style); } /** * Paints the background on <code>area</code>. * * @param g2D The graphics context. * @param width The width of the area. * @param height The height of the area. */ protected void doPaintBg(Graphics2D g2D, int width, int height) { //Draw the pattern. for(int y = 0; y < height; y += 3) { //Row 1. g2D.setColor(ROW_1); g2D.drawLine(0, y, width, y); //Row 2. g2D.setColor(ROW_2); g2D.drawLine(0, y+1, width, y+1); //Row 3. g2D.setColor(ROW_3); g2D.drawLine(0, y+2, width, y+2); } //NOTE: If h%3 != 0, the above will draw more lines than h. //Don't care: the graphics context has already been clipped //to Rect[0, 0, width, height]. } /** * Paints the title on <code>area</code>. * * @param g2D The graphics context. * @param width The width of the area. * @param height The height of the area. */ protected void doPaintTitle(Graphics2D g2D, int width, int height) { //Make sure we have a font such that title's height will fit into area. ensureSuitableFont(height, g2D); //Center the title vertically, clip it if too long, and draw it. g2D.setColor(Color.BLACK); g2D.setFont(font); //Set current font and *then* get fm. FontMetrics fm = g2D.getFontMetrics(); //NB: fm is for font now. int baseline = (height+fm.getAscent()-fm.getDescent())/2; g2D.drawString(getDisplayTitle(width, g2D), 0, baseline); } /** * Paints the title on the given <code>titleArea</code> * and the backgroung on the the given <code>bgArea</code>. * * @param g2D The graphics context. Mustn't be <code>null</code>. * @param titleArea The title area to paint. Mustn't be <code>null</code>. * @param bgArea The backgroung area to paint. * Mustn't be <code>null</code>. */ void paint(Graphics2D g2D, Rectangle titleArea, Rectangle bgArea) { if (g2D == null) throw new NullPointerException("No graphics context."); if (titleArea == null) throw new NullPointerException("No title area."); if (bgArea == null) throw new NullPointerException("No background area."); Graphics2D scratchGraphics = (Graphics2D) g2D.create(bgArea.x, bgArea.y, bgArea.width, bgArea.height); doPaintBg(scratchGraphics, bgArea.width, bgArea.height); scratchGraphics.dispose(); scratchGraphics = (Graphics2D) g2D.create(titleArea.x, titleArea.y, titleArea.width, titleArea.height); doPaintTitle(scratchGraphics, titleArea.width, titleArea.height); scratchGraphics.dispose(); } }