2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 2010-2015 Martin
19 package com
.googlecode
.lanterna
.gui2
;
21 import com
.googlecode
.lanterna
.TerminalPosition
;
22 import com
.googlecode
.lanterna
.TerminalSize
;
27 * BorderLayout imitates the BorderLayout class from AWT, allowing you to add a center component with optional
28 * components around it in top, bottom, left and right locations. The edge components will be sized at their preferred
29 * size and the center component will take up whatever remains.
32 public class BorderLayout
implements LayoutManager
{
35 * This type is what you use as the layout data for components added to a panel using {@code BorderLayout} for its
36 * layout manager. This values specified where inside the panel the component should be added.
38 public enum Location
implements LayoutData
{
40 * The component with this value as its layout data will occupy the center space, whatever is remaining after
41 * the other components (if any) have allocated their space.
45 * The component with this value as its layout data will occupy the left side of the container, attempting to
46 * allocate the preferred width of the component and at least the preferred height, but could be more depending
47 * on the other components added.
51 * The component with this value as its layout data will occupy the right side of the container, attempting to
52 * allocate the preferred width of the component and at least the preferred height, but could be more depending
53 * on the other components added.
57 * The component with this value as its layout data will occupy the top side of the container, attempting to
58 * allocate the preferred height of the component and at least the preferred width, but could be more depending
59 * on the other components added.
63 * The component with this value as its layout data will occupy the bottom side of the container, attempting to
64 * allocate the preferred height of the component and at least the preferred width, but could be more depending
65 * on the other components added.
71 //When components don't have a location, we'll assign an available location based on this order
72 private static final List
<Location
> AUTO_ASSIGN_ORDER
= Collections
.unmodifiableList(Arrays
.asList(
80 public TerminalSize
getPreferredSize(List
<Component
> components
) {
81 EnumMap
<Location
, Component
> layout
= makeLookupMap(components
);
83 (layout
.containsKey(Location
.TOP
) ? layout
.get(Location
.TOP
).getPreferredSize().getRows() : 0)
86 layout
.containsKey(Location
.LEFT
) ? layout
.get(Location
.LEFT
).getPreferredSize().getRows() : 0,
88 layout
.containsKey(Location
.CENTER
) ? layout
.get(Location
.CENTER
).getPreferredSize().getRows() : 0,
89 layout
.containsKey(Location
.RIGHT
) ? layout
.get(Location
.RIGHT
).getPreferredSize().getRows() : 0))
91 (layout
.containsKey(Location
.BOTTOM
) ? layout
.get(Location
.BOTTOM
).getPreferredSize().getRows() : 0);
95 (layout
.containsKey(Location
.LEFT
) ? layout
.get(Location
.LEFT
).getPreferredSize().getColumns() : 0) +
96 (layout
.containsKey(Location
.CENTER
) ? layout
.get(Location
.CENTER
).getPreferredSize().getColumns() : 0) +
97 (layout
.containsKey(Location
.RIGHT
) ? layout
.get(Location
.RIGHT
).getPreferredSize().getColumns() : 0),
99 layout
.containsKey(Location
.TOP
) ? layout
.get(Location
.TOP
).getPreferredSize().getColumns() : 0,
100 layout
.containsKey(Location
.BOTTOM
) ? layout
.get(Location
.BOTTOM
).getPreferredSize().getColumns() : 0));
101 return new TerminalSize(preferredWidth
, preferredHeight
);
105 public void doLayout(TerminalSize area
, List
<Component
> components
) {
106 EnumMap
<Location
, Component
> layout
= makeLookupMap(components
);
107 int availableHorizontalSpace
= area
.getColumns();
108 int availableVerticalSpace
= area
.getRows();
110 //We'll need this later on
111 int topComponentHeight
= 0;
112 int leftComponentWidth
= 0;
114 //First allocate the top
115 if(layout
.containsKey(Location
.TOP
)) {
116 Component topComponent
= layout
.get(Location
.TOP
);
117 topComponentHeight
= Math
.min(topComponent
.getPreferredSize().getRows(), availableVerticalSpace
);
118 topComponent
.setPosition(TerminalPosition
.TOP_LEFT_CORNER
);
119 topComponent
.setSize(new TerminalSize(availableHorizontalSpace
, topComponentHeight
));
120 availableVerticalSpace
-= topComponentHeight
;
123 //Next allocate the bottom
124 if(layout
.containsKey(Location
.BOTTOM
)) {
125 Component bottomComponent
= layout
.get(Location
.BOTTOM
);
126 int bottomComponentHeight
= Math
.min(bottomComponent
.getPreferredSize().getRows(), availableVerticalSpace
);
127 bottomComponent
.setPosition(new TerminalPosition(0, area
.getRows() - bottomComponentHeight
));
128 bottomComponent
.setSize(new TerminalSize(availableHorizontalSpace
, bottomComponentHeight
));
129 availableVerticalSpace
-= bottomComponentHeight
;
132 //Now divide the remaining space between LEFT, CENTER and RIGHT
133 if(layout
.containsKey(Location
.LEFT
)) {
134 Component leftComponent
= layout
.get(Location
.LEFT
);
135 leftComponentWidth
= Math
.min(leftComponent
.getPreferredSize().getColumns(), availableHorizontalSpace
);
136 leftComponent
.setPosition(new TerminalPosition(0, topComponentHeight
));
137 leftComponent
.setSize(new TerminalSize(leftComponentWidth
, availableVerticalSpace
));
138 availableHorizontalSpace
-= leftComponentWidth
;
140 if(layout
.containsKey(Location
.RIGHT
)) {
141 Component rightComponent
= layout
.get(Location
.RIGHT
);
142 int rightComponentWidth
= Math
.min(rightComponent
.getPreferredSize().getColumns(), availableHorizontalSpace
);
143 rightComponent
.setPosition(new TerminalPosition(area
.getColumns() - rightComponentWidth
, topComponentHeight
));
144 rightComponent
.setSize(new TerminalSize(rightComponentWidth
, availableVerticalSpace
));
145 availableHorizontalSpace
-= rightComponentWidth
;
147 if(layout
.containsKey(Location
.CENTER
)) {
148 Component centerComponent
= layout
.get(Location
.CENTER
);
149 centerComponent
.setPosition(new TerminalPosition(leftComponentWidth
, topComponentHeight
));
150 centerComponent
.setSize(new TerminalSize(availableHorizontalSpace
, availableVerticalSpace
));
153 //Set the remaining components to 0x0
154 for(Component component
: components
) {
155 if(!layout
.values().contains(component
)) {
156 component
.setPosition(TerminalPosition
.TOP_LEFT_CORNER
);
157 component
.setSize(TerminalSize
.ZERO
);
162 private EnumMap
<Location
, Component
> makeLookupMap(List
<Component
> components
) {
163 EnumMap
<Location
, Component
> map
= new EnumMap
<BorderLayout
.Location
, Component
>(Location
.class);
164 List
<Component
> unassignedComponents
= new ArrayList
<Component
>();
165 for(Component component
: components
) {
166 if(component
.getLayoutData() instanceof Location
) {
167 map
.put((Location
)component
.getLayoutData(), component
);
170 unassignedComponents
.add(component
);
173 //Try to assign components to available locations
174 for(Component component
: unassignedComponents
) {
175 for(Location location
: AUTO_ASSIGN_ORDER
) {
176 if(!map
.containsKey(location
)) {
177 map
.put(location
, component
);
186 public boolean hasChanged() {