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

com.alee.painter.decoration.layout.IconTextLayout Maven / Gradle / Ivy

There is a newer version: 1.2.14
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.decoration.layout;

import com.alee.api.data.BoxOrientation;
import com.alee.painter.decoration.IDecoration;
import com.alee.utils.MathUtils;
import com.alee.utils.SwingUtils;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;

import javax.swing.*;
import java.awt.*;

/**
 * Abstract implementation of simple icon and text layout.
 * Main constraints are {@link #ICON} and {@link #TEXT} which are always placed in the middle of layout.
 * Side spacing constraints are also supported which place contents similar to {@link BorderLayout}.
 *
 * @param  component type
 * @param  decoration type
 * @param  layout type
 * @author Mikle Garin
 */
@XStreamAlias ( "IconTextLayout" )
public class IconTextLayout, I extends IconTextLayout>
        extends AbstractContentLayout implements SwingConstants
{
    /**
     * Layout constraints.
     */
    protected static final String ICON = "icon";
    protected static final String TEXT = "text";
    protected static final String TOP_SPACE = "top-space";
    protected static final String LEFT_SPACE = "left-space";
    protected static final String RIGHT_SPACE = "right-space";
    protected static final String BOTTOM_SPACE = "bottom-space";

    /**
     * Gap between icon and text contents.
     */
    @XStreamAsAttribute
    protected Integer gap;

    /**
     * Horizontal content alignment.
     */
    @XStreamAsAttribute
    protected BoxOrientation halign;

    /**
     * Vertical content alignment.
     */
    @XStreamAsAttribute
    protected BoxOrientation valign;

    /**
     * Horizontal text position.
     */
    @XStreamAsAttribute
    protected BoxOrientation hpos;

    /**
     * Vertical text position.
     */
    @XStreamAsAttribute
    protected BoxOrientation vpos;

    /**
     * Returns gap between icon and text contents.
     *
     * @param c painted component
     * @param d painted decoration state
     * @return gap between icon and text contents
     */
    protected int getIconTextGap ( final C c, final D d )
    {
        return gap != null ? gap : 0;
    }

    /**
     * Returns horizontal content alignment.
     *
     * @param c painted component
     * @param d painted decoration state
     * @return horizontal content alignment
     */
    protected int getHorizontalAlignment ( final C c, final D d )
    {
        return halign != null ? halign.getValue () : CENTER;
    }

    /**
     * Returns vertical content alignment.
     *
     * @param c painted component
     * @param d painted decoration state
     * @return vertical content alignment
     */
    protected int getVerticalAlignment ( final C c, final D d )
    {
        return valign != null ? valign.getValue () : CENTER;
    }

    /**
     * Returns horizontal text position.
     *
     * @param c painted component
     * @param d painted decoration state
     * @return horizontal text position
     */
    protected int getHorizontalTextPosition ( final C c, final D d )
    {
        return hpos != null ? hpos.getValue () : TRAILING;
    }

    /**
     * Returns vertical text position.
     *
     * @param c painted component
     * @param d painted decoration state
     * @return vertical text position
     */
    protected int getVerticalTextPosition ( final C c, final D d )
    {
        return vpos != null ? vpos.getValue () : CENTER;
    }

    @Override
    public ContentLayoutData layoutContent ( final C c, final D d, final Rectangle bounds )
    {
        final ContentLayoutData layoutData = new ContentLayoutData ( 2 );

        final Dimension available = bounds.getSize ();
        final boolean ltr = isLeftToRight ( c, d );
        final int halign = getHorizontalAlignment ( c, d );
        final int valign = getVerticalAlignment ( c, d );

        // Retrieving spacing preferred sizes
        final Dimension top = getPreferredSize ( c, d, TOP_SPACE, available );
        final Dimension left = getPreferredSize ( c, d, LEFT_SPACE, available );
        final Dimension right = getPreferredSize ( c, d, RIGHT_SPACE, available );
        final Dimension bottom = getPreferredSize ( c, d, BOTTOM_SPACE, available );

        // Calculating actual spacing sizes
        // We have to find maximum of two in case axis alignment for main content is CENTER
        final int lw = halign == CENTER ? Math.max ( left.width, right.width ) : left.width;
        final int rw = halign == CENTER ? Math.max ( left.width, right.width ) : right.width;
        final int th = valign == CENTER ? Math.max ( top.height, bottom.height ) : top.height;
        final int bh = valign == CENTER ? Math.max ( top.height, bottom.height ) : bottom.height;

        // Calculating icon and text preferred size
        final Dimension iconTextAvailable = new Dimension ( available.width - lw - rw, available.height - th - bh );
        final Dimension iconTextPS = getIconTextPreferredSize ( c, d, iconTextAvailable );

        // Adjusting available size
        iconTextPS.width = Math.max ( 0, Math.min ( iconTextPS.width, bounds.width - lw - rw ) );
        iconTextPS.height = Math.max ( 0, Math.min ( iconTextPS.height, bounds.height - th - bh ) );

        // Calculating smallest content bounds required for text and icon
        final Rectangle b = new Rectangle ( 0, 0, iconTextPS.width, iconTextPS.height );
        if ( halign == LEFT || halign == LEADING && ltr || halign == TRAILING && !ltr )
        {
            b.x = bounds.x + lw;
        }
        else if ( halign == CENTER )
        {
            b.x = bounds.x + bounds.width / 2 - iconTextPS.width / 2;
        }
        else
        {
            b.x = bounds.x + bounds.width - iconTextPS.width - rw;
        }
        if ( valign == TOP )
        {
            b.y = bounds.y + th;
        }
        else if ( valign == CENTER )
        {
            b.y = bounds.y + bounds.height / 2 - iconTextPS.height / 2;
        }
        else
        {
            b.y = bounds.y + bounds.height - iconTextPS.height - bh;
        }

        // Calculating spacings positioning
        if ( !isEmpty ( c, d, TOP_SPACE ) )
        {
            layoutData.put ( TOP_SPACE, new Rectangle ( bounds.x, bounds.y,
                    bounds.width, b.y - bounds.y ) );
        }
        if ( !isEmpty ( c, d, LEFT_SPACE ) )
        {
            layoutData.put ( LEFT_SPACE, new Rectangle ( bounds.x, b.y,
                    b.x - bounds.x, b.height ) );
        }
        if ( !isEmpty ( c, d, RIGHT_SPACE ) )
        {
            layoutData.put ( RIGHT_SPACE, new Rectangle ( b.x + b.width, b.y,
                    bounds.x + bounds.width - b.x - b.width, b.height ) );
        }
        if ( !isEmpty ( c, d, BOTTOM_SPACE ) )
        {
            layoutData.put ( BOTTOM_SPACE, new Rectangle ( bounds.x, b.y + b.height,
                    bounds.width, bounds.y + bounds.height - b.y - b.height ) );
        }

        // Calculating text and icon positioning
        final boolean hasIcon = !isEmpty ( c, d, ICON );
        final boolean hasText = !isEmpty ( c, d, TEXT );
        if ( hasIcon && hasText )
        {
            final int hpos = getHorizontalTextPosition ( c, d );
            final int vpos = getVerticalTextPosition ( c, d );
            if ( hpos != CENTER || vpos != CENTER )
            {
                final Dimension ips = getPreferredSize ( c, d, ICON, available );
                final int gap = getIconTextGap ( c, d );
                if ( hpos == RIGHT || hpos == TRAILING && ltr )
                {
                    layoutData.put ( ICON, new Rectangle ( b.x, b.y, ips.width, b.height ) );
                    layoutData.put ( TEXT, new Rectangle ( b.x + gap + ips.width, b.y, b.width - ips.width - gap, b.height ) );
                }
                else if ( hpos == CENTER )
                {
                    if ( vpos == TOP )
                    {
                        layoutData.put ( ICON, new Rectangle ( b.x, b.y + b.height - ips.height, b.width, ips.height ) );
                        layoutData.put ( TEXT, new Rectangle ( b.x, b.y, b.width, b.height - gap - ips.height ) );
                    }
                    else
                    {
                        layoutData.put ( ICON, new Rectangle ( b.x, b.y, b.width, ips.height ) );
                        layoutData.put ( TEXT, new Rectangle ( b.x, b.y + ips.height + gap, b.width, b.height - ips.height - gap ) );
                    }
                }
                else
                {
                    layoutData.put ( ICON, new Rectangle ( b.x + b.width - ips.width, b.y, ips.width, b.height ) );
                    layoutData.put ( TEXT, new Rectangle ( b.x, b.y, b.width - ips.width - gap, b.height ) );
                }
            }
            else
            {
                layoutData.put ( ICON, b );
                layoutData.put ( TEXT, b );
            }
        }
        else if ( hasIcon )
        {
            layoutData.put ( ICON, b );
        }
        else if ( hasText )
        {
            layoutData.put ( TEXT, b );
        }

        return layoutData;
    }

    @Override
    protected Dimension getContentPreferredSize ( final C c, final D d, final Dimension available )
    {
        final int halign = getHorizontalAlignment ( c, d );
        final int valign = getVerticalAlignment ( c, d );

        // Retrieving spacing preferred sizes
        final Dimension top = getPreferredSize ( c, d, TOP_SPACE, available );
        final Dimension left = getPreferredSize ( c, d, LEFT_SPACE, available );
        final Dimension right = getPreferredSize ( c, d, RIGHT_SPACE, available );
        final Dimension bottom = getPreferredSize ( c, d, BOTTOM_SPACE, available );

        // Calculating actual spacing sizes
        // We have to find maximum of two in case axis alignment for main content is CENTER
        final int lw = halign == CENTER ? Math.max ( left.width, right.width ) : left.width;
        final int rw = halign == CENTER ? Math.max ( left.width, right.width ) : right.width;
        final int th = valign == CENTER ? Math.max ( top.height, bottom.height ) : top.height;
        final int bh = valign == CENTER ? Math.max ( top.height, bottom.height ) : bottom.height;

        // Calculating icon and text preferred size
        final Dimension iconTextAvailable = new Dimension ( available.width - lw - rw, available.height - th - bh );
        final Dimension iconText = getIconTextPreferredSize ( c, d, iconTextAvailable );

        // Calculating resulting preferred sizes
        final int pw = MathUtils.max ( top.width, lw + iconText.width + rw, bottom.width );
        final int ph = th + MathUtils.max ( left.height, iconText.height, right.height ) + bh;
        return new Dimension ( pw, ph );
    }

    /**
     * Returns icon and text preferred size.
     *
     * @param c         painted component
     * @param d         painted decoration state
     * @param available available space
     * @return icon and text preferred size
     */
    protected Dimension getIconTextPreferredSize ( final C c, final D d, final Dimension available )
    {
        final Dimension size;
        final boolean hasIcon = !isEmpty ( c, d, ICON );
        final boolean hasText = !isEmpty ( c, d, TEXT );
        if ( hasIcon && hasText )
        {
            final int hpos = getHorizontalTextPosition ( c, d );
            final int vpos = getVerticalTextPosition ( c, d );
            final Dimension ips = getPreferredSize ( c, d, ICON, available );
            if ( hpos != CENTER || vpos != CENTER )
            {
                final int gap = getIconTextGap ( c, d );
                if ( hpos == LEFT || hpos == LEADING || hpos == RIGHT || hpos == TRAILING )
                {
                    final Dimension havailable = new Dimension ( available.width - gap - ips.width, available.height );
                    final Dimension cps = getPreferredSize ( c, d, TEXT, havailable );
                    size = new Dimension ( ips.width + gap + cps.width, Math.max ( ips.height, cps.height ) );
                }
                else
                {
                    final Dimension vavailable = new Dimension ( available.width, available.height - gap - ips.height );
                    final Dimension cps = getPreferredSize ( c, d, TEXT, vavailable );
                    size = new Dimension ( Math.max ( ips.width, cps.width ), ips.height + gap + cps.height );
                }
            }
            else
            {
                size = SwingUtils.max ( ips, getPreferredSize ( c, d, TEXT, available ) );
            }
        }
        else if ( hasIcon )
        {
            size = getPreferredSize ( c, d, ICON, available );
        }
        else if ( hasText )
        {
            size = getPreferredSize ( c, d, TEXT, available );
        }
        else
        {
            size = new Dimension ( 0, 0 );
        }
        return size;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy