All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alee.painter.common.TitledBorderPainter Maven / Gradle / Ivy

Go to download

WebLaf is a Java Swing Look and Feel and extended components library for cross-platform applications

There is a newer version: 2.2.1
Show newest version
/*
 * This file is part of WebLookAndFeel library.
 *
 * WebLookAndFeel library 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.
 *
 * WebLookAndFeel library 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 WebLookAndFeel library.  If not, see .
 */

package com.alee.painter.common;

import com.alee.utils.GraphicsUtils;
import com.alee.utils.SwingUtils;

import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.util.Map;

/**
 * Titled border painter.
 *
 * @param  component type
 * @author Mikle Garin
 * @see com.alee.painter.common.BorderPainter
 * @see com.alee.painter.AbstractPainter
 * @see com.alee.painter.Painter
 */

public class TitledBorderPainter extends BorderPainter implements SwingConstants
{
    /**
     * todo 1. Left/Right title position
     * todo 2. Icon for title text
     * todo 3. Take title position into account when calculating preferred size & border
     */

    /**
     * Title side offset.
     */
    protected int titleOffset = 4;

    /**
     * Gap between title and border line.
     */
    protected int titleBorderGap = 3;

    /**
     * Title position relative to border.
     */
    protected TitlePosition titlePosition = TitlePosition.insideLine;

    /**
     * Title foreground.
     */
    protected Color foreground = null;

    /**
     * Painter background.
     */
    protected Color background = null;

    /**
     * Whether to clip background under the title or not.
     */
    protected boolean clipTitleBackground = true;

    /**
     * Title text alignment.
     */
    protected int titleAlignment;

    /**
     * Title text display side.
     */
    protected int titleSide;

    /**
     * Title text.
     */
    protected String titleText;

    /**
     * Runtime variables.
     */
    protected int w;
    protected int h;
    protected int sw;
    protected boolean emptyTitle;
    protected FontMetrics fontMetrics;
    protected int titleAreaHeight;
    protected int titleWidth;
    protected int titleX;
    protected int titleY;
    protected double borderCenter;
    protected double borderPosition;
    protected Shape borderShape;
    protected boolean doClip;

    public TitledBorderPainter ()
    {
        this ( null );
    }

    public TitledBorderPainter ( final String titleText )
    {
        this ( titleText, LEADING );
    }

    public TitledBorderPainter ( final String titleText, final int titleAlignment )
    {
        this ( titleText, titleAlignment, TOP );
    }

    public TitledBorderPainter ( final String titleText, final int titleAlignment, final int titleSide )
    {
        super ();
        this.titleText = titleText;
        this.titleAlignment = titleAlignment;
        this.titleSide = titleSide;
    }

    public int getTitleOffset ()
    {
        return titleOffset;
    }

    public void setTitleOffset ( final int titleOffset )
    {
        this.titleOffset = titleOffset;
        updateAll ();
    }

    public int getTitleBorderGap ()
    {
        return titleBorderGap;
    }

    public void setTitleBorderGap ( final int titleBorderGap )
    {
        this.titleBorderGap = titleBorderGap;
        updateAll ();
    }

    public int getTitleSide ()
    {
        return titleSide;
    }

    public void setTitleSide ( final int titleSide )
    {
        this.titleSide = titleSide;
        updateAll ();
    }

    public int getTitleAlignment ()
    {
        return titleAlignment;
    }

    public void setTitleAlignment ( final int titleAlignment )
    {
        this.titleAlignment = titleAlignment;
        repaint ();
    }

    public TitlePosition getTitlePosition ()
    {
        return titlePosition;
    }

    public void setTitlePosition ( final TitlePosition titlePosition )
    {
        this.titlePosition = titlePosition;
        repaint ();
    }

    public Color getForeground ()
    {
        return foreground;
    }

    public void setForeground ( final Color foreground )
    {
        this.foreground = foreground;
        repaint ();
    }

    public Color getBackground ()
    {
        return background;
    }

    public void setBackground ( final Color background )
    {
        this.background = background;
        repaint ();
    }

    public boolean isClipTitleBackground ()
    {
        return clipTitleBackground;
    }

    public void setClipTitleBackground ( final boolean clipTitleBackground )
    {
        this.clipTitleBackground = clipTitleBackground;
        repaint ();
    }

    public String getTitleText ()
    {
        return titleText;
    }

    public void setTitleText ( final String titleText )
    {
        this.titleText = titleText;
        updateAll ();
    }

    @Override
    public Insets getBorders ()
    {
        final Insets m = super.getBorders ();
        if ( !isEmptyTitle () )
        {
            switch ( titleSide )
            {
                case TOP:
                {
                    m.top += getTitleAreaHeight ( component );
                    break;
                }
                case LEFT:
                {
                    m.left += getTitleAreaHeight ( component );
                    break;
                }
                case BOTTOM:
                {
                    m.bottom += getTitleAreaHeight ( component );
                    break;
                }
                case RIGHT:
                {
                    m.right += getTitleAreaHeight ( component );
                    break;
                }
            }
        }
        return m;
    }

    @Override
    public void paint ( final Graphics2D g2d, final Rectangle bounds, final E c, final U ui )
    {
        // Initializing values
        w = c.getWidth ();
        h = c.getHeight ();
        sw = getStrokeWidth ();
        emptyTitle = isEmptyTitle ();
        fontMetrics = emptyTitle ? null : c.getFontMetrics ( c.getFont () );
        titleWidth = emptyTitle ? 0 : fontMetrics.stringWidth ( titleText );
        titleAreaHeight = getTitleAreaHeight ( c );
        titleX = getTitleX ( c );
        titleY = getTitleY ();
        borderCenter = ( double ) sw / 2;
        borderPosition = getBorderPosition ();
        borderShape = getBorderShape ();
        doClip = clipTitleBackground && !emptyTitle && titlePosition.equals ( TitlePosition.insideLine );

        // Drawing border and background

        final Object aa = GraphicsUtils.setupAntialias ( g2d );
        final Stroke os = GraphicsUtils.setupStroke ( g2d, stroke, stroke != null );

        // Drawing background when title is not on the border line
        if ( background != null && !doClip )
        {
            g2d.setPaint ( background );
            g2d.fill ( borderShape );
        }

        // Properly clipping border line for text space
        final Shape clipShape = doClip ? getBorderClipShape () : null;
        final Shape oldClip = GraphicsUtils.subtractClip ( g2d, clipShape, doClip );

        // Drawing clipped by text background
        if ( background != null && doClip )
        {
            g2d.setPaint ( background );
            g2d.fill ( borderShape );
        }

        // Drawing clipped border
        g2d.setPaint ( color );
        g2d.draw ( borderShape );

        GraphicsUtils.restoreClip ( g2d, oldClip, doClip );
        GraphicsUtils.restoreStroke ( g2d, os, stroke != null );
        GraphicsUtils.restoreAntialias ( g2d, aa );

        // Drawing text
        if ( !emptyTitle )
        {
            g2d.setPaint ( foreground != null ? foreground : c.getForeground () );
            switch ( titleSide )
            {
                case TOP:
                case BOTTOM:
                {
                    final Map hints = SwingUtils.setupTextAntialias ( g2d );
                    g2d.drawString ( titleText, titleX, titleY );
                    SwingUtils.restoreTextAntialias ( g2d, hints );
                    break;
                }
                case LEFT:
                case RIGHT:
                {
                    // todo
                    break;
                }
            }
        }
    }

    protected int getTitleX ( final E c )
    {
        if ( titleAlignment == LEFT || titleAlignment == LEADING && ltr ||
                titleAlignment == TRAILING && !ltr )
        {
            return Math.max ( sw, round ) + titleOffset + titleBorderGap;
        }
        else if ( titleAlignment == RIGHT || titleAlignment == TRAILING && ltr ||
                titleAlignment == LEADING && !ltr )
        {
            return w - Math.max ( sw, round ) - titleOffset - titleBorderGap -
                    titleWidth;
        }
        else
        {
            return w / 2 - titleWidth / 2;
        }
    }

    protected int getTitleY ()
    {
        final int fontDescent = fontMetrics != null ? fontMetrics.getDescent () : 0;
        switch ( titleSide )
        {
            case TOP:
            {
                return titlePosition.equals ( TitlePosition.aboveLive ) ? titleAreaHeight - sw - fontDescent :
                        titleAreaHeight - fontDescent;
            }
            case BOTTOM:
            {
                return titlePosition.equals ( TitlePosition.belowLine ) ? h - sw - fontDescent : h - fontDescent;
            }
            case LEFT:
            {
                // todo
                break;
            }
            case RIGHT:
            {
                // todo
                break;
            }
        }
        return 0;
    }

    protected double getBorderPosition ()
    {
        if ( emptyTitle )
        {
            return borderCenter;
        }
        else
        {
            if ( titlePosition.equals ( TitlePosition.insideLine ) )
            {
                return ( double ) titleAreaHeight / 2;
            }
            else if ( titlePosition.equals ( TitlePosition.aboveLive ) )
            {
                return titleAreaHeight - borderCenter;
            }
            else
            {
                return borderCenter;
            }
        }
    }

    protected int getTitleAreaHeight ( final E c )
    {
        if ( isEmptyTitle () )
        {
            return sw;
        }
        else
        {
            final int height = c.getFontMetrics ( c.getFont () ).getHeight ();
            return titlePosition.equals ( TitlePosition.insideLine ) ? height : height + sw;
        }
    }

    protected boolean isEmptyTitle ()
    {
        return titleText == null;
    }

    protected Shape getBorderShape ()
    {
        Rectangle2D rect = null;
        switch ( titleSide )
        {
            case TOP:
            {
                rect = new Rectangle2D.Double ( borderCenter, borderPosition, w - borderCenter * 2, h - borderPosition - borderCenter );
                break;
            }
            case LEFT:
            {
                rect = new Rectangle2D.Double ( borderPosition, borderCenter, w - borderPosition - borderCenter, h - borderCenter * 2 );
                break;
            }
            case BOTTOM:
            {
                rect = new Rectangle2D.Double ( borderCenter, borderCenter, w - borderCenter * 2, h - borderPosition - borderCenter );
                break;
            }
            case RIGHT:
            {
                rect = new Rectangle2D.Double ( borderCenter, borderCenter, w - borderPosition - borderCenter, h - borderCenter * 2 );
                break;
            }
        }
        return round > 0 ?
                new RoundRectangle2D.Double ( rect.getX (), rect.getY (), rect.getWidth (), rect.getHeight (), round * 2, round * 2 ) :
                rect;
    }

    protected Shape getBorderClipShape ()
    {
        if ( emptyTitle )
        {
            return null;
        }
        else
        {
            switch ( titleSide )
            {
                case TOP:
                {
                    return new RoundRectangle2D.Double ( titleX - titleBorderGap, borderPosition - titleAreaHeight / 2,
                            titleWidth + titleBorderGap * 2, titleAreaHeight, 3, 3 );
                }
                case BOTTOM:
                {
                    return new RoundRectangle2D.Double ( titleX - titleBorderGap, h - borderPosition - titleAreaHeight / 2,
                            titleWidth + titleBorderGap * 2, titleAreaHeight, 3, 3 );
                }
                case LEFT:
                {
                    // todo
                    return null;
                }
                case RIGHT:
                {
                    // todo
                    return null;
                }
            }
        }
        return null;
    }

    @Override
    public Dimension getPreferredSize ()
    {
        if ( isEmptyTitle () )
        {
            return super.getPreferredSize ();
        }
        else
        {
            final int titleAreaHeight = getTitleAreaHeight ( component );
            final int titleWidth = component.getFontMetrics ( component.getFont () ).stringWidth ( titleText );
            final int border = Math.max ( getStrokeWidth (), round );
            final int title = Math.max ( titleAreaHeight, border );
            switch ( titleSide )
            {
                case TOP:
                case BOTTOM:
                {
                    return new Dimension ( border * 2 + titleWidth + titleOffset * 2 +
                            titleBorderGap * 2, title + border );
                }
                case LEFT:
                case RIGHT:
                {
                    return new Dimension ( title + border, border * 2 + titleWidth + titleOffset * 2 +
                            titleBorderGap * 2 );
                }
            }
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy