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

com.alee.painter.decoration.WebDecoration 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.decoration;

import com.alee.managers.style.Bounds;
import com.alee.painter.decoration.background.IBackground;
import com.alee.painter.decoration.border.IBorder;
import com.alee.painter.decoration.content.IContent;
import com.alee.painter.decoration.layout.IContentLayout;
import com.alee.painter.decoration.shadow.IShadow;
import com.alee.painter.decoration.shadow.ShadowType;
import com.alee.painter.decoration.shape.IShape;
import com.alee.painter.decoration.shape.ShapeType;
import com.alee.painter.decoration.shape.WebShape;
import com.alee.utils.CollectionUtils;
import com.alee.utils.GraphicsUtils;
import com.alee.utils.MergeUtils;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Configurable decoration state used for most WebLaF components.
 * It provides basic elements required to paint component parts.
 *
 * @param  component type
 * @param  decoration type
 * @author Mikle Garin
 */

@XStreamAlias ( "decoration" )
public class WebDecoration> extends AbstractDecoration
{
    /**
     * Decoration shape.
     * It defines the shape of the decoration shade, border, background and might be used for other decoration elements.
     * Implicit list is only used to provide convenient XML descriptor for this field, only one shape can be provided at a time.
     *
     * @see com.alee.painter.decoration.shape.IShape
     * @see com.alee.painter.decoration.shape.AbstractShape
     */
    @XStreamImplicit
    protected List shapes = new ArrayList ( 1 );

    /**
     * Optional decoration shades.
     * Maximum two different shades could be provided at the same time - outer and inner.
     *
     * @see com.alee.painter.decoration.shadow.IShadow
     * @see com.alee.painter.decoration.shadow.AbstractShadow
     */
    @XStreamImplicit
    protected List shades = new ArrayList ( 1 );

    /**
     * Optional decoration border.
     * Implicit list is used to provide convenient XML descriptor for this field.
     * Right now only single border can be used per decoration instance, but that might change in future.
     *
     * @see com.alee.painter.decoration.border.IBorder
     * @see com.alee.painter.decoration.border.AbstractBorder
     */
    @XStreamImplicit
    protected List borders = new ArrayList ( 1 );

    /**
     * Optional decoration backgrounds.
     * Multiple backgrounds can be used per decoration instance.
     * Though it is not reasonable to use backgrounds which will fully overlap eachother.
     *
     * @see com.alee.painter.decoration.background.IBackground
     * @see com.alee.painter.decoration.background.AbstractBackground
     */
    @XStreamImplicit
    protected List background = new ArrayList ( 1 );

    /**
     * Optional decoration contents layout.
     * You can only provide single layout per decoration instance.
     * Implicit list is only used to provide convenient XML descriptor for this field.
     *
     * @see com.alee.painter.decoration.layout.IContentLayout
     */
    @XStreamImplicit
    protected List layout = new ArrayList ( 1 );

    /**
     * Optional decoration contents.
     * It can be anything contained within the decoration or placed on top of the decoration.
     * Contents are placed based on either layout, if one was provided, or their own bounds setting.
     *
     * @see com.alee.painter.decoration.content.IContent
     * @see com.alee.painter.decoration.content.AbstractContent
     */
    @XStreamImplicit
    protected List contents = new ArrayList ( 1 );

    /**
     * Returns decoration shape.
     *
     * @return decoration shape
     */
    public IShape getShape ()
    {
        return !CollectionUtils.isEmpty ( shapes ) ? shapes.get ( 0 ) : null;
    }

    /**
     * Returns shade of the specified type.
     *
     * @param type shade type
     * @return shade of the specified type
     */
    public IShadow getShade ( final ShadowType type )
    {
        if ( !CollectionUtils.isEmpty ( shades ) )
        {
            for ( final IShadow shade : shades )
            {
                if ( shade.getType () == type )
                {
                    return shade;
                }
            }
        }
        return null;
    }

    /**
     * Returns width of the shade with the specified type.
     *
     * @param type shade type
     * @return width of the shade with the specified type
     */
    public int getShadeWidth ( final ShadowType type )
    {
        final IShadow shade = getShade ( type );
        return shade != null ? shade.getWidth () : 0;
    }

    /**
     * Returns decoration border.
     *
     * @return decoration border
     */
    public IBorder getBorder ()
    {
        return !CollectionUtils.isEmpty ( borders ) ? borders.get ( 0 ) : null;
    }

    /**
     * Returns border width.
     *
     * @return border width
     */
    public float getBorderWidth ()
    {
        final IBorder border = getBorder ();
        return border != null ? border.getWidth () : 0f;
    }

    /**
     * Returns decoration backgrounds.
     *
     * @return decoration backgrounds
     */
    public List getBackgrounds ()
    {
        return !CollectionUtils.isEmpty ( background ) ? background : null;
    }

    /**
     * Returns decoration contents layout.
     *
     * @return decoration contents layout
     */
    public IContentLayout getLayout ()
    {
        return !CollectionUtils.isEmpty ( layout ) ? layout.get ( 0 ) : null;
    }

    /**
     * Returns decoration contents.
     *
     * @return decoration contents
     */
    public List getContents ()
    {
        return !CollectionUtils.isEmpty ( contents ) ? contents : null;
    }

    @Override
    public Insets getBorderInsets ( final E c )
    {
        Insets insets = null;
        if ( isVisible () )
        {
            final IShape shape = getShape ();
            if ( shape != null )
            {
                insets = shape.getBorderInsets ( c, WebDecoration.this );
            }
        }
        return insets;
    }

    @Override
    public Shape provideShape ( final E component, final Rectangle bounds )
    {
        // todo Add ShapeType into PainterShapeProvider interface
        final IShape shape = getShape ();
        return isVisible () && shape != null ? shape.getShape ( ShapeType.background, bounds, component, this ) : bounds;
    }

    @Override
    public void paint ( final Graphics2D g2d, final Rectangle bounds, final E c )
    {
        // Painting only if decoration should be visible
        if ( isVisible () )
        {
            // Checking shape existance
            final IShape shape = getShape ();
            if ( shape != null )
            {
                // Setup settings
                final Object oaa = GraphicsUtils.setupAntialias ( g2d );
                final Composite oc = GraphicsUtils.setupAlphaComposite ( g2d, getOpacity (), getOpacity () < 1f );
                final Rectangle cl = g2d.getClip () instanceof Rectangle ? ( Rectangle ) g2d.getClip () : c.getVisibleRect ();
                final Shape ocl = GraphicsUtils.setupClip ( g2d, Bounds.margin.of ( c, this, bounds ).intersection ( cl ) );

                // Outer shade
                final IShadow outer = getShade ( ShadowType.outer );
                if ( outer != null && shape.isVisible ( ShapeType.outerShade, c, WebDecoration.this ) )
                {
                    final Shape s = shape.getShape ( ShapeType.outerShade, bounds, c, WebDecoration.this );
                    outer.paint ( g2d, bounds, c, WebDecoration.this, s );
                }

                // Painting all available backgrounds
                final List backgrounds = getBackgrounds ();
                if ( !CollectionUtils.isEmpty ( backgrounds ) && shape.isVisible ( ShapeType.background, c, WebDecoration.this ) )
                {
                    final Shape s = shape.getShape ( ShapeType.background, bounds, c, WebDecoration.this );
                    for ( final IBackground background : backgrounds )
                    {
                        background.paint ( g2d, bounds, c, WebDecoration.this, s );
                    }
                }

                // Painting inner shade
                final IShadow inner = getShade ( ShadowType.inner );
                if ( inner != null && shape.isVisible ( ShapeType.innerShade, c, WebDecoration.this ) )
                {
                    final Shape s = shape.getShape ( ShapeType.innerShade, bounds, c, WebDecoration.this );
                    inner.paint ( g2d, bounds, c, WebDecoration.this, s );
                }

                // Painting border
                final IBorder border = getBorder ();
                if ( border != null && shape.isVisible ( ShapeType.border, c, WebDecoration.this ) )
                {
                    final Shape s = shape.getShape ( ShapeType.border, bounds, c, WebDecoration.this );
                    border.paint ( g2d, bounds, c, WebDecoration.this, s );

                    // Painting side lines
                    // todo This is a temporary solution
                    if ( shape instanceof WebShape )
                    {
                        final WebShape webShape = ( WebShape ) shape;
                        final boolean ltr = c.getComponentOrientation ().isLeftToRight ();
                        final boolean paintTop = webShape.isPaintTop ( c, this );
                        final boolean paintBottom = webShape.isPaintBottom ( c, this );
                        final boolean actualPaintLeft = ltr ? webShape.isPaintLeft ( c, this ) : webShape.isPaintRight ( c, this );
                        final boolean actualPaintRight = ltr ? webShape.isPaintRight ( c, this ) : webShape.isPaintLeft ( c, this );
                        final boolean paintTopLine = webShape.isPaintTopLine ( c, this );
                        final boolean paintBottomLine = webShape.isPaintBottomLine ( c, this );
                        final boolean actualPaintLeftLine =
                                ltr ? webShape.isPaintLeftLine ( c, this ) : webShape.isPaintRightLine ( c, this );
                        final boolean actualPaintRightLine =
                                ltr ? webShape.isPaintRightLine ( c, this ) : webShape.isPaintLeftLine ( c, this );
                        final int shadeWidth = getShadeWidth ( ShadowType.outer );
                        final Stroke os = GraphicsUtils.setupStroke ( g2d, border.getStroke (), border.getStroke () != null );
                        final Paint op = GraphicsUtils.setupPaint ( g2d, border.getColor (), border.getColor () != null );
                        if ( !paintTop && paintTopLine )
                        {
                            final int x1 = bounds.x + ( actualPaintLeft ? shadeWidth : 0 );
                            final int x2 = bounds.x + bounds.width - ( actualPaintRight ? shadeWidth : 0 ) - 1;
                            g2d.drawLine ( x1, bounds.y, x2, bounds.y );
                        }
                        if ( !paintBottom && paintBottomLine )
                        {
                            final int y = bounds.y + bounds.height - 1;
                            final int x1 = bounds.x + ( actualPaintLeft ? shadeWidth : 0 );
                            final int x2 = bounds.x + bounds.width - ( actualPaintRight ? shadeWidth : 0 ) - 1;
                            g2d.drawLine ( x1, y, x2, y );
                        }
                        if ( !actualPaintLeft && actualPaintLeftLine )
                        {
                            final int y1 = bounds.y + ( paintTop ? shadeWidth : 0 );
                            final int y2 = bounds.y + bounds.height - ( paintBottom ? shadeWidth : 0 ) - 1;
                            g2d.drawLine ( bounds.x, y1, bounds.x, y2 );
                        }
                        if ( !actualPaintRight && actualPaintRightLine )
                        {
                            final int x = bounds.x + bounds.width - 1;
                            final int y1 = bounds.y + ( paintTop ? shadeWidth : 0 );
                            final int y2 = bounds.y + bounds.height - ( paintBottom ? shadeWidth : 0 ) - 1;
                            g2d.drawLine ( x, y1, x, y2 );
                        }
                        GraphicsUtils.restorePaint ( g2d, op, border.getColor () != null );
                        GraphicsUtils.restoreStroke ( g2d, os, border.getStroke () != null );
                    }
                }

                // Painting contents
                final List contents = getContents ();
                if ( contents != null )
                {
                    // Checking contents layout existance
                    final IContentLayout layout = getLayout ();
                    final List cb = layout != null ? layout.layout ( bounds, c, this, contents ) : null;

                    // Painting contents in appropriate bounds
                    for ( int i = 0; i < contents.size (); i++ )
                    {
                        // Using either content layout or default centered placement
                        final IContent content = contents.get ( i );
                        final Rectangle b = cb != null ? cb.get ( i ) : content.getBoundsType ().of ( c, this, bounds );
                        content.paint ( g2d, b, c, WebDecoration.this );
                    }
                }

                // Restoring settings
                GraphicsUtils.restoreClip ( g2d, ocl );
                GraphicsUtils.restoreAntialias ( g2d, oaa );
                GraphicsUtils.restoreComposite ( g2d, oc );
            }
        }
    }

    @Override
    public I merge ( final I decoration )
    {
        super.merge ( decoration );
        shapes = MergeUtils.merge ( shapes, decoration.shapes );
        shades = MergeUtils.merge ( shades, decoration.shades );
        borders = MergeUtils.merge ( borders, decoration.borders );
        background = MergeUtils.merge ( background, decoration.background );
        layout = MergeUtils.merge ( layout, decoration.layout );
        contents = MergeUtils.merge ( contents, decoration.contents );
        return ( I ) this;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy