org.jitsi.util.swing.FitLayout Maven / Gradle / Ivy
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.util.swing;
import java.awt.*;
import javax.swing.*;
/**
* Represents a LayoutManager which centers the first
* Component within its Container and, if the preferred size
* of the Component is larger than the size of the Container,
* scales the former within the bounds of the latter while preserving the aspect
* ratio. FitLayout is appropriate for Containers which
* display a single image or video Component in its entirety for which
* preserving the aspect ratio is important.
*
* @author Lyubomir Marinov
*/
public class FitLayout
implements LayoutManager
{
/**
* The default height and width to be used by FitLayout and its
* extenders in order to avoid falling back to zero height and/or width.
* Introduced to mitigate issues arising from the fact that a
* Component zero height and/or width.
*/
protected static final int DEFAULT_HEIGHT_OR_WIDTH = 16;
/**
* {@inheritDoc}
*
* Does nothing because this LayoutManager lays out only the first
* Component of the parent Container and thus doesn't need
* any String associations.
*/
public void addLayoutComponent(String name, Component comp) {}
/**
* Gets the first Component of a specific Container if
* there is such a Component.
*
* @param parent the Container to retrieve the first
* Component of
* @return the first Component of a specific Container if
* there is such a Component; otherwise, null
*/
protected Component getComponent(Container parent)
{
Component[] components = parent.getComponents();
return (components.length > 0) ? components[0] : null;
}
protected void layoutComponent(
Component component,
Rectangle bounds,
float alignmentX, float alignmentY)
{
Dimension size;
/*
* XXX The following (mostly) represents a quick and dirty hack for the
* purposes of video conferencing which adds transparent JPanels to
* VideoContainer and does not want them fitted because they contain
* VideoContainers themselves and the videos get fitted in them.
*/
if (((component instanceof JPanel)
&& !component.isOpaque()
&& (((Container) component).getComponentCount() > 1))
|| (component instanceof VideoContainer)
/*
* If the specified component does not have a preferredSize, we
* cannot know its aspect ratio and we are left with no choice
* but to stretch it within the complete bounds.
*/
|| ((size = component.getPreferredSize()) == null))
{
size = bounds.getSize();
}
else
{
boolean scale = false;
double widthRatio;
double heightRatio;
if ((size.width != bounds.width) && (size.width > 0))
{
scale = true;
widthRatio = bounds.width / (double) size.width;
}
else
widthRatio = 1;
if ((size.height != bounds.height) && (size.height > 0))
{
scale = true;
heightRatio = bounds.height / (double) size.height;
}
else
heightRatio = 1;
if (scale)
{
double ratio = Math.min(widthRatio, heightRatio);
size.width = (int) (size.width * ratio);
size.height = (int) (size.height * ratio);
}
}
// Respect the maximumSize of the component.
if (component.isMaximumSizeSet())
{
Dimension maxSize = component.getMaximumSize();
if (size.width > maxSize.width)
size.width = maxSize.width;
if (size.height > maxSize.height)
size.height = maxSize.height;
}
/*
* Why would one fit a Component into a rectangle with zero width and
* height?
*/
if (size.height < 1)
size.height = 1;
if (size.width < 1)
size.width = 1;
component.setBounds(
bounds.x + Math.round((bounds.width - size.width) * alignmentX),
bounds.y
+ Math.round((bounds.height - size.height) * alignmentY),
size.width,
size.height);
}
/*
* Scales the first Component if its preferred size is larger than the size
* of its parent Container in order to display the Component in its entirety
* and then centers it within the display area of the parent.
*/
public void layoutContainer(Container parent)
{
layoutContainer(parent, Component.CENTER_ALIGNMENT);
}
protected void layoutContainer(Container parent, float componentAlignmentX)
{
Component component = getComponent(parent);
if (component != null)
{
layoutComponent(
component,
new Rectangle(parent.getSize()),
componentAlignmentX, Component.CENTER_ALIGNMENT);
}
}
/*
* Since this LayoutManager lays out only the first Component of the
* specified parent Container, the minimum size of the Container is the
* minimum size of the mentioned Component.
*/
public Dimension minimumLayoutSize(Container parent)
{
Component component = getComponent(parent);
return
(component != null)
? component.getMinimumSize()
: new Dimension(
DEFAULT_HEIGHT_OR_WIDTH,
DEFAULT_HEIGHT_OR_WIDTH);
}
/**
* {@inheritDoc}
*
* Since this LayoutManager lays out only the first
* Component of the specified parent Container, the
* preferred size of the Container is the preferred size of the
* mentioned Component.
*/
public Dimension preferredLayoutSize(Container parent)
{
Component component = getComponent(parent);
return
(component != null)
? component.getPreferredSize()
: new Dimension(
DEFAULT_HEIGHT_OR_WIDTH,
DEFAULT_HEIGHT_OR_WIDTH);
}
/**
* {@inheritDoc}
*
* Does nothing because this LayoutManager lays out only the first
* Component of the parent Container and thus doesn't need
* any String associations.
*/
public void removeLayoutComponent(Component comp) {}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy