blob: 39ce1ac79c04bfe78991497c5704a844dddbf16d [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* 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 com.intellij.util.ui;
import org.intellij.lang.annotations.JdkConstants;
import javax.swing.*;
import java.awt.*;
/**
* Flow layout calculates necessary size assuming that all components are laid out within a single row.
* That may cause troubles during initial space calculation, i.e. panel with flow layout is represented as a
* single wide row inside a scroll pane. This panel fixes that by calculating necessary size on its own.
* It fixes the width to use as a minimum between a width offered by default flow layout and customizable value
* and calculates the height. If the user has an ability to manually change panel size (e.g. indirectly via changing
* size of the dialog that serves as a container for the panel), that width is used as a maximum width.
*
* @author Denis Zhdanov
* @since Jul 28, 2008
*/
public class MultiRowFlowPanel extends JPanel {
private final int maximumWidth = GraphicsEnvironment.isHeadless()
? 400
: GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().getBounds().width / 2;
private int myForcedWidth;
public MultiRowFlowPanel(@JdkConstants.FlowLayoutAlignment int align, int hGap, int vGap) {
super(new FlowLayout(align, hGap, vGap));
}
/**
* Calculates a preferred size assuming that the maximum row width is a value returned from
* {@link #getMaxRowWidth()}.
*/
@Override
public Dimension getPreferredSize() {
return calculateSize(getMaxRowWidth());
}
/**
* Calculates a preferred size assuming that the maximum row width is a value returned from
* {@link #getMaxRowWidth()}.
*/
@Override
public Dimension getMinimumSize() {
return calculateSize(getMaxRowWidth());
}
/**
* @return current representation width if the component is already showed; minimum of default preferred
* width (when all components are layed in a single row) and half screen width
*/
private int getMaxRowWidth() {
if (myForcedWidth > 0) {
return myForcedWidth;
}
int result = getSize().width;
if (result == 0) {
result = Math.min(super.getPreferredSize().width, maximumWidth);
}
return result;
}
public void setForcedWidth(int forcedWidth) {
myForcedWidth = forcedWidth;
}
/**
* Iterates all child components and calculates the space enough to keep all of them assuming that the width is
* fixed.
*/
private Dimension calculateSize(int maxRowWidth) {
FlowLayout layout = (FlowLayout)getLayout();
int height = 0;
int currentRowWidth = 0;
int currentRowHeight = 0;
for (int i = 0, count = getComponentCount(); i < count; ++i) {
Component comp = getComponent(i);
Dimension bounds = comp.getPreferredSize();
if (!comp.isVisible()) {
continue;
}
currentRowHeight = Math.max(currentRowHeight, bounds.height);
if (currentRowWidth + layout.getHgap() + bounds.width <= maxRowWidth) {
if (bounds.width != 0) {
currentRowWidth += bounds.width + layout.getHgap();
}
continue;
}
height += currentRowHeight + layout.getVgap();
currentRowWidth = bounds.width;
currentRowHeight = bounds.height;
}
return new Dimension(maxRowWidth, height + currentRowHeight + 2 * layout.getVgap());
}
}