com.alee.extended.layout.AccordionLayout Maven / Gradle / Ivy
/*
* 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.extended.layout;
import com.alee.extended.panel.WebAccordion;
import com.alee.extended.panel.WebCollapsiblePane;
import com.alee.laf.grouping.AbstractGroupingLayout;
import com.alee.painter.decoration.DecorationUtils;
import com.alee.utils.general.Pair;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Custom layout for {@link WebAccordion} component.
*
* @author Mikle Garin
*/
public class AccordionLayout extends AbstractGroupingLayout
{
@Override
public void layoutContainer ( final Container container )
{
final WebAccordion accordion = ( WebAccordion ) container;
final List panes = accordion.getPanes ();
final int gap = accordion.getGap ();
final Insets insets = container.getInsets ();
final Dimension size = container.getSize ();
final int w = size.width - insets.left - insets.right;
final int h = size.height - insets.top - insets.bottom;
final boolean hor = accordion.getOrientation () == SwingConstants.HORIZONTAL;
int x = insets.left;
int y = insets.top;
if ( accordion.isFillSpace () )
{
// Computing the part available to fill in with panes content
float totalStates = 0;
int totalFillLength = ( hor ? size.width - insets.left - insets.right : size.height - insets.top - insets.bottom ) + gap;
int visuallyExpanded = 0;
int lastFillIndex = -1;
final List base = new ArrayList ();
for ( final WebCollapsiblePane pane : panes )
{
final Dimension bps = pane.getBasePreferredSize ();
base.add ( hor ? bps.width : bps.height );
final float expandState = pane.getTransitionProgress ();
totalStates += expandState;
totalFillLength -= ( hor ? bps.width : bps.height ) + gap;
if ( expandState > 0f )
{
lastFillIndex = panes.indexOf ( pane );
visuallyExpanded++;
}
}
totalStates = visuallyExpanded == 1 ? 1f : totalStates;
totalFillLength = Math.max ( totalFillLength, 0 );
// Layouting panes
float end = 0f;
for ( int i = 0; i < panes.size (); i++ )
{
final float expandState = panes.get ( i ).getTransitionProgress ();
int length = base.get ( i );
if ( expandState > 0f )
{
end += totalFillLength * expandState / totalStates % 1;
length += Math.round ( ( float ) Math.floor ( totalFillLength * expandState / totalStates ) ) +
( i == lastFillIndex ? Math.round ( end ) : 0 );
}
panes.get ( i ).setBounds ( x, y, hor ? length : w, hor ? h : length );
if ( hor )
{
x += length + gap;
}
else
{
y += length + gap;
}
}
}
else
{
// Simply layouting panes by preferred size
for ( final WebCollapsiblePane pane : panes )
{
final Dimension cps = pane.getPreferredSize ();
pane.setBounds ( x, y, hor ? cps.width : w, hor ? h : cps.height );
if ( hor )
{
x += cps.width + gap;
}
else
{
y += cps.height + gap;
}
}
}
}
@Override
public Dimension preferredLayoutSize ( final Container container )
{
return getLayoutSize ( container, true );
}
@Override
public Dimension minimumLayoutSize ( final Container container )
{
return getLayoutSize ( container, false );
}
/**
* Returns either minimum or preferred container size.
*
* @param container container
* @param preferred whether preferred size should be returned or not
* @return either minimum or preferred container size
*/
protected Dimension getLayoutSize ( final Container container, final boolean preferred )
{
final WebAccordion accordion = ( WebAccordion ) container;
final List panes = accordion.getPanes ();
final int gap = accordion.getGap ();
final Dimension ps = new Dimension ();
final boolean hor = accordion.getOrientation () == SwingConstants.HORIZONTAL;
for ( final WebCollapsiblePane pane : panes )
{
final Dimension cps = preferred || !accordion.isFillSpace () ? pane.getPreferredSize () : pane.getBasePreferredSize ();
if ( hor )
{
ps.width += cps.width;
ps.height = Math.max ( ps.height, cps.height );
}
else
{
ps.width = Math.max ( ps.width, cps.width );
ps.height += cps.height;
}
}
if ( panes.size () > 0 )
{
if ( hor )
{
ps.width += gap * ( panes.size () - 1 );
}
else
{
ps.height += gap * ( panes.size () - 1 );
}
}
final Insets insets = container.getInsets ();
ps.width += insets.left + insets.right;
ps.height += insets.top + insets.bottom;
return ps;
}
@Override
protected String sides ()
{
return sides != null ? sides : ( sides = "0,0,0,0" );
}
@Override
public Pair getDescriptors ( final Container container, final Component component, final int index )
{
final Pair descriptors;
final WebAccordion accordion = ( WebAccordion ) container;
if ( accordion.getGap () == 0 )
{
final int last = container.getComponentCount () - 1;
final boolean hor = accordion.getOrientation () == SwingConstants.HORIZONTAL;
final boolean top = ( hor || !hor && index == 0 ) && isPaintTop ();
final boolean left = ( index == 0 || !hor ) && isPaintLeft ();
final boolean bottom = ( hor || !hor && index == last ) && isPaintBottom ();
final boolean right = ( index == last || !hor ) && isPaintLeft ();
final String sides = DecorationUtils.toString ( top, left, bottom, right );
final String lines = DecorationUtils.toString ( false, false, !hor && index != last, hor && index != last );
descriptors = new Pair ( sides, lines );
}
else
{
descriptors = new Pair ();
}
return descriptors;
}
}