content: package io.github.andrewauclair.moderndocking.internal.util;
  
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Font;
  import java.awt.FontMetrics;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.RenderingHints;
  import java.awt.Toolkit;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.util.Map;
  import javax.swing.Icon;
  import javax.swing.JComponent;
  
  /**
   *  The TextIcon will paint a String of text as an Icon. The Icon
   *  can be used by any Swing component that supports icons.
  
   *  TextIcon supports two different layout styles:
   *  <ul>
   *  <li>Horizontally - does normal rendering of the text by using the
   *	  Graphics.drawString(...) method
   *  <li>Vertically - Each character is displayed on a separate line
   *  </ul>
   *
   *  TextIcon was designed to be rendered on a specific JComponent as it
   *  requires FontMetrics information in order to calculate its size and to do
   *  the rendering. Therefore, it should only be added to component it was
   *  created for.
  
   *  By default, the text will be rendered using the Font and foreground color
   *  of its associated component. However, this class does allow you to override
   *  these properties. Also starting in JDK6 the desktop renderering hints will
   *  be used to renderer the text. For versions not supporting the rendering
   *  hints antialiasing will be turned on.
   */
  public class TextIcon implements Icon, PropertyChangeListener
  {
  	/**
  	 * Layout of text icon
  	 */
  	public enum Layout
  	{
  		/**
  		 * Text is horizontal in the icon
  		 */
  		HORIZONTAL,
  		/**
  		 * Text is vertical in the icon
  		 */
  		VERTICAL
  	}
  
  	private final JComponent component;
  
  	private final Layout layout;
  
  	private String text;
  
  	private Font font;
  
  	private Color foreground;
  
  	private int padding;
  
  	//  Used for the implementation of Icon interface
  
  	private int iconWidth;
  	private int iconHeight;
  
  	//  Used for Layout.VERTICAL to save reparsing the text every time the
  	//  icon is repainted
  
  	private String[] strings;
  	private int[] stringWidths;
  
  	/**
  	 *  Convenience constructor to create a TextIcon with a HORIZONTAL layout.
  	 *
  	 *  @param component  the component to which the icon will be added
  	 *  @param text       the text to be rendered on the Icon
  	 */
  	public TextIcon(JComponent component, String text)
  	{
  		this(component, text, Layout.HORIZONTAL);
  	}
  
  	/**
  	 *  Create a TextIcon specifying all the properties.
  	 *
  	 *  @param component  the component to which the icon will be added
  	 *  @param text       the text to be rendered on the Icon
  	 *  @param layout     specify the layout of the text. Must be one of
  	 *	                  the Layout enums: HORIZONTAL or VERTICAL
  	 */
  	public TextIcon(JComponent component, String text, Layout layout)
  	{
  		this.component = component;
  		this.layout = layout;
  		setText( text );
  
  		component.addPropertyChangeListener("font", this);
  	}
  
  	/**
  	 *  Get the Layout enum
  	 *
  	 *  @return the Layout enum
  	 */
  	public Layout getLayout()
  	{
  		return layout;
  	}
  
  	/**
  	 *  Get the text String that will be rendered on the Icon
  	 *
  	 *  @return the text of the Icon
  	 */
  	public String getText()
  	{
  		return text;
  	}
  
  	/**
  	 *  Set the text to be rendered on the Icon
  	 *
  	 *  @param text  the text to be rendered on the Icon
  	 */
  	public void setText(String text)
  	{
  		this.text = text;
  
  		calculateIconDimensions();
  	}
  
  	/**
  	 *  Get the Font used to render the text. This will default to the Font
  	 *  of the component unless the Font has been overridden by using the
  	 *  setFont() method.
  	 *
  	 *  @return the Font used to render the text
  	 */
  	public Font getFont()
  	{
  		if (font == null) {
  			return component.getFont();
  		}
  		else {
  			return font;
  		}
  	}
  
  	/**
  	 *  Set the Font to be used for rendering the text
  	 *
  	 *  @param font  the Font to be used for rendering the text
  	 */
  	public void setFont(Font font)
  	{
  		this.font = font;
  
  		calculateIconDimensions();
  	}
  
  	/**
  	 *  Get the foreground Color used to render the text. This will default to
  	 *  the foreground Color of the component unless the foreground Color has
  	 *  been overridden by using the setForeground() method.
  	 *
  	 *  @return the Color used to render the text
  	 */
  	public Color getForeground()
  	{
  		if (foreground == null) {
  			return component.getForeground();
  		}
  		else {
  			return foreground;
  		}
  	}
  
  	/**
  	 *  Set the foreground Color to be used for rendering the text
  	 *
  	 *  @param foreground  the foreground Color to be used for rendering the text
  	 */
  	public void setForeground(Color foreground)
  	{
  		this.foreground = foreground;
  		component.repaint();
  	}
  
  	/**
  	 *  Get the padding used when rendering the text
  	 *
  	 *  @return the padding specified in pixels
  	 */
  	public int getPadding()
  	{
  		return padding;
  	}
  
  	/**
  	 *  By default, the size of the Icon is based on the size of the rendered
  	 *  text. You can specify some padding to be added to the start and end
  	 *  of the text when it is rendered.
  	 *
  	 *  @param padding  the padding amount in pixels
  	 */
  	public void setPadding(int padding)
  	{
  		this.padding = padding;
  
  		calculateIconDimensions();
  	}
  
  	/**
  	 *  Calculate the size of the Icon using the FontMetrics of the Font.
  	 */
  	private void calculateIconDimensions()
  	{
  		Font font = getFont();
  		FontMetrics fm = component.getFontMetrics( font );
  
  		if (layout == Layout.HORIZONTAL)
  		{
  		 	iconWidth = fm.stringWidth( text ) + (padding * 2);
  		 	iconHeight = fm.getHeight();
  		}
  		else if (layout == Layout.VERTICAL)
  		{
  			int maxWidth = 0;
  			strings = new String[text.length()];
  			stringWidths = new int[text.length()];
  
  			//  Find the widest character in the text string
  
  			for (int i = 0; i < text.length(); i++)
  			{
  				strings[i] = text.substring(i, i + 1);
  				stringWidths[i] = fm.stringWidth( strings[i] );
  				maxWidth = Math.max(maxWidth, stringWidths[i]);
  			}
  
  			//  Add a minimum of 2 extra pixels, plus the leading value,
  			//  on each side of the character.
  
  			iconWidth = maxWidth + ((fm.getLeading() + 2) * 2);
  
  			//  Decrease then normal gap betweens lines of text by taking into
  			//  account the descent.
  
  			iconHeight = (fm.getHeight() - fm.getDescent()) * text.length();
  			iconHeight += padding * 2;
  		}
  
  		component.revalidate();
  	}
  //
  //  Implement the Icon Interface
  //
  	/**
  	 *  Gets the width of this icon.
  	 *
  	 *  @return the width of the icon in pixels.
  	 */
  	@Override
  	public int getIconWidth()
  	{
  		return iconWidth;
  	}
  
  	/**
  	 *  Gets the height of this icon.
  	 *
  	 *  @return the height of the icon in pixels.
  	 */
  	@Override
  	public int getIconHeight()
  	{
  		return iconHeight;
  	}
  
     /**
  	*  Paint the icons of this compound icon at the specified location
  	*
  	*  @param c The component to which the icon is added
  	*  @param g the graphics context
  	*  @param x the X coordinate of the icon's top-left corner
  	*  @param y the Y coordinate of the icon's top-left corner
  	*/
  	@Override
  	public void paintIcon(Component c, Graphics g, int x, int y)
  	{
  		Graphics2D g2 = (Graphics2D)g.create();
  
  		//  The "desktophints" is supported in JDK6
  
  		Toolkit toolkit = Toolkit.getDefaultToolkit();
  		Map map = (Map)(toolkit.getDesktopProperty("awt.font.desktophints"));
  
  		if (map != null) {
  			g2.addRenderingHints(map);
  		}
  		else {
  			g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
  					RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  		}
  
  		g2.setFont( getFont() );
  		g2.setColor( getForeground() );
  		FontMetrics fm = g2.getFontMetrics();
  
  		if (layout == Layout.HORIZONTAL)
  		{
  			g2.translate(x, y +	fm.getAscent());
  			g2.drawString(text, padding, 0);
  		}
  		else if (layout == Layout.VERTICAL)
  		{
  			int offsetY = fm.getAscent() - fm.getDescent() + padding;
  			int incrementY = fm.getHeight() - fm.getDescent();
  
  			for (int i = 0; i < text.length(); i++)
  			{
  				int offsetX = Math.round((getIconWidth() - stringWidths[i]) / 2.0f);
  				g2.drawString(strings[i], x + offsetX, y + offsetY);
  				offsetY += incrementY;
  			}
  		}
  
  		g2.dispose();
  	}
  //
  //  Implement the PropertyChangeListener interface
  //
  	public void propertyChange(PropertyChangeEvent e)
  	{
  		//  Handle font change when using the default font
  
  		if (font == null) {
  			calculateIconDimensions();
  		}
  	}
  }