diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java b/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java index 63f982b806f3..9652562b6d2a 100644 --- a/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java +++ b/platform/platform-api/src/com/intellij/ui/components/panels/HorizontalLayout.java @@ -20,13 +20,20 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; -import java.awt.LayoutManager; +import java.awt.LayoutManager2; import java.util.ArrayList; /** + * This class is intended to lay out added components horizontally. + * It allows to add them into the LEFT, CENTER, or RIGHT group, which are aligned separately. + * Every group can contain any amount of components. The specified gap is added between components, + * and the double gap is added between groups of components. + *

NB!: this class must be modified together with the VerticalLayout class accordingly

+ * * @author Sergey.Malenkov + * @see VerticalLayout */ -public final class HorizontalLayout implements LayoutManager { +public final class HorizontalLayout implements LayoutManager2 { public static final String LEFT = "LEFT"; public static final String RIGHT = "RIGHT"; public static final String CENTER = "CENTER"; @@ -73,6 +80,35 @@ public final class HorizontalLayout implements LayoutManager { } } + @Override + public void addLayoutComponent(Component component, Object constraints) { + if ((constraints == null) || (constraints instanceof String)) { + addLayoutComponent((String)constraints, component); + } + else { + throw new IllegalArgumentException("unsupported constraints: " + constraints); + } + } + + @Override + public Dimension maximumLayoutSize(Container target) { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Override + public float getLayoutAlignmentX(Container target) { + return .5f; + } + + @Override + public float getLayoutAlignmentY(Container target) { + return .5f; + } + + @Override + public void invalidateLayout(Container target) { + } + @Override public void addLayoutComponent(String name, Component component) { synchronized (component.getTreeLock()) { @@ -154,19 +190,21 @@ public final class HorizontalLayout implements LayoutManager { private int layout(ArrayList list, int x, int height, Insets insets) { for (Component component : list) { - Dimension size = component.getPreferredSize(); - int y = 0; - if (myAlignment == -1) { - size.height = height; - } - else if (myAlignment != SwingConstants.TOP) { - y = height - size.height; - if (myAlignment == SwingConstants.CENTER) { - y /= 2; + if (component.isVisible()) { + Dimension size = component.getPreferredSize(); + int y = 0; + if (myAlignment == -1) { + size.height = height; } + else if (myAlignment != SwingConstants.TOP) { + y = height - size.height; + if (myAlignment == SwingConstants.CENTER) { + y /= 2; + } + } + component.setBounds(x + insets.left, y + insets.top, size.width, size.height); + x += size.width + myGap; } - component.setBounds(x + insets.left, y + insets.top, size.width, size.height); - x += size.width + myGap; } return x; } @@ -188,7 +226,9 @@ public final class HorizontalLayout implements LayoutManager { private Dimension getPreferredSize(ArrayList list) { Dimension result = null; for (Component component : list) { - result = join(result, myGap, component.getPreferredSize()); + if (component.isVisible()) { + result = join(result, myGap, component.getPreferredSize()); + } } return result; } diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java b/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java new file mode 100644 index 000000000000..7b9fdd0242ba --- /dev/null +++ b/platform/platform-api/src/com/intellij/ui/components/panels/VerticalLayout.java @@ -0,0 +1,256 @@ +/* + * Copyright 2000-2014 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.ui.components.panels; + +import javax.swing.SwingConstants; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager2; +import java.util.ArrayList; + +/** + * This class is intended to lay out added components vertically. + * It allows to add them into the TOP, CENTER, or BOTTOM group, which are aligned separately. + * Every group can contain any amount of components. The specified gap is added between components, + * and the double gap is added between groups of components. + *

NB!: this class must be modified together with the HorizontalLayout class accordingly

+ * + * @author Sergey.Malenkov + * @see HorizontalLayout + */ +public final class VerticalLayout implements LayoutManager2 { + public static final String TOP = "TOP"; + public static final String BOTTOM = "BOTTOM"; + public static final String CENTER = "CENTER"; + + private final ArrayList myTop = new ArrayList(); + private final ArrayList myBottom = new ArrayList(); + private final ArrayList myCenter = new ArrayList(); + private final int myAlignment; + private final int myGap; + + /** + * Creates a layout with the specified gap. + * All components will have preferred widths, + * but their widths will be set according to the container. + * + * @param gap vertical gap between components + */ + public VerticalLayout(int gap) { + myGap = gap; + myAlignment = -1; + } + + /** + * Creates a layout with the specified gap and vertical alignment. + * All components will have preferred sizes. + * + * @param gap vertical gap between components + * @param alignment horizontal alignment for components + * + * @see SwingConstants#LEFT + * @see SwingConstants#RIGHT + * @see SwingConstants#CENTER + */ + public VerticalLayout(int gap, int alignment) { + myGap = gap; + switch (alignment) { + case SwingConstants.LEFT: + case SwingConstants.RIGHT: + case SwingConstants.CENTER: + myAlignment = alignment; + break; + default: + throw new IllegalArgumentException("unsupported alignment: " + alignment); + } + } + + @Override + public void addLayoutComponent(Component component, Object constraints) { + if ((constraints == null) || (constraints instanceof String)) { + addLayoutComponent((String)constraints, component); + } + else { + throw new IllegalArgumentException("unsupported constraints: " + constraints); + } + } + + @Override + public Dimension maximumLayoutSize(Container target) { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + @Override + public float getLayoutAlignmentX(Container target) { + return .5f; + } + + @Override + public float getLayoutAlignmentY(Container target) { + return .5f; + } + + @Override + public void invalidateLayout(Container target) { + } + + @Override + public void addLayoutComponent(String name, Component component) { + synchronized (component.getTreeLock()) { + if (name == null || CENTER.equalsIgnoreCase(name)) { + myCenter.add(component); + } + else if (TOP.equalsIgnoreCase(name)) { + myTop.add(component); + } + else if (BOTTOM.equalsIgnoreCase(name)) { + myBottom.add(component); + } + else { + throw new IllegalArgumentException("unsupported name: " + name); + } + } + } + + @Override + public void removeLayoutComponent(Component component) { + myTop.remove(component); + myBottom.remove(component); + myCenter.remove(component); + } + + @Override + public Dimension preferredLayoutSize(Container container) { + return getPreferredSize(container, true); + } + + @Override + public Dimension minimumLayoutSize(Container container) { + return getPreferredSize(container, false); + } + + @Override + public void layoutContainer(Container container) { + synchronized (container.getTreeLock()) { + Dimension top = getPreferredSize(myTop); + Dimension bottom = getPreferredSize(myBottom); + Dimension center = getPreferredSize(myCenter); + + Insets insets = container.getInsets(); + int width = container.getWidth() - insets.left - insets.right; + int height = container.getHeight() - insets.top - insets.bottom; + + int topY = 0; + if (top != null) { + topY = myGap + layout(myTop, 0, width, insets); + } + int bottomY = height; + if (bottom != null) { + bottomY -= bottom.height; + } + if (bottomY < topY) { + bottomY = topY; + } + if (center != null) { + int centerY = (height - center.height) / 2; + if (centerY > topY) { + int centerBottomY = centerY + center.height + myGap + myGap; + if (centerBottomY > bottomY) { + centerY = bottomY - center.height - myGap - myGap; + } + } + if (centerY < topY) { + centerY = topY; + } + centerY = myGap + layout(myCenter, centerY, width, insets); + if (bottomY < centerY) { + bottomY = centerY; + } + } + if (bottom != null) { + layout(myBottom, bottomY, width, insets); + } + } + } + + private int layout(ArrayList list, int y, int width, Insets insets) { + for (Component component : list) { + if (component.isVisible()) { + Dimension size = component.getPreferredSize(); + int x = 0; + if (myAlignment == -1) { + size.width = width; + } + else if (myAlignment != SwingConstants.LEFT) { + x = width - size.width; + if (myAlignment == SwingConstants.CENTER) { + x /= 2; + } + } + component.setBounds(x + insets.left, y + insets.top, size.width, size.height); + y += size.height + myGap; + } + } + return y; + } + + private static Dimension join(Dimension result, int gap, Dimension size) { + if (size == null) { + return result; + } + if (result == null) { + return new Dimension(size); + } + result.height += gap + size.height; + if (result.width < size.width) { + result.width = size.width; + } + return result; + } + + private Dimension getPreferredSize(ArrayList list) { + Dimension result = null; + for (Component component : list) { + if (component.isVisible()) { + result = join(result, myGap, component.getPreferredSize()); + } + } + return result; + } + + private Dimension getPreferredSize(Container container, boolean aligned) { + synchronized (container.getTreeLock()) { + Dimension top = getPreferredSize(myTop); + Dimension bottom = getPreferredSize(myBottom); + Dimension center = getPreferredSize(myCenter); + Dimension result = join(join(join(null, myGap + myGap, top), myGap + myGap, center), myGap + myGap, bottom); + if (result == null) { + result = new Dimension(); + } + else if (aligned) { + int topHeight = top == null ? 0 : top.height; + int bottomHeight = bottom == null ? 0 : bottom.height; + result.width += Math.abs(topHeight - bottomHeight); + } + Insets insets = container.getInsets(); + result.width += insets.left + insets.right; + result.height += insets.top + insets.bottom; + return result; + } + } +}