pax_global_header 0000666 0000000 0000000 00000000064 13241015632 0014507 g ustar 00root root 0000000 0000000 52 comment=391752a7c1878873f2d487956dfaa417754e56d7
miglayout-5.1/ 0000775 0000000 0000000 00000000000 13241015632 0013366 5 ustar 00root root 0000000 0000000 miglayout-5.1/.gitignore 0000775 0000000 0000000 00000001166 13241015632 0015365 0 ustar 00root root 0000000 0000000
/core/.settings
/core/target
/core/.project
/core/.classpath
/demo/.project
/demo/.settings
/demo/target
/demo/.classpath
/examples/.project
/examples/.settings
/examples/target
/examples/.classpath
/ideutil/.project
/ideutil/.settings
/ideutil/target
/ideutil/.classpath
/swing/.project
/swing/.settings
/swing/target
/swing/.classpath
/swt/.project
/swt/.settings
/swt/target
/swt/.classpath
/target
/release.properties
/javafx/.project
/javafx/.settings
/javafx/target
/javafx/.classpath
#
# ignore target folders in the build tree
#
**/target
#
# ignore eclipse local settings files
#
**/.project
**/.classpath
**/.settings
miglayout-5.1/README.md 0000664 0000000 0000000 00000001602 13241015632 0014644 0 ustar 00root root 0000000 0000000 # miglayout
Official MiG Layout for Swing, SWT and JavaFX
For Java developers writing GUI layouts by hand that wants simplicity, power and automatic per platform fidelity, that are dissatisfied with the current layout managers in Swing, JavaFX and SWT, MigLayout solves your layout problems. User interfaces created with MigLayout is easy to maintain, you will understand how the layout will look like just by looking at the source code.
MigLayout is a superbly versatile JavaFX/SWT/Swing layout manager that makes layout problems trivial. It is using String or API type-checked constraints to format the layout. MigLayout can produce flowing, grid based, absolute (with links), grouped and docking layouts. You will never have to switch to another layout manager ever again! MigLayout is created to be to manually coded layouts what Matisse/GroupLayout is to IDE supported visual layouts.
miglayout-5.1/core/ 0000775 0000000 0000000 00000000000 13241015632 0014316 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/pom.xml 0000775 0000000 0000000 00000001202 13241015632 0015631 0 ustar 00root root 0000000 0000000 4.0.0com.miglayoutmiglayout-parent5.1-SNAPSHOT../pom.xmlmiglayout-corejarMiGLayout CoreMiGLayout - core layout logic
miglayout-5.1/core/src/ 0000775 0000000 0000000 00000000000 13241015632 0015105 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/ 0000775 0000000 0000000 00000000000 13241015632 0016031 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/java/ 0000775 0000000 0000000 00000000000 13241015632 0016752 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/java/net/ 0000775 0000000 0000000 00000000000 13241015632 0017540 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/java/net/miginfocom/ 0000775 0000000 0000000 00000000000 13241015632 0021667 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/java/net/miginfocom/layout/ 0000775 0000000 0000000 00000000000 13241015632 0023204 5 ustar 00root root 0000000 0000000 miglayout-5.1/core/src/main/java/net/miginfocom/layout/AC.java 0000775 0000000 0000000 00000062057 13241015632 0024347 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.io.*;
import java.util.ArrayList;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A constraint that holds the column or row constraints for the grid. It also holds the gaps between the rows and columns.
*
* This class is a holder and builder for a number of {@link net.miginfocom.layout.DimConstraint}s.
*
* For a more thorough explanation of what these constraints do, and how to build the constraints, see the White Paper or Cheat Sheet at www.migcomponents.com.
*
* Note that there are two way to build this constraint. Through String (e.g. "[100]3[200,fill]" or through API (E.g.
* new AC().size("100").gap("3").size("200").fill().
*/
public final class AC implements Externalizable
{
private final ArrayList cList = new ArrayList(1);
private transient int curIx = 0;
/** Constructor. Creates an instance that can be configured manually. Will be initialized with a default
* {@link net.miginfocom.layout.DimConstraint}.
*/
public AC()
{
cList.add(new DimConstraint());
}
/** Property. The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of.
* These DimConstraints contains all information in this class.
*
* Yes, we are embarrassingly aware that the method is misspelled.
* @return The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. A new list and
* never null.
*/
public final DimConstraint[] getConstaints()
{
return cList.toArray(new DimConstraint[cList.size()]);
}
/** Sets the different {@link net.miginfocom.layout.DimConstraint}s that this object should consists of.
*
* Yes, we are embarrassingly aware that the method is misspelled.
* @param constr The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. The list
* will be copied for storage. null or and empty array will reset the constraints to one DimConstraint
* with default values.
*/
public final void setConstaints(DimConstraint[] constr)
{
if (constr == null || constr.length < 1 )
constr = new DimConstraint[] {new DimConstraint()};
cList.clear();
cList.ensureCapacity(constr.length);
for (DimConstraint c : constr)
cList.add(c);
}
/** Returns the number of rows/columns that this constraints currently have.
* @return The number of rows/columns that this constraints currently have. At least 1.
*/
public int getCount()
{
return cList.size();
}
/** Sets the total number of rows/columns to size. If the number of rows/columns is already more
* than size nothing will happen.
* @param size The total number of rows/columns
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC count(int size)
{
makeSize(size);
return this;
}
/** Specifies that the current row/column should not be grid-like. The while row/column will have its components layed out
* in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC noGrid()
{
return noGrid(curIx);
}
/** Specifies that the indicated rows/columns should not be grid-like. The while row/column will have its components layed out
* in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC noGrid(int... indexes)
{
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setNoGrid(true);
}
return this;
}
/** Sets the current row/column to i. If the current number of rows/columns is less than i a call
* to {@link #count(int)} will set the size accordingly.
*
* The next call to any of the constraint methods (e.g. {@link net.miginfocom.layout.AC#noGrid}) will be carried
* out on this new row/column.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param i The new current row/column.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC index(int i)
{
makeSize(i);
curIx = i;
return this;
}
/** Specifies that the current row/column's component should grow by default. It does not affect the size of the row/column.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC fill()
{
return fill(curIx);
}
/** Specifies that the indicated rows'/columns' component should grow by default. It does not affect the size of the row/column.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC fill(int... indexes)
{
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setFill(true);
}
return this;
}
// /** Specifies that the current row/column should be put in the end group s and will thus share the same ending
// * coordinate within the group.
// *
// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
// * @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
// */
// public final AxisConstraint endGroup(String s)
// {
// return endGroup(s, curIx);
// }
//
// /** Specifies that the indicated rows/columns should be put in the end group s and will thus share the same ending
// * coordinate within the group.
// *
// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
// * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
// * @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
// */
// public final AxisConstraint endGroup(String s, int... indexes)
// {
// for (int i = indexes.length - 1; i >= 0; i--) {
// int ix = indexes[i];
// makeSize(ix);
// cList.get(ix).setEndGroup(s);
// }
// return this;
// }
/** Specifies that the current row/column should be put in the size group s and will thus share the same size
* constraints as the other components in the group.
*
* Same as sizeGroup("")
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final AC sizeGroup()
{
return sizeGroup("", curIx);
}
/** Specifies that the current row/column should be put in the size group s and will thus share the same size
* constraints as the other components in the group.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s A name to associate on the group that should be the same for other rows/columns in the same group.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC sizeGroup(String s)
{
return sizeGroup(s, curIx);
}
/** Specifies that the indicated rows/columns should be put in the size group s and will thus share the same size
* constraints as the other components in the group.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s A name to associate on the group that should be the same for other rows/columns in the same group.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC sizeGroup(String s, int... indexes)
{
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setSizeGroup(s);
}
return this;
}
/** Specifies the current row/column's min and/or preferred and/or max size. E.g. "10px" or "50:100:200".
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
* as a BoundSize. For more info on how BoundSize is formatted see the documentation.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC size(String s)
{
return size(s, curIx);
}
/** Specifies the indicated rows'/columns' min and/or preferred and/or max size. E.g. "10px" or "50:100:200".
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
* as a BoundSize. For more info on how BoundSize is formatted see the documentation.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC size(String size, int... indexes)
{
BoundSize bs = ConstraintParser.parseBoundSize(size, false, true);
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setSize(bs);
}
return this;
}
/** Specifies the gap size to be the default one AND moves to the next column/row. The method is called .gap()
* rather the more natural .next() to indicate that it is very much related to the other .gap(..) methods.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC gap()
{
curIx++;
makeSize(curIx);
return this;
}
/** Specifies the gap size to sizeAND moves to the next column/row.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
* The string will be interpreted as a BoundSize. For more info on how BoundSize is formatted see the documentation.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC gap(String size)
{
return gap(size, curIx++);
}
/** Specifies the indicated rows'/columns' gap size to size.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
* The string will be interpreted as a BoundSize. For more info on how BoundSize is formatted see the documentation.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC gap(String size, int... indexes)
{
BoundSize bsa = size != null ? ConstraintParser.parseBoundSize(size, true, true) : null;
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix + 1);
if (bsa != null)
cList.get(ix).setGapAfter(bsa);
}
return this;
}
/** Specifies the current row/column's columns default alignment for its components. It does not affect the positioning
* or size of the columns/row itself. For columns it is the horizontal alignment (e.g. "left") and for rows it is the vertical
* alignment (e.g. "top").
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param side The default side to align the components. E.g. "top" or "left", or "leading" or "trailing" or "bottom" or "right".
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC align(String side)
{
return align(side, curIx);
}
/** Specifies the indicated rows'/columns' columns default alignment for its components. It does not affect the positioning
* or size of the columns/row itself. For columns it is the horizontal alignment (e.g. "left") and for rows it is the vertical
* alignment (e.g. "top").
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param side The default side to align the components. E.g. "top" or "left", or "before" or "after" or "bottom" or "right".
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC align(String side, int... indexes)
{
UnitValue al = ConstraintParser.parseAlignKeywords(side, true);
if (al == null)
al = ConstraintParser.parseAlignKeywords(side, false);
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setAlign(al);
}
return this;
}
/** Specifies the current row/column's grow priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new grow priority.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC growPrio(int p)
{
return growPrio(p, curIx);
}
/** Specifies the indicated rows'/columns' grow priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new grow priority.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC growPrio(int p, int... indexes)
{
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setGrowPriority(p);
}
return this;
}
/** Specifies the current row/column's grow weight within columns/rows with the grow priority 100f.
*
* Same as grow(100f)
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final AC grow()
{
return grow(100f, curIx);
}
/** Specifies the current row/column's grow weight within columns/rows with the same grow priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new grow weight.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC grow(float w)
{
return grow(w, curIx);
}
/** Specifies the indicated rows'/columns' grow weight within columns/rows with the same grow priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new grow weight.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC grow(float w, int... indexes)
{
Float gw = new Float(w);
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setGrow(gw);
}
return this;
}
/** Specifies the current row/column's shrink priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new shrink priority.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC shrinkPrio(int p)
{
return shrinkPrio(p, curIx);
}
/** Specifies the indicated rows'/columns' shrink priority.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new shrink priority.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
*/
public final AC shrinkPrio(int p, int... indexes)
{
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setShrinkPriority(p);
}
return this;
}
/** Specifies that the current row/column's shrink weight within the columns/rows with the shrink priority 100f.
*
* Same as shrink(100f).
*
* For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final AC shrink()
{
return shrink(100f, curIx);
}
/** Specifies that the current row/column's shrink weight within the columns/rows with the same shrink priority.
*
* For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
* @param w The shrink weight.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final AC shrink(float w)
{
return shrink(w, curIx);
}
/** Specifies the indicated rows'/columns' shrink weight within the columns/rows with the same shrink priority.
*
* For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
* @param w The shrink weight.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final AC shrink(float w, int... indexes)
{
Float sw = new Float(w);
for (int i = indexes.length - 1; i >= 0; i--) {
int ix = indexes[i];
makeSize(ix);
cList.get(ix).setShrink(sw);
}
return this;
}
/** Specifies that the current row/column's shrink weight within the columns/rows with the same shrink priority.
*
* For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
* @param w The shrink weight.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @deprecated in 3.7.2. Use {@link #shrink(float)} instead.
*/
public final AC shrinkWeight(float w)
{
return shrink(w);
}
/** Specifies the indicated rows'/columns' shrink weight within the columns/rows with the same shrink priority.
*
* For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
* @param w The shrink weight.
* @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
* @return this so it is possible to chain calls. E.g. new AxisConstraint().noGrid().gap().fill().
* @deprecated in 3.7.2. Use {@link #shrink(float, int...)} instead.
*/
public final AC shrinkWeight(float w, int... indexes)
{
return shrink(w, indexes);
}
private void makeSize(int sz)
{
if (cList.size() <= sz) {
cList.ensureCapacity(sz);
for (int i = cList.size(); i <= sz; i++)
cList.add(new DimConstraint());
}
}
// ************************************************
// Persistence Delegate and Serializable combined.
// ************************************************
private Object readResolve() throws ObjectStreamException
{
return LayoutUtil.getSerializedObject(this);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
}
@Override
public void writeExternal(ObjectOutput out) throws IOException
{
if (getClass() == AC.class)
LayoutUtil.writeAsXML(out, this);
}
} miglayout-5.1/core/src/main/java/net/miginfocom/layout/AnimSpec.java 0000664 0000000 0000000 00000007314 13241015632 0025553 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
*/
import java.io.Serializable;
/**
* @author Mikael Grev, MiG InfoCom AB
* Date: 14-09-24
* Time: 17:05
*/
public class AnimSpec implements Serializable
{
// public static final AnimSpec OFF = new AnimSpec(-1, 0, 0);
public static final AnimSpec DEF = new AnimSpec(0, 0, 0.2f, 0.2f);
private final int prio;
private final int durMillis;
private final float easeIn, easeOut;
/**
* @param prio The animation priority. When added with the general animation priority of the layout the animation will
* be done if the resulting value is > 0.
* @param durMillis Duration in milliseconds. <=0 means default value should be used and > 0 is the number of millis
* @param easeIn 0 is linear (no ease). 1 is max ease. Always clamped between these values.
* @param easeOut 0 is linear (no ease). 1 is max ease. Always clamped between these values.
*/
public AnimSpec(int prio, int durMillis, float easeIn, float easeOut)
{
this.prio = prio;
this.durMillis = durMillis;
this.easeIn = LayoutUtil.clamp(easeIn, 0, 1);
this.easeOut = LayoutUtil.clamp(easeOut, 0, 1);
}
/**
* @return The animation priority. When added with the general animation priority of the layout the animation will
* be done if the resulting value is > 0.
*/
public int getPriority()
{
return prio;
}
/**
* @param defMillis Default used if the millis in the spec is set to "default".
* @return Duration in milliseconds. <=0 means default value should be used and > 0 is the number of millis
*/
public int getDurationMillis(int defMillis)
{
return durMillis > 0 ? durMillis : defMillis;
}
/**
* @return Duration in milliseconds. <= 0 means default value should be used and > 0 is the number of millis
*/
public int getDurationMillis()
{
return durMillis;
}
/**
* @return A value between 0 and 1 where 0 is no ease in and 1 is maximum ease in.
*/
public float getEaseIn()
{
return easeIn;
}
/**
* @return A value between 0 and 1 where 0 is no ease out and 1 is maximum ease out.
*/
public float getEaseOut()
{
return easeOut;
}
}
miglayout-5.1/core/src/main/java/net/miginfocom/layout/BoundSize.java 0000775 0000000 0000000 00000024525 13241015632 0025764 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.beans.Encoder;
import java.beans.Expression;
import java.beans.PersistenceDelegate;
import java.io.*;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A size that contains minimum, preferred and maximum size of type {@link UnitValue}.
*
* This class is a simple value container and it is immutable.
*
* If a size is missing (i.e., null) that boundary should be considered "not in use".
*
* You can create a BoundSize from a String with the use of {@link ConstraintParser#parseBoundSize(String, boolean, boolean)}
*/
public class BoundSize implements Serializable
{
public static final BoundSize NULL_SIZE = new BoundSize(null, null);
public static final BoundSize ZERO_PIXEL = new BoundSize(UnitValue.ZERO, "0px");
private final transient UnitValue min;
private final transient UnitValue pref;
private final transient UnitValue max;
private final transient boolean gapPush;
/** Constructor that use the same value for min/preferred/max size.
* @param minMaxPref The value to use for min/preferred/max size.
* @param createString The string used to create the BoundsSize.
*/
public BoundSize(UnitValue minMaxPref, String createString)
{
this(minMaxPref, minMaxPref, minMaxPref, createString);
}
/** Constructor. This method is here for serialization only and should normally not be used. Use
* {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
* @param min The minimum size. May be null.
* @param preferred The preferred size. May be null.
* @param max The maximum size. May be null.
* @param createString The string used to create the BoundsSize.
*/
public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, String createString) // Bound to old delegate!!!!!
{
this(min, preferred, max, false, createString);
}
/** Constructor. This method is here for serialization only and should normally not be used. Use
* {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
* @param min The minimum size. May be null.
* @param preferred The preferred size. May be null.
* @param max The maximum size. May be null.
* @param gapPush If the size should be hinted as "pushing" and thus want to occupy free space if no one else is claiming it.
* @param createString The string used to create the BoundsSize.
*/
public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, boolean gapPush, String createString)
{
this.min = min;
this.pref = preferred;
this.max = max;
this.gapPush = gapPush;
LayoutUtil.putCCString(this, createString); // this escapes!!
}
/** Returns the minimum size as sent into the constructor.
* @return The minimum size as sent into the constructor. May be null.
*/
public final UnitValue getMin()
{
return min;
}
/** Returns the preferred size as sent into the constructor.
* @return The preferred size as sent into the constructor. May be null.
*/
public final UnitValue getPreferred()
{
return pref;
}
/** Returns the maximum size as sent into the constructor.
* @return The maximum size as sent into the constructor. May be null.
*/
public final UnitValue getMax()
{
return max;
}
/** If the size should be hinted as "pushing" and thus want to occupy free space if no one else is claiming it.
* @return The value.
*/
public boolean getGapPush()
{
return gapPush;
}
/** Returns if this bound size has no min, preferred and maximum size set (they are all null)
* @return If unset.
*/
public boolean isUnset()
{
// Most common case by far is this == ZERO_PIXEL...
return this == ZERO_PIXEL || (pref == null && min == null && max == null && gapPush == false);
}
/** Makes sure that size is within min and max of this size.
* @param size The size to constrain.
* @param refValue The reference to use for relative sizes.
* @param parent The parent container.
* @return The size, constrained within min and max.
*/
public int constrain(int size, float refValue, ContainerWrapper parent)
{
if (max != null)
size = Math.min(size, max.getPixels(refValue, parent, parent));
if (min != null)
size = Math.max(size, min.getPixels(refValue, parent, parent));
return size;
}
/** Returns the minimum, preferred or maximum size for this bounded size.
* @param sizeType The type. LayoutUtil.MIN, LayoutUtil.PREF or LayoutUtil.MAX.
* @return
*/
final UnitValue getSize(int sizeType)
{
switch(sizeType) {
case LayoutUtil.MIN:
return min;
case LayoutUtil.PREF:
return pref;
case LayoutUtil.MAX:
return max;
default:
throw new IllegalArgumentException("Unknown size: " + sizeType);
}
}
/** Convert the bound sizes to pixels.
*
* null bound sizes will be 0 for min and preferred and {@link net.miginfocom.layout.LayoutUtil#INF} for max.
* @param refSize The reference size.
* @param parent The parent. Not null.
* @param comp The component, if applicable, can be null.
* @return An array of length three (min,pref,max).
*/
final int[] getPixelSizes(float refSize, ContainerWrapper parent, ComponentWrapper comp)
{
return new int[] {
min != null ? min.getPixels(refSize, parent, comp) : 0,
pref != null ? pref.getPixels(refSize, parent, comp) : 0,
max != null ? max.getPixels(refSize, parent, comp) : LayoutUtil.INF
};
}
/** Returns the a constraint string that can be re-parsed to be the exact same UnitValue.
* @return A String. Never null.
*/
String getConstraintString()
{
String cs = LayoutUtil.getCCString(this);
if (cs != null)
return cs;
if (min == pref && pref == max)
return min != null ? (min.getConstraintString() + "!") : "null";
StringBuilder sb = new StringBuilder(16);
if (min != null)
sb.append(min.getConstraintString()).append(':');
if (pref != null) {
if (min == null && max != null)
sb.append(":");
sb.append(pref.getConstraintString());
} else if (min != null) {
sb.append('n');
}
if (max != null)
sb.append(sb.length() == 0 ? "::" : ":").append(max.getConstraintString());
if (gapPush) {
if (sb.length() > 0)
sb.append(':');
sb.append("push");
}
return sb.toString();
}
void checkNotLinked()
{
if (isLinked())
throw new IllegalArgumentException("Size may not contain links");
}
boolean isLinked()
{
return min != null && min.isLinkedDeep() || pref != null && pref.isLinkedDeep() || max != null && max.isLinkedDeep();
}
boolean isAbsolute()
{
return (min == null || min.isAbsoluteDeep()) && (pref == null || pref.isAbsoluteDeep()) && (max == null || max.isAbsoluteDeep());
}
public String toString()
{
return "BoundSize{" + "min=" + min + ", pref=" + pref + ", max=" + max + ", gapPush=" + gapPush +'}';
}
static {
if(LayoutUtil.HAS_BEANS){
LayoutUtil.setDelegate(BoundSize.class, new PersistenceDelegate() {
@Override
protected Expression instantiate(Object oldInstance, Encoder out)
{
BoundSize bs = (BoundSize) oldInstance;
if (Grid.TEST_GAPS) {
return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getGapPush(), bs.getConstraintString()
});
} else {
return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getConstraintString()
});
}
}
});
}
}
// ************************************************
// Persistence Delegate and Serializable combined.
// ************************************************
private static final long serialVersionUID = 1L;
protected Object readResolve() throws ObjectStreamException
{
return LayoutUtil.getSerializedObject(this);
}
private void writeObject(ObjectOutputStream out) throws IOException
{
if (getClass() == BoundSize.class)
LayoutUtil.writeAsXML(out, this);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
}
}
miglayout-5.1/core/src/main/java/net/miginfocom/layout/CC.java 0000775 0000000 0000000 00000236232 13241015632 0024347 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.io.*;
import java.util.ArrayList;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A simple value holder for one component's constraint.
*/
public final class CC implements Externalizable
{
private static final BoundSize DEF_GAP = BoundSize.NULL_SIZE; // Only used to denote default wrap/newline gap.
static final String[] DOCK_SIDES = {"north", "west", "south", "east"};
// See the getters and setters for information about the properties below.
private int dock = -1;
private UnitValue[] pos = null; // [x1, y1, x2, y2]
private UnitValue[] padding = null; // top, left, bottom, right
private UnitValue[] visualPadding = null; // top, left, bottom, right
private Boolean flowX = null;
private int skip = 0;
private int split = 1;
private int spanX = 1, spanY = 1;
private int cellX = -1, cellY = 0; // If cellX is -1 then cellY is also considered -1. cellY is never negative.
private String tag = null;
private String id = null;
private int hideMode = -1;
private DimConstraint hor = new DimConstraint();
private DimConstraint ver = new DimConstraint();
private BoundSize newline = null;
private BoundSize wrap = null;
private boolean boundsInGrid = true;
private boolean external = false;
private Float pushX = null, pushY = null;
private AnimSpec animSpec = AnimSpec.DEF;
// ***** Tmp cache field
private static final String[] EMPTY_ARR = new String[0];
private transient String[] linkTargets = null;
/** Empty constructor.
*/
public CC()
{
}
String[] getLinkTargets()
{
if (linkTargets == null) {
final ArrayList targets = new ArrayList(2);
if (pos != null) {
for (int i = 0; i < pos.length ; i++)
addLinkTargetIDs(targets, pos[i]);
}
linkTargets = targets.size() == 0 ? EMPTY_ARR : targets.toArray(new String[targets.size()]);
}
return linkTargets;
}
private void addLinkTargetIDs(ArrayList targets, UnitValue uv)
{
if (uv != null) {
String linkId = uv.getLinkTargetId();
if (linkId != null) {
targets.add(linkId);
} else {
for (int i = uv.getSubUnitCount() - 1; i >= 0; i--) {
UnitValue subUv = uv.getSubUnitValue(i);
if (subUv.isLinkedDeep())
addLinkTargetIDs(targets, subUv);
}
}
}
}
// **********************************************************
// Chaining constraint setters
// **********************************************************
/** Specifies that the component should be put in the end group s and will thus share the same ending
* coordinate as them within the group.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s A name to associate on the group that should be the same for other rows/columns in the same group.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC endGroupX(String s)
{
hor.setEndGroup(s);
return this;
}
/** Specifies that the component should be put in the size group s and will thus share the same size
* as them within the group.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s A name to associate on the group that should be the same for other rows/columns in the same group.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC sizeGroupX(String s)
{
hor.setSizeGroup(s);
return this;
}
/** The minimum size for the component. The value will override any value that is set on the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a UnitValue. E.g. "100px" or "200mm".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC minWidth(String size)
{
hor.setSize(LayoutUtil.derive(hor.getSize(), ConstraintParser.parseUnitValue(size, true), null, null));
return this;
}
/** The size for the component as a min and/or preferred and/or maximum size. The value will override any value that is set on
* the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a BoundSize. E.g. "50:100px:200mm" or "100px".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC width(String size)
{
hor.setSize(ConstraintParser.parseBoundSize(size, false, true));
return this;
}
/** The maximum size for the component. The value will override any value that is set on the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a UnitValue. E.g. "100px" or "200mm".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC maxWidth(String size)
{
hor.setSize(LayoutUtil.derive(hor.getSize(), null, null, ConstraintParser.parseUnitValue(size, true)));
return this;
}
/** The horizontal gap before and/or after the component. The gap is towards cell bounds and/or other component bounds.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param before The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @param after The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC gapX(String before, String after)
{
if (before != null)
hor.setGapBefore(ConstraintParser.parseBoundSize(before, true, true));
if (after != null)
hor.setGapAfter(ConstraintParser.parseBoundSize(after, true, true));
return this;
}
/** Same functionality as getHorizontal().setAlign(ConstraintParser.parseUnitValue(unitValue, true)) only this method
* returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC alignX(String align)
{
hor.setAlign(ConstraintParser.parseUnitValueOrAlign(align, true, null));
return this;
}
/** The grow priority compared to other components in the same cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The grow priority.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC growPrioX(int p)
{
hor.setGrowPriority(p);
return this;
}
/** Grow priority for the component horizontally and optionally vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param widthHeight The new shrink weight and height. 1-2 arguments, never null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC growPrio(int ... widthHeight)
{
switch (widthHeight.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + widthHeight.length);
case 2:
growPrioY(widthHeight[1]);
case 1:
growPrioX(widthHeight[0]);
}
return this;
}
/** Grow weight for the component horizontally. It default to weight 100.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #growX(float)
*/
public final CC growX()
{
hor.setGrow(ResizeConstraint.WEIGHT_100);
return this;
}
/** Grow weight for the component horizontally.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new grow weight.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC growX(float w)
{
hor.setGrow(new Float(w));
return this;
}
/** grow weight for the component horizontally and optionally vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param widthHeight The new shrink weight and height. 1-2 arguments, never null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC grow(float ... widthHeight)
{
switch (widthHeight.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + widthHeight.length);
case 2:
growY(widthHeight[1]);
case 1:
growX(widthHeight[0]);
}
return this;
}
/** The shrink priority compared to other components in the same cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The shrink priority.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC shrinkPrioX(int p)
{
hor.setShrinkPriority(p);
return this;
}
/** Shrink priority for the component horizontally and optionally vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param widthHeight The new shrink weight and height. 1-2 arguments, never null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC shrinkPrio(int ... widthHeight)
{
switch (widthHeight.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + widthHeight.length);
case 2:
shrinkPrioY(widthHeight[1]);
case 1:
shrinkPrioX(widthHeight[0]);
}
return this;
}
/** Shrink weight for the component horizontally.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new shrink weight.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC shrinkX(float w)
{
hor.setShrink(new Float(w));
return this;
}
/** Shrink weight for the component horizontally and optionally vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param widthHeight The new shrink weight and height. 1-2 arguments, never null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC shrink(float ... widthHeight)
{
switch (widthHeight.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + widthHeight.length);
case 2:
shrinkY(widthHeight[1]);
case 1:
shrinkX(widthHeight[0]);
}
return this;
}
/** The end group that this component should be placed in.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The name of the group. If null that means no group (default)
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC endGroupY(String s)
{
ver.setEndGroup(s);
return this;
}
/** The end group(s) that this component should be placed in.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param xy The end group for x and y respectively. 1-2 arguments, not null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC endGroup(String ... xy)
{
switch (xy.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + xy.length);
case 2:
endGroupY(xy[1]);
case 1:
endGroupX(xy[0]);
}
return this;
}
/** The size group that this component should be placed in.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The name of the group. If null that means no group (default)
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC sizeGroupY(String s)
{
ver.setSizeGroup(s);
return this;
}
/** The size group(s) that this component should be placed in.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param xy The size group for x and y respectively. 1-2 arguments, not null.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC sizeGroup(String ... xy)
{
switch (xy.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + xy.length);
case 2:
sizeGroupY(xy[1]);
case 1:
sizeGroupX(xy[0]);
}
return this;
}
/** The minimum size for the component. The value will override any value that is set on the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a UnitValue. E.g. "100px" or "200mm".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC minHeight(String size)
{
ver.setSize(LayoutUtil.derive(ver.getSize(), ConstraintParser.parseUnitValue(size, false), null, null));
return this;
}
/** The size for the component as a min and/or preferred and/or maximum size. The value will override any value that is set on
* the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a BoundSize. E.g. "50:100px:200mm" or "100px".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC height(String size)
{
ver.setSize(ConstraintParser.parseBoundSize(size, false, false));
return this;
}
/** The maximum size for the component. The value will override any value that is set on the component itself.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The size expressed as a UnitValue. E.g. "100px" or "200mm".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC maxHeight(String size)
{
ver.setSize(LayoutUtil.derive(ver.getSize(), null, null, ConstraintParser.parseUnitValue(size, false)));
return this;
}
/** The vertical gap before (normally above) and/or after (normally below) the component. The gap is towards cell bounds and/or other component bounds.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param before The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @param after The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC gapY(String before, String after)
{
if (before != null)
ver.setGapBefore(ConstraintParser.parseBoundSize(before, true, false));
if (after != null)
ver.setGapAfter(ConstraintParser.parseBoundSize(after, true, false));
return this;
}
/** Same functionality as getVertical().setAlign(ConstraintParser.parseUnitValue(unitValue, true)) only this method
* returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param align The align keyword or for instance "100px". E.g "top" or "bottom".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC alignY(String align)
{
ver.setAlign(ConstraintParser.parseUnitValueOrAlign(align, false, null));
return this;
}
/** The grow priority compared to other components in the same cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The grow priority.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC growPrioY(int p)
{
ver.setGrowPriority(p);
return this;
}
/** Grow weight for the component vertically. Defaults to 100.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #growY(Float)
*/
public final CC growY()
{
ver.setGrow(ResizeConstraint.WEIGHT_100);
return this;
}
/** Grow weight for the component vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new grow weight.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC growY(float w)
{
ver.setGrow(w);
return this;
}
/** Grow weight for the component vertically.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new grow weight.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
@Deprecated
public final CC growY(Float w)
{
ver.setGrow(w);
return this;
}
/** The shrink priority compared to other components in the same cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The shrink priority.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC shrinkPrioY(int p)
{
ver.setShrinkPriority(p);
return this;
}
/** Shrink weight for the component horizontally.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param w The new shrink weight.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC shrinkY(float w)
{
ver.setShrink(new Float(w));
return this;
}
/** How this component, if hidden (not visible), should be treated.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param mode The mode. Default to the mode in the {@link net.miginfocom.layout.LC}.
* 0 == Normal. Bounds will be calculated as if the component was visible.
* 1 == If hidden the size will be 0, 0 but the gaps remain.
* 2 == If hidden the size will be 0, 0 and gaps set to zero.
* 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC hideMode(int mode)
{
setHideMode(mode);
return this;
}
/** The id used to reference this component in some constraints.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The id or null. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
* The dot should never be first or last if present.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
*/
public final CC id(String s)
{
setId(s);
return this;
}
/** Same functionality as {@link #setTag(String tag)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param tag The new tag. May be null.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setTag(String)
*/
public final CC tag(String tag)
{
setTag(tag);
return this;
}
/** Set the cell(s) that the component should occupy in the grid. Same functionality as {@link #setCellX(int col)} and
* {@link #setCellY(int row)} together with {@link #setSpanX(int width)} and {@link #setSpanY(int height)}. This method
* returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param colRowWidthHeight cellX, cellY, spanX, spanY respectively. 1-4 arguments, not null.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setCellX(int)
* @see #setCellY(int)
* @see #setSpanX(int)
* @see #setSpanY(int)
* @since 3.7.2. Replacing cell(int, int) and cell(int, int, int, int)
*/
public final CC cell(int ... colRowWidthHeight)
{
switch (colRowWidthHeight.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + colRowWidthHeight.length);
case 4:
setSpanY(colRowWidthHeight[3]);
case 3:
setSpanX(colRowWidthHeight[2]);
case 2:
setCellY(colRowWidthHeight[1]);
case 1:
setCellX(colRowWidthHeight[0]);
}
return this;
}
/** Same functionality as spanX(cellsX).spanY(cellsY) which means this cell will span cells in both x and y.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* Since 3.7.2 this takes an array/vararg whereas it previously only took two specific values, xSpan and ySpan.
* @param cells spanX and spanY, when present, and in that order.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setSpanY(int)
* @see #setSpanX(int)
* @see #spanY()
* @see #spanX()
* @since 3.7.2 Replaces span(int, int).
*/
public final CC span(int ... cells)
{
if (cells == null || cells.length == 0) {
setSpanX(LayoutUtil.INF);
setSpanY(1);
} else if (cells.length == 1) {
setSpanX(cells[0]);
setSpanY(1);
} else {
setSpanX(cells[0]);
setSpanY(cells[1]);
}
return this;
}
/** Corresponds exactly to the "gap left right top bottom" keyword.
* @param args Same as for the "gap" keyword. Length 1-4, never null buf elements can be null.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gap(String ... args)
{
switch (args.length) {
default:
throw new IllegalArgumentException("Illegal argument count: " + args.length);
case 4:
gapBottom(args[3]);
case 3:
gapTop(args[2]);
case 2:
gapRight(args[1]);
case 1:
gapLeft(args[0]);
}
return this;
}
/** Sets the horizontal gap before the component.
*
* Note! This is currently same as gapLeft(). This might change in 4.x.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapBefore(String boundsSize)
{
hor.setGapBefore(ConstraintParser.parseBoundSize(boundsSize, true, true));
return this;
}
/** Sets the horizontal gap after the component.
*
* Note! This is currently same as gapRight(). This might change in 4.x.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapAfter(String boundsSize)
{
hor.setGapAfter(ConstraintParser.parseBoundSize(boundsSize, true, true));
return this;
}
/** Sets the gap above the component.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapTop(String boundsSize)
{
ver.setGapBefore(ConstraintParser.parseBoundSize(boundsSize, true, false));
return this;
}
/** Sets the gap to the left the component.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapLeft(String boundsSize)
{
hor.setGapBefore(ConstraintParser.parseBoundSize(boundsSize, true, true));
return this;
}
/** Sets the gap below the component.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapBottom(String boundsSize)
{
ver.setGapAfter(ConstraintParser.parseBoundSize(boundsSize, true, false));
return this;
}
/** Sets the gap to the right of the component.
* @param boundsSize The size of the gap expressed as a BoundSize. E.g. "50:100px:200mm" or "100px!".
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @since 3.7.2
*/
public final CC gapRight(String boundsSize)
{
hor.setGapAfter(ConstraintParser.parseBoundSize(boundsSize, true, true));
return this;
}
/** Same functionality as calling {@link #setSpanY(int)} with LayoutUtil.INF which means this cell will span the rest of the column.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setSpanY(int)
* @see #spanY()
*/
public final CC spanY()
{
return spanY(LayoutUtil.INF);
}
/** Same functionality as {@link #setSpanY(int)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells The number of cells to span (i.e. merge).
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setSpanY(int)
*/
public final CC spanY(int cells)
{
setSpanY(cells);
return this;
}
/** Same functionality as {@link #setSpanX(int)} which means this cell will span the rest of the row.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setSpanX(int)
* @see #spanX()
*/
public final CC spanX()
{
return spanX(LayoutUtil.INF);
}
/** Same functionality as {@link #setSpanX(int)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells The number of cells to span (i.e. merge).
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setSpanY(int)
*/
public final CC spanX(int cells)
{
setSpanX(cells);
return this;
}
/** Same functionality as pushX().pushY() which means this cell will push in both x and y dimensions.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushX(Float)
* @see #setPushX(Float)
* @see #pushY()
* @see #pushX()
*/
public final CC push()
{
return pushX().pushY();
}
/** Same functionality as pushX(weightX).pushY(weightY) which means this cell will push in both x and y dimensions.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param weightX The weight used in the push.
* @param weightY The weight used in the push.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushY(Float)
* @see #setPushX(Float)
* @see #pushY()
* @see #pushX()
*/
public final CC push(Float weightX, Float weightY)
{
return pushX(weightX).pushY(weightY);
}
/** Same functionality as {@link #setPushY(Float)} which means this cell will push the rest of the column.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushY(Float)
*/
public final CC pushY()
{
return pushY(ResizeConstraint.WEIGHT_100);
}
/** Same functionality as {@link #setPushY(Float weight)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param weight The weight used in the push.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushY(Float)
*/
public final CC pushY(Float weight)
{
setPushY(weight);
return this;
}
/** Same functionality as {@link #setPushX(Float)} which means this cell will push the rest of the row.
* This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushX(Float)
*/
public final CC pushX()
{
return pushX(ResizeConstraint.WEIGHT_100);
}
/** Same functionality as {@link #setPushX(Float weight)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param weight The weight used in the push.
* @return this so it is possible to chain calls. E.g. new LayoutConstraint().noGrid().gap().fill().
* @see #setPushY(Float)
*/
public final CC pushX(Float weight)
{
setPushX(weight);
return this;
}
/** Same functionality as {@link #setSplit(int parts)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param parts The number of parts (i.e. component slots) the cell should be divided into.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setSplit(int)
*/
public final CC split(int parts)
{
setSplit(parts);
return this;
}
/** Same functionality as split(LayoutUtil.INF), which means split until one of the keywords that breaks the split is found for
* a component after this one (e.g. wrap, newline and skip).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setSplit(int)
* @since 3.7.2
*/
public final CC split()
{
setSplit(LayoutUtil.INF);
return this;
}
/** Same functionality as {@link #setSkip(int)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells How many cells in the grid that should be skipped before the component that this constraint belongs to
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setSkip(int)
*/
public final CC skip(int cells)
{
setSkip(cells);
return this;
}
/** Same functionality as skip(1).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setSkip(int)
* @since 3.7.2
*/
public final CC skip()
{
setSkip(1);
return this;
}
/** Same functionality as calling {@link #setExternal(boolean)} with true only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setExternal(boolean)
*/
public final CC external()
{
setExternal(true);
return this;
}
/** Same functionality as calling {@link #setFlowX(Boolean)} with Boolean.TRUE only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setFlowX(Boolean)
*/
public final CC flowX()
{
setFlowX(Boolean.TRUE);
return this;
}
/** Same functionality as calling {@link #setFlowX(Boolean)} with Boolean.FALSE only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setFlowX(Boolean)
*/
public final CC flowY()
{
setFlowX(Boolean.FALSE);
return this;
}
/** Same functionality as {@link #growX()} and {@link #growY()}.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #growX()
* @see #growY()
*/
public final CC grow()
{
growX();
growY();
return this;
}
/** Same functionality as calling {@link #setNewline(boolean)} with true only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setNewline(boolean)
*/
public final CC newline()
{
setNewline(true);
return this;
}
/** Same functionality as {@link #setNewlineGapSize(BoundSize)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param gapSize The gap size that will override the gap size in the row/column constraints if != null. E.g. "5px" or "unrel".
* If null or "" the newline size will be set to the default size and turned on. This is different compared to
* {@link #setNewlineGapSize(BoundSize)}.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setNewlineGapSize(BoundSize)
*/
public final CC newline(String gapSize)
{
BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
if (bs != null) {
setNewlineGapSize(bs);
} else {
setNewline(true);
}
return this;
}
/** Same functionality as calling {@link #setWrap(boolean)} with true only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setWrap(boolean)
*/
public final CC wrap()
{
setWrap(true);
return this;
}
/** Same functionality as {@link #setWrapGapSize(BoundSize)} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param gapSize The gap size that will override the gap size in the row/column constraints if != null. E.g. "5px" or "unrel".
* If null or "" the wrap size will be set to the default size and turned on. This is different compared to
* {@link #setWrapGapSize(BoundSize)}.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setWrapGapSize(BoundSize)
*/
public final CC wrap(String gapSize)
{
BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
if (bs != null) {
setWrapGapSize(bs);
} else {
setWrap(true);
}
return this;
}
/** Same functionality as calling {@link #setDockSide(int)} with 0 only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setDockSide(int)
*/
public final CC dockNorth()
{
setDockSide(0);
return this;
}
/** Same functionality as calling {@link #setDockSide(int)} with 1 only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setDockSide(int)
*/
public final CC dockWest()
{
setDockSide(1);
return this;
}
/** Same functionality as calling {@link #setDockSide(int)} with 2 only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setDockSide(int)
*/
public final CC dockSouth()
{
setDockSide(2);
return this;
}
/** Same functionality as calling {@link #setDockSide(int)} with 3 only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setDockSide(int)
*/
public final CC dockEast()
{
setDockSide(3);
return this;
}
/** Sets the x-coordinate for the component. This is used to set the x coordinate position to a specific value. The component
* bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
* @see #setBoundsInGrid(boolean)
*/
public final CC x(String x)
{
return corrPos(x, 0);
}
/** Sets the y-coordinate for the component. This is used to set the y coordinate position to a specific value. The component
* bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
* @see #setBoundsInGrid(boolean)
*/
public final CC y(String y)
{
return corrPos(y, 1);
}
/** Sets the x2-coordinate for the component (right side). This is used to set the x2 coordinate position to a specific value. The component
* bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
* @see #setBoundsInGrid(boolean)
*/
public final CC x2(String x2)
{
return corrPos(x2, 2);
}
/** Sets the y2-coordinate for the component (bottom side). This is used to set the y2 coordinate position to a specific value. The component
* bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
* @see #setBoundsInGrid(boolean)
*/
public final CC y2(String y2)
{
return corrPos(y2, 3);
}
private final CC corrPos(String uv, int ix)
{
UnitValue[] b = getPos();
if (b == null)
b = new UnitValue[4];
b[ix] = ConstraintParser.parseUnitValue(uv, (ix % 2 == 0));
setPos(b);
setBoundsInGrid(true);
return this;
}
/** Same functionality as {@link #x(String x)} and {@link #y(String y)} together.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
*/
public final CC pos(String x, String y)
{
UnitValue[] b = getPos();
if (b == null)
b = new UnitValue[4];
b[0] = ConstraintParser.parseUnitValue(x, true);
b[1] = ConstraintParser.parseUnitValue(y, false);
setPos(b);
setBoundsInGrid(false);
return this;
}
/** Same functionality as {@link #x(String x)}, {@link #y(String y)}, {@link #y2(String y)} and {@link #y2(String y)} together.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
* @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
* @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setPos(UnitValue[])
*/
public final CC pos(String x, String y, String x2, String y2)
{
setPos(new UnitValue[] {
ConstraintParser.parseUnitValue(x, true),
ConstraintParser.parseUnitValue(y, false),
ConstraintParser.parseUnitValue(x2, true),
ConstraintParser.parseUnitValue(y2, false),
});
setBoundsInGrid(false);
return this;
}
/** Same functionality as {@link #setPadding(UnitValue[])} but the unit values as absolute pixels. This method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param top The top padding that will be added to the y coordinate at the last stage in the layout.
* @param left The top padding that will be added to the x coordinate at the last stage in the layout.
* @param bottom The top padding that will be added to the y2 coordinate at the last stage in the layout.
* @param right The top padding that will be added to the x2 coordinate at the last stage in the layout.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setTag(String)
*/
public final CC pad(int top, int left, int bottom, int right)
{
setPadding(new UnitValue[] {
new UnitValue(top), new UnitValue(left), new UnitValue(bottom), new UnitValue(right)
});
return this;
}
/** Same functionality as setPadding(ConstraintParser.parseInsets(pad, false))} only this method returns this for chaining multiple calls.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param pad The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
* @return this so it is possible to chain calls. E.g. new ComponentConstraint().noGrid().gap().fill().
* @see #setTag(String)
*/
public final CC pad(String pad)
{
setPadding(pad != null ? ConstraintParser.parseInsets(pad, false) : null);
return this;
}
// **********************************************************
// Bean properties
// **********************************************************
/** Returns the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
* and grow/shrink priorities and weights.
*
* Note! If any changes is to be made it must be made direct when the object is returned. It is not allowed to save the
* constraint for later use.
* @return The current dimension constraint. Never null.
*/
public DimConstraint getHorizontal()
{
return hor;
}
/** Sets the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
* and grow/shrink priorities and weights.
* @param h The new dimension constraint. If null it will be reset to new DimConstraint();
*/
public void setHorizontal(DimConstraint h)
{
hor = h != null ? h : new DimConstraint();
}
/** Returns the vertical dimension constraint for this component constraint. It has constraints for the vertical size
* and grow/shrink priorities and weights.
*
* Note! If any changes is to be made it must be made direct when the object is returned. It is not allowed to save the
* constraint for later use.
* @return The current dimension constraint. Never null.
*/
public DimConstraint getVertical()
{
return ver;
}
/** Sets the vertical dimension constraint for this component constraint. It has constraints for the vertical size
* and grow/shrink priorities and weights.
* @param v The new dimension constraint. If null it will be reset to new DimConstraint();
*/
public void setVertical(DimConstraint v)
{
ver = v != null ? v : new DimConstraint();
}
/** Returns the vertical or horizontal dim constraint.
*
* Note! If any changes is to be made it must be made direct when the object is returned. It is not allowed to save the
* constraint for later use.
* @param isHor If the horizontal constraint should be returned.
* @return The dim constraint. Never null.
*/
public DimConstraint getDimConstraint(boolean isHor)
{
return isHor ? hor : ver;
}
/** Returns the absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
* affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
* to adjust the edges relative to the old value. May be null and elements may be null.
* null value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
* and x2 will just absolutely positions the component.
*
* Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of this property slightly.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value as a new array, free to modify.
*/
public UnitValue[] getPos()
{
return pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
}
/** Sets absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
* affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
* to adjust the edges relative to the old value. May be null and elements may be null.
* null value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
* and x2 will just absolutely positions the component.
*
* Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of this property slightly.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param pos UnitValue[] {x, y, x2, y2}. Must be null or of length 4. Elements can be null.
*/
public void setPos(UnitValue[] pos)
{
this.pos = pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
linkTargets = null;
}
/** Returns if the absolute pos value should be corrections to the component that is in a normal cell. If false
* the value of pos is truly absolute in that it will not affect the grid or have a default bounds in the grid.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
* @see #getPos()
*/
public boolean isBoundsInGrid()
{
return boundsInGrid;
}
/** Sets if the absolute pos value should be corrections to the component that is in a normal cell. If false
* the value of pos is truly absolute in that it will not affect the grid or have a default bounds in the grid.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true for bounds taken from the grid position. false is default.
* @see #setPos(UnitValue[])
*/
void setBoundsInGrid(boolean b)
{
this.boundsInGrid = b;
}
/** Returns the absolute cell position in the grid or -1 if cell positioning is not used.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public int getCellX()
{
return cellX;
}
/** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy.
* If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param x The x-position or -1 to disable cell positioning.
*/
public void setCellX(int x)
{
cellX = x;
}
/** Returns the absolute cell position in the grid or -1 if cell positioning is not used.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public int getCellY()
{
return cellX < 0 ? -1 : cellY;
}
/** Set an absolute cell x-position in the grid. If >= 0 this point points to the absolute cell that this constaint's component should occupy.
* If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param y The y-position or -1 to disable cell positioning.
*/
public void setCellY(int y)
{
if (y < 0)
cellX = -1;
cellY = y < 0 ? 0 : y;
}
/** Sets the docking side. -1 means no docking.
* Valid sides are: north = 0, west = 1, south = 2, east = 3.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current side.
*/
public int getDockSide()
{
return dock;
}
/** Sets the docking side. -1 means no docking.
* Valid sides are: north = 0, west = 1, south = 2, east = 3.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param side -1 or 0-3.
*/
public void setDockSide(int side)
{
if (side < -1 || side > 3)
throw new IllegalArgumentException("Illegal dock side: " + side);
dock = side;
}
/** Returns if this component should have its bounds handled by an external source and not this layout manager.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public boolean isExternal()
{
return external;
}
/** If this boolean is true this component is not handled in any way by the layout manager and the component can have its bounds set by an external
* handler which is normally by the use of some component.setBounds(x, y, width, height) directly (for Swing).
*
* The bounds will not affect the minimum and preferred size of the container.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true means that the bounds are not changed.
*/
public void setExternal(boolean b)
{
this.external = b;
}
/** Returns if the flow in the cell is in the horizontal dimension. Vertical if false. Only the first
* component is a cell can set the flow.
*
* If null the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public Boolean getFlowX()
{
return flowX;
}
/** Sets if the flow in the cell is in the horizontal dimension. Vertical if false. Only the first
* component is a cell can set the flow.
*
* If null the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b Boolean.TRUE means horizontal flow in the cell.
*/
public void setFlowX(Boolean b)
{
this.flowX = b;
}
/** Sets how a component that is hidden (not visible) should be treated by default.
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The mode:
* 0 == Normal. Bounds will be calculated as if the component was visible.
* 1 == If hidden the size will be 0, 0 but the gaps remain.
* 2 == If hidden the size will be 0, 0 and gaps set to zero.
* 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
*/
public int getHideMode()
{
return hideMode;
}
/** Sets how a component that is hidden (not visible) should be treated by default.
* @param mode The mode:
* 0 == Normal. Bounds will be calculated as if the component was visible.
* 1 == If hidden the size will be 0, 0 but the gaps remain.
* 2 == If hidden the size will be 0, 0 and gaps set to zero.
* 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
*/
public void setHideMode(int mode)
{
if (mode < -1 || mode > 3)
throw new IllegalArgumentException("Wrong hideMode: " + mode);
hideMode = mode;
}
/** Returns the id used to reference this component in some constraints.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The id or null. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
* The dot should never be first or last if present.
*/
public String getId()
{
return id;
}
/** Sets the id used to reference this component in some constraints.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param id The id or null. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
* The dot should never be first or last if present.
*/
public void setId(String id)
{
this.id = id;
}
/** Returns the absolute resizing in the last stage of the layout cycle. May be null and elements may be null.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value. null or of length 4.
*/
public UnitValue[] getPadding()
{
return padding != null ? new UnitValue[] {padding[0], padding[1], padding[2], padding[3]} : null;
}
/** Sets the absolute resizing in the last stage of the layout cycle. These values are added to the edges and can thus for
* instance be used to grow or reduce the size or move the component an absolute number of pixels. May be null
* and elements may be null.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param sides top, left, bottom right. Must be null or of length 4.
*/
public void setPadding(UnitValue[] sides)
{
this.padding = sides != null ? new UnitValue[] {sides[0], sides[1], sides[2], sides[3]} : null;
}
/** Returns the visual padding used when laying out this Component. May be null and elements may be null.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value. null or of length 4.
*/
public UnitValue[] getVisualPadding()
{
return visualPadding != null ? new UnitValue[] {visualPadding[0], visualPadding[1], visualPadding[2], visualPadding[3]} : null;
}
/** Sets the visual padding used when laying out this Component.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param sides top, left, bottom right. Must be null or of length 4.
*/
public void setVisualPadding(UnitValue[] sides)
{
this.visualPadding = sides != null ? new UnitValue[] {sides[0], sides[1], sides[2], sides[3]} : null;
}
/** Returns how many cells in the grid that should be skipped before the component that this constraint belongs to.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value. 0 if no skip.
*/
public int getSkip()
{
return skip;
}
/** Sets how many cells in the grid that should be skipped before the component that this constraint belongs to.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells How many cells in the grid that should be skipped before the component that this constraint belongs to
*/
public void setSkip(int cells)
{
this.skip = cells;
}
/** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. 1 is default and
* means that it only spans the current cell. LayoutUtil.INF is used to indicate a span to the end of the column/row.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public int getSpanX()
{
return spanX;
}
/** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. 1 is default and
* means that it only spans the current cell. LayoutUtil.INF is used to indicate a span to the end of the column/row.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells The number of cells to span (i.e. merge).
*/
public void setSpanX(int cells)
{
this.spanX = cells;
}
/** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. 1 is default and
* means that it only spans the current cell. LayoutUtil.INF is used to indicate a span to the end of the column/row.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public int getSpanY()
{
return spanY;
}
/** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. 1 is default and
* means that it only spans the current cell. LayoutUtil.INF is used to indicate a span to the end of the column/row.
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param cells The number of cells to span (i.e. merge).
*/
public void setSpanY(int cells)
{
this.spanY = cells;
}
/** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
* If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
* will take precedence. Push is normally used when the grid has not been defined in the layout.
*
* If multiple components in a column has push weights set the largest one will be used for the column.
* @return The current push value. Default is null.
*/
public Float getPushX()
{
return pushX;
}
/** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
* If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
* will take precedence. Push is normally used when the grid has not been defined in the layout.
*
* If multiple components in a column has push weights set the largest one will be used for the column.
* @param weight The new push value. Default is null.
*/
public void setPushX(Float weight)
{
this.pushX = weight;
}
/** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
* If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
* will take precedence. Push is normally used when the grid has not been defined in the layout.
*
* If multiple components in a row has push weights set the largest one will be used for the row.
* @return The current push value. Default is null.
*/
public Float getPushY()
{
return pushY;
}
/** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
* If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
* will take precedence. Push is normally used when the grid has not been defined in the layout.
*
* If multiple components in a row has push weights set the largest one will be used for the row.
* @param weight The new push value. Default is null.
*/
public void setPushY(Float weight)
{
this.pushY = weight;
}
/** Returns in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
* it is split in two, the next component will also share the same cell. Note that the cell can also span a number of
* cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
* set to a very high value to make all components in the same row/column share the same cell (e.g. LayoutUtil.INF).
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public int getSplit()
{
return split;
}
/** Sets in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
* it is split in two, the next component will also share the same cell. Note that the cell can also span a number of
* cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
* set to a very high value to make all components in the same row/column share the same cell (e.g. LayoutUtil.INF).
*
* Note that only the first component will be checked for this property.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param parts The number of parts (i.e. component slots) the cell should be divided into.
*/
public void setSplit(int parts)
{
this.split = parts;
}
/** Tags the component with metadata. Currently only used to tag buttons with for instance "cancel" or "ok" to make them
* show up in the correct order depending on platform. See {@link PlatformDefaults#setButtonOrder(String)} for information.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value. May be null.
*/
public String getTag()
{
return tag;
}
/** Optional tag that gives more context to this constraint's component. It is for instance used to tag buttons in a
* button bar with the button type such as "ok", "help" or "cancel".
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param tag The new tag. May be null.
*/
public void setTag(String tag)
{
this.tag = tag;
}
/** Returns if the flow should wrap to the next line/column after the component that this constraint belongs to.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public boolean isWrap()
{
return wrap != null;
}
/** Sets if the flow should wrap to the next line/column after the component that this constraint belongs to.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true means wrap after.
*/
public void setWrap(boolean b)
{
wrap = b ? (wrap == null ? DEF_GAP : wrap) : null;
}
/** Returns the wrap size if it is a custom size. If wrap was set to true with {@link #setWrap(boolean)} then this method will
* return null since that means that the gap size should be the default one as defined in the rows spec.
* @return The custom gap size. NOTE! Will return null for both no wrap and default wrap.
* @see #isWrap()
* @see #setWrap(boolean)
* @since 2.4.2
*/
public BoundSize getWrapGapSize()
{
return wrap == DEF_GAP ? null : wrap;
}
/** Set the wrap size and turns wrap on if != null.
* @param s The custom gap size. NOTE! null will not turn on or off wrap, it will only set the wrap gap size to "default".
* A non-null value will turn on wrap though.
* @see #isWrap()
* @see #setWrap(boolean)
* @since 2.4.2
*/
public void setWrapGapSize(BoundSize s)
{
wrap = s == null ? (wrap != null ? DEF_GAP : null) : s;
}
/** Returns if the flow should wrap to the next line/column before the component that this constraint belongs to.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current value.
*/
public boolean isNewline()
{
return newline != null;
}
/** Sets if the flow should wrap to the next line/column before the component that this constraint belongs to.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true means wrap before.
*/
public void setNewline(boolean b)
{
newline = b ? (newline == null ? DEF_GAP : newline) : null;
}
/** Returns the newline size if it is a custom size. If newline was set to true with {@link #setNewline(boolean)} then this method will
* return null since that means that the gap size should be the default one as defined in the rows spec.
* @return The custom gap size. NOTE! Will return null for both no newline and default newline.
* @see #isNewline()
* @see #setNewline(boolean)
* @since 2.4.2
*/
public BoundSize getNewlineGapSize()
{
return newline == DEF_GAP ? null : newline;
}
/** Set the newline size and turns newline on if != null.
* @param s The custom gap size. NOTE! null will not turn on or off newline, it will only set the newline gap size to "default".
* A non-null value will turn on newline though.
* @see #isNewline()
* @see #setNewline(boolean)
* @since 2.4.2
*/
public void setNewlineGapSize(BoundSize s)
{
newline = s == null ? (newline != null ? DEF_GAP : null) : s;
}
/** Returns the animation spec. Default is a spec where animation is off (prio 0).
* @return Never null.
*/
public AnimSpec getAnimSpec()
{
return animSpec;
}
// ************************************************
// Persistence Delegate and Serializable combined.
// ************************************************
private Object readResolve() throws ObjectStreamException
{
return LayoutUtil.getSerializedObject(this);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
}
@Override
public void writeExternal(ObjectOutput out) throws IOException
{
if (getClass() == CC.class)
LayoutUtil.writeAsXML(out, this);
}
} miglayout-5.1/core/src/main/java/net/miginfocom/layout/ComponentWrapper.java 0000775 0000000 0000000 00000035100 13241015632 0027354 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A class that wraps the important parts of a Component.
*
* NOTE!.equals() and .hashcode() should be forwarded to the wrapped component. E.g.
*
* public int hashCode()
{
return getComponent().hashCode();
}
public final boolean equals(Object o)
{
if (o instanceof ComponentWrapper == false)
return false;
return getComponent().equals(((ComponentWrapper) o).getComponent());
}
*
*/
public interface ComponentWrapper
{
static final int TYPE_UNSET = -1;
public static final int TYPE_UNKNOWN = 0;
public static final int TYPE_CONTAINER = 1;
public static final int TYPE_LABEL = 2;
public static final int TYPE_TEXT_FIELD = 3;
public static final int TYPE_TEXT_AREA = 4;
public static final int TYPE_BUTTON = 5;
public static final int TYPE_LIST = 6;
public static final int TYPE_TABLE = 7;
public static final int TYPE_SCROLL_PANE = 8;
public static final int TYPE_IMAGE = 9;
public static final int TYPE_PANEL = 10;
public static final int TYPE_COMBO_BOX = 11;
public static final int TYPE_SLIDER = 12;
public static final int TYPE_SPINNER = 13;
public static final int TYPE_PROGRESS_BAR = 14;
public static final int TYPE_TREE = 15;
public static final int TYPE_CHECK_BOX = 16;
public static final int TYPE_SCROLL_BAR = 17;
public static final int TYPE_SEPARATOR = 18;
public static final int TYPE_TABBED_PANE = 19;
/** Returns the actual object that this wrapper is aggregating. This might be needed for getting
* information about the object that the wrapper interface does not provide.
*
* If this is a container the container should be returned instead.
* @return The actual object that this wrapper is aggregating. Not null.
*/
public abstract Object getComponent();
/** Returns the current x coordinate for this component.
* @return The current x coordinate for this component.
*/
public abstract int getX();
/** Returns the current y coordinate for this component.
* @return The current y coordinate for this component.
*/
public abstract int getY();
/** Returns the current width for this component.
* @return The current width for this component.
*/
public abstract int getWidth();
/** Returns the current height for this component.
* @return The current height for this component.
*/
public abstract int getHeight();
/** Returns the screen x-coordinate for the upper left coordinate of the component layout-able bounds.
* @return The screen x-coordinate for the upper left coordinate of the component layout-able bounds.
*/
public abstract int getScreenLocationX();
/** Returns the screen y-coordinate for the upper left coordinate of the component layout-able bounds.
* @return The screen y-coordinate for the upper left coordinate of the component layout-able bounds.
*/
public abstract int getScreenLocationY();
/** Returns the minimum width of the component.
* @param hHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The minimum width of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getMinimumWidth(int hHint);
/** Returns the minimum height of the component.
* @param wHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The minimum height of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getMinimumHeight(int wHint);
/** Returns the preferred width of the component.
* @param hHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The preferred width of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getPreferredWidth(int hHint);
/** Returns the preferred height of the component.
* @param wHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The preferred height of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getPreferredHeight(int wHint);
/** Returns the maximum width of the component.
* @param hHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The maximum width of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getMaximumWidth(int hHint);
/** Returns the maximum height of the component.
* @param wHint The Size hint for the other dimension. An implementation can use this value or the
* current size for the widget in this dimension, or a combination of both, to calculate the correct size.
* Use -1 to denote that there is no hint. This corresponds with SWT.DEFAULT.
* @return The maximum height of the component.
* @since 3.5. Added the hint as a parameter knowing that a correction and recompilation is necessary for
* any implementing classes. This change was worth it though.
*/
public abstract int getMaximumHeight(int wHint);
/** Sets the component's bounds.
* @param x The x coordinate.
* @param y The y coordinate.
* @param width The width.
* @param height The height.
*/
public abstract void setBounds(int x, int y, int width, int height);
/** Returns if the component's visibility is set to true. This should not return if the component is
* actually visible, but if the visibility is set to true or not.
* @return true means visible.
*/
public abstract boolean isVisible();
/** Returns the baseline for the component given the suggested height.
* @param width The width to calculate for if other than the current. If -1 the current size should be used.
* @param height The height to calculate for if other than the current. If -1 the current size should be used.
* @return The baseline from the top or -1 if not applicable.
*/
public abstract int getBaseline(int width, int height);
/** Returns if the component has a baseline and if it can be retrieved. Should for instance return
* false for Swing before mustang.
* @return If the component has a baseline and if it can be retrieved.
*/
public abstract boolean hasBaseline();
/** Returns the container for this component.
* @return The container for this component. Will return null if the component has no parent.
*/
public abstract ContainerWrapper getParent();
/** Returns the pixel unit factor for the horizontal or vertical dimension.
*
* The factor is 1 for both dimensions on the normal font in a JPanel on Windows. The factor should increase with a bigger "X".
*
* @param isHor If it is the horizontal factor that should be returned.
* @return The factor.
*/
public abstract float getPixelUnitFactor(boolean isHor);
/** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
* screen if the component is not visible.
*
* If headless mode {@link net.miginfocom.layout.PlatformDefaults#getDefaultDPI} will be returned.
* @return The DPI.
*/
public abstract int getHorizontalScreenDPI();
/** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
* screen if the component is not visible.
*
* If headless mode {@link net.miginfocom.layout.PlatformDefaults#getDefaultDPI} will be returned.
* @return The DPI.
*/
public abstract int getVerticalScreenDPI();
/** Returns the pixel size of the screen that the component is currently in or for the default
* screen if the component is not visible or null.
*
* If in headless mode 1024 is returned.
* @return The screen size. E.g. 1280.
*/
public abstract int getScreenWidth();
/** Returns the pixel size of the screen that the component is currently in or for the default
* screen if the component is not visible or null.
*
* If in headless mode 768 is returned.
* @return The screen size. E.g. 1024.
*/
public abstract int getScreenHeight();
/** Returns a String id that can be used to reference the component in link constraints. This value should
* return the default id for the component. The id can be set for a component in the constraints and if
* so the value returned by this method will never be used. If there are no sensible id for the component
* null should be returned.
*
* For instance the Swing implementation returns the string returned from Component.getName().
* @return The string link id or null.
*/
public abstract String getLinkId();
/** Returns a hash code that should be reasonably different for anything that might change the layout. This value is used to
* know if the component layout needs to clear any caches.
* @return A hash code that should be reasonably different for anything that might change the layout. Returns -1 if the widget is
* disposed.
*/
public abstract int getLayoutHashCode();
/** Returns the padding on a component by component basis. This method can be overridden to return padding to compensate for example for
* borders that have shadows or where the outer most pixel is not the visual "edge" to align to.
*
* Default implementation returns null for all components except for Windows XP's JTabbedPane which will return new Insets(0, 0, 2, 2).
*
* NOTE! To reduce generated garbage the returned padding should never be changed so that the same insets can be returned many times.
* @return null if no padding. NOTE! To reduce generated garbage the returned padding should never be changed so that
* the same insets can be returned many times. [top, left, bottom, right]
*/
public int[] getVisualPadding();
/** Paints component outline to indicate where it is.
* @param showVisualPadding If the visual padding should be shown in the debug drawing.
*/
public abstract void paintDebugOutline(boolean showVisualPadding);
/** Returns the type of component that this wrapper is wrapping.
*
* This method can be invoked often so the result should be cached.
*
* @param disregardScrollPane Is true any wrapping scroll pane should be disregarded and the type
* of the scrolled component should be returned.
* @return The type of component that this wrapper is wrapping. E.g. {@link #TYPE_LABEL}.
*/
public abstract int getComponentType(boolean disregardScrollPane);
/** Returns in what way the min/pref/max sizes relates to it's height or width for the current settings of the component (like wrapText).
* If the min/pref/max height depends on it's width return {@link net.miginfocom.layout.LayoutUtil#HORIZONTAL}
* If the min/pref/max width depends on it's height (not common) return {@link net.miginfocom.layout.LayoutUtil#VERTICAL}
* If there is no connection between the preferred min/pref/max and the size of the component return -1.
* @since 5.0
*/
public abstract int getContentBias();
} miglayout-5.1/core/src/main/java/net/miginfocom/layout/ConstraintParser.java 0000775 0000000 0000000 00000143416 13241015632 0027364 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** Parses string constraints.
*/
public final class ConstraintParser
{
private ConstraintParser()
{
}
/** Parses the layout constraints and stores the parsed values in the transient (cache) member variables.
* @param s The String to parse. Should not be null and must be lower case and trimmed.
* @throws RuntimeException if the constraint was not valid.
* @return The parsed constraint. Never null.
*/
public static LC parseLayoutConstraint(String s)
{
LC lc = new LC();
if (s.isEmpty())
return lc;
String[] parts = toTrimmedTokens(s, ',');
// First check for "ltr" or "rtl" since that will affect the interpretation of the other constraints.
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
if (part == null)
continue;
int len = part.length();
if (len == 3 || len == 11) { // Optimization
if (part.equals("ltr") || part.equals("rtl") || part.equals("lefttoright") || part.equals("righttoleft")) {
lc.setLeftToRight(part.charAt(0) == 'l' ? Boolean.TRUE : Boolean.FALSE);
parts[i] = null; // So we will not try to interpret it again
}
if (part.equals("ttb") || part.equals("btt") || part.equals("toptobottom") || part.equals("bottomtotop")) {
lc.setTopToBottom(part.charAt(0) == 't');
parts[i] = null; // So we will not try to interpret it again
}
}
}
for (String part : parts) {
if (part == null || part.length() == 0)
continue;
try {
int ix = -1;
char c = part.charAt(0);
if (c == 'w' || c == 'h') {
ix = startsWithLenient(part, "wrap", -1, true);
if (ix > -1) {
String num = part.substring(ix).trim();
lc.setWrapAfter(num.length() != 0 ? Integer.parseInt(num) : 0);
continue;
}
boolean isHor = c == 'w';
if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
String sz = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
lc.setWidth(parseBoundSize(sz, false, true));
continue;
}
if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
lc.setHeight(parseBoundSize(uvStr, false, false));
continue;
}
if (part.length() > 5) {
String sz = part.substring(5).trim();
if (part.startsWith("wmin ")) {
lc.minWidth(sz);
continue;
} else if (part.startsWith("wmax ")) {
lc.maxWidth(sz);
continue;
} else if (part.startsWith("hmin ")) {
lc.minHeight(sz);
continue;
} else if (part.startsWith("hmax ")) {
lc.maxHeight(sz);
continue;
}
}
if (part.startsWith("hidemode ")) {
lc.setHideMode(Integer.parseInt(part.substring(9)));
continue;
}
}
if (c == 'g') {
if (part.startsWith("gapx ")) {
lc.setGridGapX(parseBoundSize(part.substring(5).trim(), true, true));
continue;
}
if (part.startsWith("gapy ")) {
lc.setGridGapY(parseBoundSize(part.substring(5).trim(), true, false));
continue;
}
if (part.startsWith("gap ")) {
String[] gaps = toTrimmedTokens(part.substring(4).trim(), ' ');
lc.setGridGapX(parseBoundSize(gaps[0], true, true));
lc.setGridGapY(gaps.length > 1 ? parseBoundSize(gaps[1], true, false) : lc.getGridGapX());
continue;
}
}
if (c == 'd') {
ix = startsWithLenient(part, "debug", 5, true);
if (ix > -1) {
String millis = part.substring(ix).trim();
lc.setDebugMillis(millis.length() > 0 ? Integer.parseInt(millis) : 1000);
continue;
}
}
if (c == 'n') {
if (part.equals("nogrid")) {
lc.setNoGrid(true);
continue;
}
if (part.equals("nocache")) {
lc.setNoCache(true);
continue;
}
if (part.equals("novisualpadding")) {
lc.setVisualPadding(false);
continue;
}
}
if (c == 'f') {
if (part.equals("fill") || part.equals("fillx") || part.equals("filly")) {
lc.setFillX(part.length() == 4 || part.charAt(4) == 'x');
lc.setFillY(part.length() == 4 || part.charAt(4) == 'y');
continue;
}
if (part.equals("flowy")) {
lc.setFlowX(false);
continue;
}
if (part.equals("flowx")) {
lc.setFlowX(true); // This is the default but added for consistency
continue;
}
}
if (c == 'i') {
ix = startsWithLenient(part, "insets", 3, true);
if (ix > -1) {
String insStr = part.substring(ix).trim();
UnitValue[] ins = parseInsets(insStr, true);
LayoutUtil.putCCString(ins, insStr);
lc.setInsets(ins);
continue;
}
}
if (c == 'a') {
ix = startsWithLenient(part, new String[]{"aligny", "ay"}, new int[]{6, 2}, true);
if (ix > -1) {
UnitValue align = parseUnitValueOrAlign(part.substring(ix).trim(), false, null);
if (align == UnitValue.BASELINE_IDENTITY)
throw new IllegalArgumentException("'baseline' can not be used to align the whole component group.");
lc.setAlignY(align);
continue;
}
ix = startsWithLenient(part, new String[]{"alignx", "ax"}, new int[]{6, 2}, true);
if (ix > -1) {
lc.setAlignX(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
continue;
}
ix = startsWithLenient(part, "align", 2, true);
if (ix > -1) {
String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
lc.setAlignX(parseUnitValueOrAlign(gaps[0], true, null));
if (gaps.length > 1) {
UnitValue align = parseUnitValueOrAlign(gaps[1], false, null);
if (align == UnitValue.BASELINE_IDENTITY)
throw new IllegalArgumentException("'baseline' can not be used to align the whole component group.");
lc.setAlignY(align);
}
continue;
}
}
if (c == 'p') {
if (part.startsWith("packalign ")) {
String[] packs = toTrimmedTokens(part.substring(10).trim(), ' ');
lc.setPackWidthAlign(packs[0].length() > 0 ? Float.parseFloat(packs[0]) : 0.5f);
if (packs.length > 1)
lc.setPackHeightAlign(Float.parseFloat(packs[1]));
continue;
}
if (part.startsWith("pack ") || part.equals("pack")) {
String ps = part.substring(4).trim();
String[] packs = toTrimmedTokens(ps.length() > 0 ? ps : "pref pref", ' ');
lc.setPackWidth(parseBoundSize(packs[0], false, true));
if (packs.length > 1)
lc.setPackHeight(parseBoundSize(packs[1], false, false));
continue;
}
}
if (lc.getAlignX() == null) {
UnitValue alignX = parseAlignKeywords(part, true);
if (alignX != null) {
lc.setAlignX(alignX);
continue;
}
}
UnitValue alignY = parseAlignKeywords(part, false);
if (alignY != null) {
lc.setAlignY(alignY);
continue;
}
throw new IllegalArgumentException("Unknown Constraint: '" + part + "'\n");
} catch (Exception ex) {
throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
}
}
// lc = (LC) serializeTest(lc);
return lc;
}
/** Parses the column or rows constraints. They normally looks something like "[min:pref]rel[10px][]".
* @param s The string to parse. Not null.
* @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
* @throws RuntimeException if the constraint was not valid.
*/
public static AC parseRowConstraints(String s)
{
return parseAxisConstraint(s, false);
}
/** Parses the column or rows constraints. They normally looks something like "[min:pref]rel[10px][]".
* @param s The string to parse. Not null.
* @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
* @throws RuntimeException if the constraint was not valid.
*/
public static AC parseColumnConstraints(String s)
{
return parseAxisConstraint(s, true);
}
/** Parses the column or rows constraints. They normally looks something like "[min:pref]rel[10px][]".
* @param s The string to parse. Not null.
* @param isCols If this for columns rather than rows.
* @return An array of {@link DimConstraint}s that is as many are there exist "[...]" sections in the string that is parsed.
* @throws RuntimeException if the constraint was not valid.
*/
private static AC parseAxisConstraint(String s, boolean isCols)
{
s = s.trim();
if (s.length() == 0)
return new AC(); // Short circuit for performance.
s = s.toLowerCase();
ArrayList parts = getRowColAndGapsTrimmed(s);
BoundSize[] gaps = new BoundSize[(parts.size() >> 1) + 1];
for (int i = 0, iSz = parts.size(), gIx = 0; i < iSz; i += 2, gIx++)
gaps[gIx] = parseBoundSize(parts.get(i), true, isCols);
DimConstraint[] colSpecs = new DimConstraint[parts.size() >> 1];
for (int i = 0, gIx = 0; i < colSpecs.length; i++, gIx++) {
if (gIx >= gaps.length - 1)
gIx = gaps.length - 2;
colSpecs[i] = parseDimConstraint(parts.get((i << 1) + 1), gaps[gIx], gaps[gIx + 1], isCols);
}
AC ac = new AC();
ac.setConstaints(colSpecs);
// ac = (AC) serializeTest(ac);
return ac;
}
/** Parses a single column or row constraint.
* @param s The single constraint to parse. May look something like "min:pref,fill,grow". Should not be null and must
* be lower case and trimmed.
* @param gapBefore The default gap "before" the column/row constraint. Can be overridden with a "gap" section within s.
* @param gapAfter The default gap "after" the column/row constraint. Can be overridden with a "gap" section within s.
* @param isCols If the constraints are column constraints rather than row constraints.
* @return A single constraint. Never null.
* @throws RuntimeException if the constraint was not valid.
*/
private static DimConstraint parseDimConstraint(String s, BoundSize gapBefore, BoundSize gapAfter, boolean isCols)
{
DimConstraint dimConstraint = new DimConstraint();
// Default values.
dimConstraint.setGapBefore(gapBefore);
dimConstraint.setGapAfter(gapAfter);
String[] parts = toTrimmedTokens(s, ',');
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
try {
if (part.length() == 0)
continue;
if (part.equals("fill")) {
dimConstraint.setFill(true);
// dimConstraint.setAlign(null); // Can not have both fill and alignment (changed for 3.5 since it can have "growy 0")
continue;
}
if (part.equals("nogrid")) {
dimConstraint.setNoGrid(true);
continue;
}
int ix = -1;
char c = part.charAt(0);
if (c == 's') {
ix = startsWithLenient(part, new String[] {"sizegroup", "sg"}, new int[] {5, 2}, true);
if (ix > -1) {
dimConstraint.setSizeGroup(part.substring(ix).trim());
continue;
}
ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
if (ix > -1) {
dimConstraint.setShrinkPriority(Integer.parseInt(part.substring(ix).trim()));
continue;
}
ix = startsWithLenient(part, "shrink", 6, true);
if (ix > -1) {
dimConstraint.setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
}
if (c == 'g') {
ix = startsWithLenient(part, new String[] {"growpriority", "gp"}, new int[] {5, 2}, true);
if (ix > -1) {
dimConstraint.setGrowPriority(Integer.parseInt(part.substring(ix).trim()));
continue;
}
ix = startsWithLenient(part, "grow", 4, true);
if (ix > -1) {
dimConstraint.setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
}
if (c == 'a') {
ix = startsWithLenient(part, "align", 2, true);
if (ix > -1) {
// if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set. (changed for 3.5 since it can have "growy 0")
dimConstraint.setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), isCols, null));
continue;
}
}
UnitValue align = parseAlignKeywords(part, isCols);
if (align != null) {
// if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set. (changed for 3.5 since it can have "growy 0")
dimConstraint.setAlign(align);
continue;
}
// Only min:pref:max still left that is ok
dimConstraint.setSize(parseBoundSize(part, false, isCols));
} catch (Exception ex) {
throw new IllegalArgumentException("Illegal constraint: '" + part + "'\n" + ex.getMessage());
}
}
return dimConstraint;
}
/** Parses all component constraints and stores the parsed values in the transient (cache) member variables.
* @param constrMap The constraints as Strings. Strings must be lower case and trimmed
* @return The parsed constraints. Never null.
*/
public static Map parseComponentConstraints(Map constrMap)
{
HashMap flowConstrMap = new HashMap();
for (Iterator> it = constrMap.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = it.next();
flowConstrMap.put(entry.getKey(), parseComponentConstraint(entry.getValue()));
}
return flowConstrMap;
}
/** Parses one component constraint and returns the parsed value.
* @param s The string to parse. Must be lower case and trimmed.
* @throws RuntimeException if the constraint was not valid.
* @return The parsed constraint. Never null.
*/
public static CC parseComponentConstraint(String s)
{
CC cc = new CC();
if (s == null || s.isEmpty())
return cc;
String[] parts = toTrimmedTokens(s, ',');
for (String part : parts) {
try {
if (part.length() == 0)
continue;
int ix = -1;
char c = part.charAt(0);
if (c == 'n') {
if (part.equals("north")) {
cc.setDockSide(0);
continue;
}
if (part.equals("newline")) {
cc.setNewline(true);
continue;
}
if (part.startsWith("newline ")) {
String gapSz = part.substring(7).trim();
cc.setNewlineGapSize(parseBoundSize(gapSz, true, true));
continue;
}
}
if (c == 'f' && (part.equals("flowy") || part.equals("flowx"))) {
cc.setFlowX(part.charAt(4) == 'x' ? Boolean.TRUE : Boolean.FALSE);
continue;
}
if (c == 's') {
ix = startsWithLenient(part, "skip", 4, true);
if (ix > -1) {
String num = part.substring(ix).trim();
cc.setSkip(num.length() != 0 ? Integer.parseInt(num) : 1);
continue;
}
ix = startsWithLenient(part, "split", 5, true);
if (ix > -1) {
String split = part.substring(ix).trim();
cc.setSplit(split.length() > 0 ? Integer.parseInt(split) : LayoutUtil.INF);
continue;
}
if (part.equals("south")) {
cc.setDockSide(2);
continue;
}
ix = startsWithLenient(part, new String[]{"spany", "sy"}, new int[]{5, 2}, true);
if (ix > -1) {
cc.setSpanY(parseSpan(part.substring(ix).trim()));
continue;
}
ix = startsWithLenient(part, new String[]{"spanx", "sx"}, new int[]{5, 2}, true);
if (ix > -1) {
cc.setSpanX(parseSpan(part.substring(ix).trim()));
continue;
}
ix = startsWithLenient(part, "span", 4, true);
if (ix > -1) {
String[] spans = toTrimmedTokens(part.substring(ix).trim(), ' ');
cc.setSpanX(spans[0].length() > 0 ? Integer.parseInt(spans[0]) : LayoutUtil.INF);
cc.setSpanY(spans.length > 1 ? Integer.parseInt(spans[1]) : 1);
continue;
}
ix = startsWithLenient(part, "shrinkx", 7, true);
if (ix > -1) {
cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "shrinky", 7, true);
if (ix > -1) {
cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "shrink", 6, false);
if (ix > -1) {
String[] shrinks = toTrimmedTokens(part.substring(ix).trim(), ' ');
cc.getHorizontal().setShrink(parseFloat(shrinks[0], ResizeConstraint.WEIGHT_100));
if (shrinks.length > 1)
cc.getVertical().setShrink(parseFloat(shrinks[1], ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, new String[]{"shrinkprio", "shp"}, new int[]{10, 3}, true);
if (ix > -1) {
String sp = part.substring(ix).trim();
if (sp.startsWith("x") || sp.startsWith("y")) { // To handle "gpx", "gpy", "shrinkpriorityx", shrinkpriorityy"
(sp.startsWith("x") ? cc.getHorizontal() : cc.getVertical()).setShrinkPriority(Integer.parseInt(sp.substring(2)));
} else {
String[] shrinks = toTrimmedTokens(sp, ' ');
cc.getHorizontal().setShrinkPriority(Integer.parseInt(shrinks[0]));
if (shrinks.length > 1)
cc.getVertical().setShrinkPriority(Integer.parseInt(shrinks[1]));
}
continue;
}
ix = startsWithLenient(part, new String[]{"sizegroupx", "sizegroupy", "sgx", "sgy"}, new int[]{9, 9, 2, 2}, true);
if (ix > -1) {
String sg = part.substring(ix).trim();
char lc = part.charAt(ix - 1);
if (lc != 'y')
cc.getHorizontal().setSizeGroup(sg);
if (lc != 'x')
cc.getVertical().setSizeGroup(sg);
continue;
}
}
if (c == 'g') {
ix = startsWithLenient(part, "growx", 5, true);
if (ix > -1) {
cc.getHorizontal().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "growy", 5, true);
if (ix > -1) {
cc.getVertical().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "grow", 4, false);
if (ix > -1) {
String[] grows = toTrimmedTokens(part.substring(ix).trim(), ' ');
cc.getHorizontal().setGrow(parseFloat(grows[0], ResizeConstraint.WEIGHT_100));
cc.getVertical().setGrow(parseFloat(grows.length > 1 ? grows[1] : "", ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, new String[]{"growprio", "gp"}, new int[]{8, 2}, true);
if (ix > -1) {
String gp = part.substring(ix).trim();
char c0 = gp.length() > 0 ? gp.charAt(0) : ' ';
if (c0 == 'x' || c0 == 'y') { // To handle "gpx", "gpy", "growpriorityx", growpriorityy"
(c0 == 'x' ? cc.getHorizontal() : cc.getVertical()).setGrowPriority(Integer.parseInt(gp.substring(2)));
} else {
String[] grows = toTrimmedTokens(gp, ' ');
cc.getHorizontal().setGrowPriority(Integer.parseInt(grows[0]));
if (grows.length > 1)
cc.getVertical().setGrowPriority(Integer.parseInt(grows[1]));
}
continue;
}
if (part.startsWith("gap")) {
BoundSize[] gaps = parseGaps(part); // Changes order!!
if (gaps[0] != null)
cc.getVertical().setGapBefore(gaps[0]);
if (gaps[1] != null)
cc.getHorizontal().setGapBefore(gaps[1]);
if (gaps[2] != null)
cc.getVertical().setGapAfter(gaps[2]);
if (gaps[3] != null)
cc.getHorizontal().setGapAfter(gaps[3]);
continue;
}
}
if (c == 'a') {
ix = startsWithLenient(part, new String[]{"aligny", "ay"}, new int[]{6, 2}, true);
if (ix > -1) {
cc.getVertical().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
continue;
}
ix = startsWithLenient(part, new String[]{"alignx", "ax"}, new int[]{6, 2}, true);
if (ix > -1) {
cc.getHorizontal().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
continue;
}
ix = startsWithLenient(part, "align", 2, true);
if (ix > -1) {
String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
cc.getHorizontal().setAlign(parseUnitValueOrAlign(gaps[0], true, null));
if (gaps.length > 1)
cc.getVertical().setAlign(parseUnitValueOrAlign(gaps[1], false, null));
continue;
}
}
if ((c == 'x' || c == 'y') && part.length() > 2) {
char c2 = part.charAt(1);
if (c2 == ' ' || (c2 == '2' && part.charAt(2) == ' ')) {
if (cc.getPos() == null) {
cc.setPos(new UnitValue[4]);
} else if (cc.isBoundsInGrid() == false) {
throw new IllegalArgumentException("Cannot combine 'position' with 'x/y/x2/y2' keywords.");
}
int edge = (c == 'x' ? 0 : 1) + (c2 == '2' ? 2 : 0);
UnitValue[] pos = cc.getPos();
pos[edge] = parseUnitValue(part.substring(2).trim(), null, c == 'x');
cc.setPos(pos);
cc.setBoundsInGrid(true);
continue;
}
}
if (c == 'c') {
ix = startsWithLenient(part, "cell", 4, true);
if (ix > -1) {
String[] grs = toTrimmedTokens(part.substring(ix).trim(), ' ');
if (grs.length < 2)
throw new IllegalArgumentException("At least two integers must follow " + part);
cc.setCellX(Integer.parseInt(grs[0]));
cc.setCellY(Integer.parseInt(grs[1]));
if (grs.length > 2)
cc.setSpanX(Integer.parseInt(grs[2]));
if (grs.length > 3)
cc.setSpanY(Integer.parseInt(grs[3]));
continue;
}
}
if (c == 'p') {
ix = startsWithLenient(part, "pos", 3, true);
if (ix > -1) {
if (cc.getPos() != null && cc.isBoundsInGrid())
throw new IllegalArgumentException("Can not combine 'pos' with 'x/y/x2/y2' keywords.");
String[] pos = toTrimmedTokens(part.substring(ix).trim(), ' ');
UnitValue[] bounds = new UnitValue[4];
for (int j = 0; j < pos.length; j++)
bounds[j] = parseUnitValue(pos[j], null, j % 2 == 0);
if (bounds[0] == null && bounds[2] == null || bounds[1] == null && bounds[3] == null)
throw new IllegalArgumentException("Both x and x2 or y and y2 can not be null!");
cc.setPos(bounds);
cc.setBoundsInGrid(false);
continue;
}
ix = startsWithLenient(part, "pad", 3, true);
if (ix > -1) {
UnitValue[] p = parseInsets(part.substring(ix).trim(), false);
cc.setPadding(new UnitValue[]{
p[0],
p.length > 1 ? p[1] : null,
p.length > 2 ? p[2] : null,
p.length > 3 ? p[3] : null});
continue;
}
ix = startsWithLenient(part, "pushx", 5, true);
if (ix > -1) {
cc.setPushX(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "pushy", 5, true);
if (ix > -1) {
cc.setPushY(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
continue;
}
ix = startsWithLenient(part, "push", 4, false);
if (ix > -1) {
String[] pushs = toTrimmedTokens(part.substring(ix).trim(), ' ');
cc.setPushX(parseFloat(pushs[0], ResizeConstraint.WEIGHT_100));
cc.setPushY(parseFloat(pushs.length > 1 ? pushs[1] : "", ResizeConstraint.WEIGHT_100));
continue;
}
}
if (c == 't') {
ix = startsWithLenient(part, "tag", 3, true);
if (ix > -1) {
cc.setTag(part.substring(ix).trim());
continue;
}
}
if (c == 'w' || c == 'h') {
if (part.equals("wrap")) {
cc.setWrap(true);
continue;
}
if (part.startsWith("wrap ")) {
String gapSz = part.substring(5).trim();
cc.setWrapGapSize(parseBoundSize(gapSz, true, true));
continue;
}
boolean isHor = c == 'w';
if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
cc.getHorizontal().setSize(parseBoundSize(uvStr, false, true));
continue;
}
if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
cc.getVertical().setSize(parseBoundSize(uvStr, false, false));
continue;
}
if (part.startsWith("wmin ") || part.startsWith("wmax ") || part.startsWith("hmin ") || part.startsWith("hmax ")) {
String uvStr = part.substring(5).trim();
if (uvStr.length() > 0) {
UnitValue uv = parseUnitValue(uvStr, null, isHor);
boolean isMin = part.charAt(3) == 'n';
DimConstraint dc = isHor ? cc.getHorizontal() : cc.getVertical();
dc.setSize(new BoundSize(
isMin ? uv : dc.getSize().getMin(),
dc.getSize().getPreferred(),
isMin ? (dc.getSize().getMax()) : uv,
uvStr
));
continue;
}
}
if (part.equals("west")) {
cc.setDockSide(1);
continue;
}
if (part.startsWith("hidemode ")) {
cc.setHideMode(Integer.parseInt(part.substring(9)));
continue;
}
}
if (c == 'i' && part.startsWith("id ")) {
cc.setId(part.substring(3).trim());
int dIx = cc.getId().indexOf('.');
if (dIx == 0 || dIx == cc.getId().length() - 1)
throw new IllegalArgumentException("Dot must not be first or last!");
continue;
}
if (c == 'e') {
if (part.equals("east")) {
cc.setDockSide(3);
continue;
}
if (part.equals("external")) {
cc.setExternal(true);
continue;
}
ix = startsWithLenient(part, new String[]{"endgroupx", "endgroupy", "egx", "egy"}, new int[]{-1, -1, -1, -1}, true);
if (ix > -1) {
String sg = part.substring(ix).trim();
char lc = part.charAt(ix - 1);
DimConstraint dc = (lc == 'x' ? cc.getHorizontal() : cc.getVertical());
dc.setEndGroup(sg);
continue;
}
}
if (c == 'd') {
if (part.equals("dock north")) {
cc.setDockSide(0);
continue;
}
if (part.equals("dock west")) {
cc.setDockSide(1);
continue;
}
if (part.equals("dock south")) {
cc.setDockSide(2);
continue;
}
if (part.equals("dock east")) {
cc.setDockSide(3);
continue;
}
if (part.equals("dock center")) {
cc.getHorizontal().setGrow(100f);
cc.getVertical().setGrow(100f);
cc.setPushX(100f);
cc.setPushY(100f);
continue;
}
}
if (c == 'v') {
ix = startsWithLenient(part, new String[] {"visualpadding", "vp"}, new int[] {3, 2}, true);
if (ix > -1) {
UnitValue[] p = parseInsets(part.substring(ix).trim(), false);
cc.setVisualPadding(new UnitValue[] {
p[0],
p.length > 1 ? p[1] : null,
p.length > 2 ? p[2] : null,
p.length > 3 ? p[3] : null});
continue;
}
}
UnitValue horAlign = parseAlignKeywords(part, true);
if (horAlign != null) {
cc.getHorizontal().setAlign(horAlign);
continue;
}
UnitValue verAlign = parseAlignKeywords(part, false);
if (verAlign != null) {
cc.getVertical().setAlign(verAlign);
continue;
}
throw new IllegalArgumentException("Unknown keyword.");
} catch (Exception ex) {
throw new IllegalArgumentException("Error parsing Constraint: '" + part + "'", ex);
}
}
// cc = (CC) serializeTest(cc);
return cc;
}
/** Parses insets which consists of 1-4 UnitValues.
* @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
* @param acceptPanel If "panel" and "dialog" should be accepted. They are used to access platform defaults.
* @return An array of length 4 with the parsed insets.
* @throws IllegalArgumentException if the parsing could not be done.
*/
public static UnitValue[] parseInsets(String s, boolean acceptPanel)
{
if (s.length() == 0 || s.equals("dialog") || s.equals("panel")) {
if (acceptPanel == false)
throw new IllegalArgumentException("Insets now allowed: " + s + "\n");
boolean isPanel = s.startsWith("p");
UnitValue[] ins = new UnitValue[4];
for (int j = 0; j < 4; j++)
ins[j] = isPanel ? PlatformDefaults.getPanelInsets(j) : PlatformDefaults.getDialogInsets(j);
return ins;
} else {
String[] insS = toTrimmedTokens(s, ' ');
UnitValue[] ins = new UnitValue[4];
for (int j = 0; j < 4; j++) {
UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1);
ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j);
}
return ins;
}
}
/** Parses gaps.
* @param s The string that contains gap information. Should start with "gap".
* @return The gaps as specified in s. Indexed: [top,left,bottom,right][min,pref,max] or
* [before,after][min,pref,max] if oneDim is true.
*/
private static BoundSize[] parseGaps(String s)
{
BoundSize[] ret = new BoundSize[4];
int ix = startsWithLenient(s, "gaptop", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[0] = parseBoundSize(s, true, false);
return ret;
}
ix = startsWithLenient(s, "gapleft", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[1] = parseBoundSize(s, true, true);
return ret;
}
ix = startsWithLenient(s, "gapbottom", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[2] = parseBoundSize(s, true, false);
return ret;
}
ix = startsWithLenient(s, "gapright", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[3] = parseBoundSize(s, true, true);
return ret;
}
ix = startsWithLenient(s, "gapbefore", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[1] = parseBoundSize(s, true, true);
return ret;
}
ix = startsWithLenient(s, "gapafter", -1, true);
if (ix > -1) {
s = s.substring(ix).trim();
ret[3] = parseBoundSize(s, true, true);
return ret;
}
ix = startsWithLenient(s, new String[] {"gapx", "gapy"}, null, true);
if (ix > -1) {
boolean x = s.charAt(3) == 'x';
String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
ret[x ? 1 : 0] = parseBoundSize(gaps[0], true, x);
if (gaps.length > 1)
ret[x ? 3 : 2] = parseBoundSize(gaps[1], true, !x);
return ret;
}
ix = startsWithLenient(s, "gap ", 1, true);
if (ix > -1) {
String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
ret[1] = parseBoundSize(gaps[0], true, true); // left
if (gaps.length > 1) {
ret[3] = parseBoundSize(gaps[1], true, false); // right
if (gaps.length > 2) {
ret[0] = parseBoundSize(gaps[2], true, true); // top
if (gaps.length > 3)
ret[2] = parseBoundSize(gaps[3], true, false); // bottom
}
}
return ret;
}
throw new IllegalArgumentException("Unknown Gap part: '" + s + "'");
}
private static int parseSpan(String s)
{
return s.length() > 0 ? Integer.parseInt(s) : LayoutUtil.INF;
}
private static Float parseFloat(String s, Float nullVal)
{
return s.length() > 0 ? new Float(Float.parseFloat(s)) : nullVal;
}
/** Parses a single "min:pref:max" value. May look something like "10px:20lp:30%" or "pref!".
* @param s The string to parse. Not null.
* @param isGap If this bound size is a gap (different empty string handling).
* @param isHor If the size is for the horizontal dimension.
* @return A bound size that may be null if the string was "null", "n" or null.
*/
public static BoundSize parseBoundSize(String s, boolean isGap, boolean isHor)
{
if (s.length() == 0 || s.equals("null") || s.equals("n"))
return null;
String cs = s;
boolean push = false;
if (s.endsWith("push")) {
push = true;
int l = s.length();
s = s.substring(0, l - (s.endsWith(":push") ? 5 : 4));
if (s.length() == 0)
return new BoundSize(null, null, null, true, cs);
}
String[] sizes = toTrimmedTokens(s, ':');
String s0 = sizes[0];
if (sizes.length == 1) {
boolean hasEM = s0.endsWith("!");
if (hasEM)
s0 = s0.substring(0, s0.length() - 1);
UnitValue uv = parseUnitValue(s0, null, isHor);
return new BoundSize(((isGap || hasEM) ? uv : null), uv, (hasEM ? uv : null), push, cs);
} else if (sizes.length == 2) {
return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), null, push, cs);
} else if (sizes.length == 3) {
return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), parseUnitValue(sizes[2], null, isHor), push, cs);
} else {
throw new IllegalArgumentException("Min:Preferred:Max size section must contain 0, 1 or 2 colons. '" + cs + "'");
}
}
/** Parses a single unit value that may also be an alignment as parsed by {@link #parseAlignKeywords(String, boolean)}.
* @param s The string to parse. Not null. May look something like "10px" or "5dlu".
* @param isHor If the value is for the horizontal dimension.
* @param emptyReplacement A replacement if s is empty. May be null.
* @return The parsed unit value. May be null.
*/
public static UnitValue parseUnitValueOrAlign(String s, boolean isHor, UnitValue emptyReplacement)
{
if (s.length() == 0)
return emptyReplacement;
UnitValue align = parseAlignKeywords(s, isHor);
if (align != null)
return align;
return parseUnitValue(s, emptyReplacement, isHor);
}
/** Parses a single unit value. E.g. "10px" or "5in"
* @param s The string to parse. Not null. May look something like "10px" or "5dlu".
* @param isHor If the value is for the horizontal dimension.
* @return The parsed unit value. null is empty string,
*/
public static UnitValue parseUnitValue(String s, boolean isHor)
{
return parseUnitValue(s, null, isHor);
}
/** Parses a single unit value.
* @param s The string to parse. May be null. May look something like "10px" or "5dlu".
* @param emptyReplacement A replacement s is empty or null. May be null.
* @param isHor If the value is for the horizontal dimension.
* @return The parsed unit value. May be null.
*/
private static UnitValue parseUnitValue(String s, UnitValue emptyReplacement, boolean isHor)
{
if (s == null || s.length() == 0)
return emptyReplacement;
String cs = s; // Save creation string.
char c0 = s.charAt(0);
// Remove start and end parentheses, if there.
if (c0 == '(' && s.charAt(s.length() - 1) == ')')
s = s.substring(1, s.length() - 1);
if (c0 == 'n' && (s.equals("null") || s.equals("n")))
return null;
if (c0 == 'i' && s.equals("inf"))
return UnitValue.INF;
int oper = getOper(s);
boolean inline = oper == UnitValue.ADD || oper == UnitValue.SUB || oper == UnitValue.MUL || oper == UnitValue.DIV;
if (oper != UnitValue.STATIC) { // It is a multi-value
String[] uvs;
if (inline == false) { // If the format is of type "opr(xxx,yyy)" (compared to in-line "10%+15px")
String sub = s.substring(4, s.length() - 1).trim();
uvs = toTrimmedTokens(sub, ',');
if (uvs.length == 1)
return parseUnitValue(sub, null, isHor);
} else {
char delim;
if (oper == UnitValue.ADD) {
delim = '+';
} else if (oper == UnitValue.SUB) {
delim = '-';
} else if (oper == UnitValue.MUL) {
delim = '*';
} else { // div left
delim = '/';
}
uvs = toTrimmedTokens(s, delim);
if (uvs.length > 2) { // More than one +-*/.
String last = uvs[uvs.length - 1];
String first = s.substring(0, s.length() - last.length() - 1);
uvs = new String[] {first, last};
}
}
if (uvs.length != 2)
throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
UnitValue sub1 = parseUnitValue(uvs[0], null, isHor);
UnitValue sub2 = parseUnitValue(uvs[1], null, isHor);
if (sub1 == null || sub2 == null)
throw new IllegalArgumentException("Malformed UnitValue. Must be two sub-values: '" + s + "'");
return new UnitValue(isHor, oper, sub1, sub2, cs);
} else {
try {
String[] numParts = getNumTextParts(s);
float value = numParts[0].length() > 0 ? Float.parseFloat(numParts[0]) : 1; // e.g. "related" has no number part..
return new UnitValue(value, numParts[1], isHor, oper, cs);
} catch(Exception e) {
throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'", e);
}
}
}
/** Parses alignment keywords and returns the appropriate UnitValue.
* @param s The string to parse. Not null.
* @param isHor If alignments for horizontal is checked. false means vertical.
* @return The unit value or null if not recognized (no exception).
*/
static UnitValue parseAlignKeywords(String s, boolean isHor)
{
if (startsWithLenient(s, "center", 1, false) != -1)
return UnitValue.CENTER;
if (isHor) {
if (startsWithLenient(s, "left", 1, false) != -1)
return UnitValue.LEFT;
if (startsWithLenient(s, "right", 1, false) != -1)
return UnitValue.RIGHT;
if (startsWithLenient(s, "leading", 4, false) != -1)
return UnitValue.LEADING;
if (startsWithLenient(s, "trailing", 5, false) != -1)
return UnitValue.TRAILING;
if (startsWithLenient(s, "label", 5, false) != -1)
return UnitValue.LABEL;
} else {
if (startsWithLenient(s, "baseline", 4, false) != -1)
return UnitValue.BASELINE_IDENTITY;
if (startsWithLenient(s, "top", 1, false) != -1)
return UnitValue.TOP;
if (startsWithLenient(s, "bottom", 1, false) != -1)
return UnitValue.BOTTOM;
}
return null;
}
/** Splits a text-number combination such as "hello 10.0" into {"hello", "10.0"}.
* @param s The string to split. Not null. Needs be be reasonably formatted since the method
* only finds the first 0-9 or . and cuts the string in half there.
* @return Always length 2 and no null elements. Elements are "" if no part found.
*/
private static String[] getNumTextParts(String s)
{
for (int i = 0, iSz = s.length(); i < iSz; i++) {
char c = s.charAt(i);
if (c == ' ')
throw new IllegalArgumentException("Space in UnitValue: '" + s + "'");
if ((c < '0' || c > '9') && c != '.' && c != '-')
return new String[] {s.substring(0, i).trim(), s.substring(i).trim()};
}
return new String[] {s, ""};
}
/** Returns the operation depending on the start character.
* @param s The string to check. Not null.
* @return E.g. UnitValue.ADD, UnitValue.SUB or UnitValue.STATIC. Returns negative value for in-line operations.
*/
private static int getOper(String s)
{
int len = s.length();
if (len < 3)
return UnitValue.STATIC;
if (len > 5 && s.charAt(3) == '(' && s.charAt(len - 1) == ')') {
if (s.startsWith("min("))
return UnitValue.MIN;
if (s.startsWith("max("))
return UnitValue.MAX;
if (s.startsWith("mid("))
return UnitValue.MID;
}
// Try in-line add/sub. E.g. "pref+10px".
for (int j = 0; j < 2; j++) { // First +- then */ (precedence)
for (int i = len - 1, p = 0; i > 0; i--) {
char c = s.charAt(i);
if (c == ')') {
p++;
} else if (c == '(') {
p--;
} else if (p == 0) {
if (j == 0) {
if (c == '+')
return UnitValue.ADD;
if (c == '-')
return UnitValue.SUB;
} else {
if (c == '*')
return UnitValue.MUL;
if (c == '/')
return UnitValue.DIV;
}
}
}
}
return UnitValue.STATIC;
}
/** Returns if a string shares at least a specified numbers starting characters with a number of matches.
*
* This method just exercise {@link #startsWithLenient(String, String, int, boolean)} with every one of
* matches and minChars.
* @param s The string to check. Not null.
* @param matches A number of possible starts for s.
* @param minChars The minimum number of characters to match for every element in matches. Needs
* to be of same length as matches. Can be null.
* @param acceptTrailing If after the required number of characters are matched on recognized characters that are not
* in one of the the matches string should be accepted. For instance if "abczz" should be matched with
* "abcdef" and min chars 3.
* @return The index of the first unmatched character if minChars was reached or -1 if a match was not
* found.
*/
private static int startsWithLenient(String s, String[] matches, int[] minChars, boolean acceptTrailing)
{
for (int i = 0; i < matches.length; i++) {
int minChar = minChars != null ? minChars[i] : -1;
int ix = startsWithLenient(s, matches[i], minChar, acceptTrailing);
if (ix > -1)
return ix;
}
return -1;
}
/** Returns if a string shares at least a specified numbers starting characters with a match.
* @param s The string to check. Not null and must be trimmed.
* @param match The possible start for s. Not null and must be trimmed.
* @param minChars The mimimum number of characters to match to s for it this to be considered a match. -1 means
* the full length of match.
* @param acceptTrailing If after the required number of charecters are matched unrecognized characters that are not
* in one of the the matches string should be accepted. For instance if "abczz" should be matched with
* "abcdef" and min chars 3.
* @return The index of the first unmatched character if minChars was reached or -1 if a match was not
* found.
*/
private static int startsWithLenient(String s, String match, int minChars, boolean acceptTrailing)
{
if (s.charAt(0) != match.charAt(0)) // Fast sanity check.
return -1;
if (minChars == -1)
minChars = match.length();
int sSz = s.length();
if (sSz < minChars)
return -1;
int mSz = match.length();
int sIx = 0;
for (int mIx = 0; mIx < mSz; sIx++, mIx++) {
while (sIx < sSz && (s.charAt(sIx) == ' ' || s.charAt(sIx) == '_')) // Disregard spaces and _
sIx++;
if (sIx >= sSz || s.charAt(sIx) != match.charAt(mIx))
return mIx >= minChars && (acceptTrailing || sIx >= sSz) && (sIx >= sSz || s.charAt(sIx - 1) == ' ') ? sIx : -1;
}
return sIx >= sSz || acceptTrailing ||s.charAt(sIx) == ' ' ? sIx : -1;
}
/** Parses a string and returns it in those parts of the string that are separated with a sep character.
*
* separator characters within parentheses will not be counted or handled in any way, whatever the depth.
*
* A space separator will be a hit to one or more spaces and thus not return empty strings.
* @param s The string to parse. If it starts and/or ends with a sep the first and/or last element returned will be "". If
* two sep are next to each other and empty element will be "between" the periods. The sep themselves will never be returned.
* @param sep The separator char.
* @return Those parts of the string that are separated with sep. Never null and at least of size 1
* @since 6.7.2 Changed so more than one space in a row works as one space.
*/
private static String[] toTrimmedTokens(String s, char sep)
{
int toks = 0, sSize = s.length();
boolean disregardDoubles = sep == ' ';
// Count the sep:s
int p = 0;
for(int i = 0; i < sSize; i++) {
char c = s.charAt(i);
if (c == '(') {
p++;
} else if (c == ')') {
p--;
} else if (p == 0 && c == sep) {
toks++;
while (disregardDoubles && i < sSize - 1 && s.charAt(i + 1) == ' ')
i++;
}
if (p < 0)
throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
}
if (p != 0)
throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
if (toks == 0)
return new String [] {s.trim()};
String[] retArr = new String[toks + 1];
int st = 0, pNr = 0;
p = 0;
for (int i = 0; i < sSize; i++) {
char c = s.charAt(i);
if (c == '(') {
p++;
} else if (c == ')') {
p--;
} else if (p == 0 && c == sep) {
retArr[pNr++] = s.substring(st, i).trim();
st = i + 1;
while (disregardDoubles && i < sSize - 1 && s.charAt(i + 1) == ' ')
i++;
}
}
retArr[pNr++] = s.substring(st, sSize).trim();
return retArr;
}
/** Parses "AAA[BBB]CCC[DDD]EEE" into {"AAA", "BBB", "CCC", "DDD", "EEE", "FFF"}. Handles empty parts. Will always start and end outside
* a [] block so that the number of returned elemets will always be uneven and at least of length 3.
*
* "|" is interpreted as "][".
* @param s The string. Might be "" but not null. Should be trimmed.
* @return The string divided into elements. Never null and at least of length 3.
* @throws IllegalArgumentException If a [] mismatch of some kind. (If not same [ as ] count or if the interleave.)
*/
private static ArrayList getRowColAndGapsTrimmed(String s)
{
if (s.indexOf('|') != -1)
s = s.replaceAll("\\|", "][");
ArrayList retList = new ArrayList(Math.max(s.length() >> 2 + 1, 3)); // Approx return length.
int s0 = 0, s1 = 0; // '[' and ']' count.
int st = 0; // Start of "next token to add".
for (int i = 0, iSz = s.length(); i < iSz; i++) {
char c = s.charAt(i);
if (c == '[') {
s0++;
} else if (c == ']') {
s1++;
} else {
continue;
}
if (s0 != s1 && (s0 - 1) != s1)
break; // Wrong [ or ] found. Break for throw.
retList.add(s.substring(st, i).trim());
st = i + 1;
}
if (s0 != s1)
throw new IllegalArgumentException("'[' and ']' mismatch in row/column format string: " + s);
if (s0 == 0) {
retList.add("");
retList.add(s);
retList.add("");
} else if (retList.size() % 2 == 0) {
retList.add(s.substring(st, s.length()));
}
return retList;
}
/** Makes null "", trims and converts to lower case.
* @param s The string
* @return Not null.
*/
public static String prepare(String s)
{
return s != null ? s.trim().toLowerCase() : "";
}
// /** Tests to serialize and deserialize the object with both XMLEncoder/Decoder and through Serializable
// * @param o The object to serialize
// * @return The same object after a tri through the process.
// */
// public static final Object serializeTest(Object o)
// {
// try {
// ByteArrayOutputStream barr = new ByteArrayOutputStream();
// XMLEncoder enc = new XMLEncoder(barr);
// enc.writeObject(o);
// enc.close();
//
// XMLDecoder dec = new XMLDecoder(new ByteArrayInputStream(barr.toByteArray()));
// o = dec.readObject();
// dec.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// try {
// ByteArrayOutputStream barr = new ByteArrayOutputStream();
// ObjectOutputStream oos = new ObjectOutputStream(barr);
// oos.writeObject(o);
// oos.close();
//
// ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
// o = ois.readObject();
// ois.close();
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// return o;
// }
}
miglayout-5.1/core/src/main/java/net/miginfocom/layout/ContainerWrapper.java 0000775 0000000 0000000 00000006176 13241015632 0027347 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A class that wraps a container that contains components.
*/
public interface ContainerWrapper extends ComponentWrapper
{
/** Returns the components of the container that wrapper is wrapping.
* @return The components of the container that wrapper is wrapping. Never null.
*/
public abstract ComponentWrapper[] getComponents();
/** Returns the number of components that this parent has.
* @return The number of components that this parent has.
*/
public abstract int getComponentCount();
/** Returns the LayoutHandler (in Swing terms) that is handling the layout of this container.
* If there exist no such class the method should return the same as {@link #getComponent()}, which is the
* container itself.
* @return The layout handler instance. Never null.
*/
public abstract Object getLayout();
/** Returns if this container is using left-to-right component ordering.
* @return If this container is using left-to-right component ordering.
*/
public abstract boolean isLeftToRight();
/** Paints a cell to indicate where it is.
* @param x The x coordinate to start the drawing.
* @param y The x coordinate to start the drawing.
* @param width The width to draw/fill
* @param height The height to draw/fill
*/
public abstract void paintDebugCell(int x, int y, int width, int height);
}
miglayout-5.1/core/src/main/java/net/miginfocom/layout/DimConstraint.java 0000775 0000000 0000000 00000046737 13241015632 0026651 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** A simple value holder for a constraint for one dimension.
*/
public final class DimConstraint implements Externalizable
{
/** How this entity can be resized in the dimension that this constraint represents.
*/
final ResizeConstraint resize = new ResizeConstraint();
// Look at the properties' getter/setter methods for explanation
private String sizeGroup = null; // A "context" compared with equals.
private BoundSize size = BoundSize.NULL_SIZE; // Min, pref, max. Never null, but sizes can be null.
private BoundSize gapBefore = null, gapAfter = null;
private UnitValue align = null;
// ************** Only applicable on components! *******************
private String endGroup = null; // A "context" compared with equals.
// ************** Only applicable on rows/columns! *******************
private boolean fill = false;
private boolean noGrid = false;
/** Empty constructor.
*/
public DimConstraint()
{
}
/** Returns the grow priority. Relative priority is used for determining which entities gets the extra space first.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The grow priority.
*/
public int getGrowPriority()
{
return resize.growPrio;
}
/** Sets the grow priority. Relative priority is used for determining which entities gets the extra space first.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new grow priority.
*/
public void setGrowPriority(int p)
{
resize.growPrio = p;
}
/** Returns the grow weight.
* Grow weight is how flexible the entity should be, relative to other entities, when it comes to growing. null or
* zero mean it will never grow. An entity that has twice the grow weight compared to another entity will get twice
* as much of available space.
*
* GrowWeight are only compared within the same GrowPrio.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current grow weight.
*/
public Float getGrow()
{
return resize.grow;
}
/** Sets the grow weight.
* Grow weight is how flexible the entity should be, relative to other entities, when it comes to growing. null or
* zero mean it will never grow. An entity that has twice the grow weight compared to another entity will get twice
* as much of available space.
*
* GrowWeight are only compared within the same GrowPrio.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param weight The new grow weight.
*/
public void setGrow(Float weight)
{
resize.grow = weight;
}
/** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarce.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The shrink priority.
*/
public int getShrinkPriority()
{
return resize.shrinkPrio;
}
/** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarce.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param p The new shrink priority.
*/
public void setShrinkPriority(int p)
{
resize.shrinkPrio = p;
}
/** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarce.
* Shrink weight is how flexible the entity should be, relative to other entities, when it comes to shrinking. null or
* zero mean it will never shrink (default). An entity that has twice the shrink weight compared to another entity will get twice
* as much of available space.
*
* Shrink(Weight) are only compared within the same ShrinkPrio.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current shrink weight.
*/
public Float getShrink()
{
return resize.shrink;
}
/** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarce.
* Shrink weight is how flexible the entity should be, relative to other entities, when it comes to shrinking. null or
* zero mean it will never shrink (default). An entity that has twice the shrink weight compared to another entity will get twice
* as much of available space.
*
* Shrink(Weight) are only compared within the same ShrinkPrio.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param weight The new shrink weight.
*/
public void setShrink(Float weight)
{
resize.shrink = weight;
}
public UnitValue getAlignOrDefault(boolean isCols)
{
if (align != null)
return align;
if (isCols)
return UnitValue.LEADING;
return fill || PlatformDefaults.getDefaultRowAlignmentBaseline() == false ? UnitValue.CENTER : UnitValue.BASELINE_IDENTITY;
}
/** Returns the alignment used either as a default value for sub-entities or for this entity.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The alignment.
*/
public UnitValue getAlign()
{
return align;
}
/** Sets the alignment used wither as a default value for sub-entities or for this entity.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param uv The new shrink priority. E.g. {@link UnitValue#CENTER} or {@link net.miginfocom.layout.UnitValue#LEADING}.
*/
public void setAlign(UnitValue uv)
{
this.align = uv;
}
/** Returns the gap after this entity. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
* grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The gap after this entity
*/
public BoundSize getGapAfter()
{
return gapAfter;
}
/** Sets the gap after this entity. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
* grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The new gap.
* @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean)
*/
public void setGapAfter(BoundSize size)
{
this.gapAfter = size;
}
boolean hasGapAfter()
{
return gapAfter != null && gapAfter.isUnset() == false;
}
boolean isGapAfterPush()
{
return gapAfter != null && gapAfter.getGapPush();
}
/** Returns the gap before this entity. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
* grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The gap before this entity
*/
public BoundSize getGapBefore()
{
return gapBefore;
}
/** Sets the gap before this entity. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
* grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
*
* See also {@link net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean)}.
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The new gap.
*/
public void setGapBefore(BoundSize size)
{
this.gapBefore = size;
}
boolean hasGapBefore()
{
return gapBefore != null && gapBefore.isUnset() == false;
}
boolean isGapBeforePush()
{
return gapBefore != null && gapBefore.getGapPush();
}
/** Returns the min/preferred/max size for the entity in the dimension that this object describes.
*
* See also {@link net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean)}.
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current size. Never null since v3.5.
*/
public BoundSize getSize()
{
return size;
}
/** Sets the min/preferred/max size for the entity in the dimension that this object describes.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param size The new size. May be null.
*/
public void setSize(BoundSize size)
{
if (size != null)
size.checkNotLinked();
this.size = size;
}
/** Returns the size group that this entity should be in for the dimension that this object is describing.
* If this constraint is in a size group that is specified here. null means no size group
* and all other values are legal. Comparison with .equals(). Components/columns/rows in the same size group
* will have the same min/preferred/max size; that of the largest in the group for the first two and the
* smallest for max.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current size group. May be null.
*/
public String getSizeGroup()
{
return sizeGroup;
}
/** Sets the size group that this entity should be in for the dimension that this object is describing.
* If this constraint is in a size group that is specified here. null means no size group
* and all other values are legal. Comparison with .equals(). Components/columns/rows in the same size group
* will have the same min/preferred/max size; that of the largest in the group for the first two and the
* smallest for max.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The new size group. null disables size grouping.
*/
public void setSizeGroup(String s)
{
sizeGroup = s;
}
// ************** Only applicable on components ! *******************
/** Returns the end group that this entity should be in for the dimension that this object is describing.
* If this constraint is in an end group that is specified here. null means no end group
* and all other values are legal. Comparison with .equals(). Components in the same end group
* will have the same end coordinate.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return The current end group. null may be returned.
*/
public String getEndGroup()
{
return endGroup;
}
/** Sets the end group that this entity should be in for the dimension that this object is describing.
* If this constraint is in an end group that is specified here. null means no end group
* and all other values are legal. Comparison with .equals(). Components in the same end group
* will have the same end coordinate.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param s The new end group. null disables end grouping.
*/
public void setEndGroup(String s)
{
endGroup = s;
}
// ************** Not applicable on components below ! *******************
/** Returns if the component in the row/column that this constraint should default be grown in the same dimension that
* this constraint represents (width for column and height for a row).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return true means that components should grow.
*/
public boolean isFill()
{
return fill;
}
/** Sets if the component in the row/column that this constraint should default be grown in the same dimension that
* this constraint represents (width for column and height for a row).
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true means that components should grow.
*/
public void setFill(boolean b)
{
fill = b;
}
/** Returns if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
* will be one cell and all components will end up in that cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @return true means that the whole row/column should be one cell.
*/
public boolean isNoGrid()
{
return noGrid;
}
/** Sets if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
* will be one cell and all components will end up in that cell.
*
* For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
* @param b true means that the whole row/column should be one cell.
*/
public void setNoGrid(boolean b)
{
this.noGrid = b;
}
/** Returns the gaps as pixel values.
* @param parent The parent. Used to get the pixel values.
* @param defGap The default gap to use if there is no gap set on this object (i.e. it is null).
* @param refSize The reference size used to get the pixel sizes.
* @param before IF it is the gap before rather than the gap after to return.
* @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
* for gap sizes that are null. Returns null if there was no gap specified. A new and free to use array.
*/
int[] getRowGaps(ContainerWrapper parent, BoundSize defGap, int refSize, boolean before)
{
BoundSize gap = before ? gapBefore : gapAfter;
if (gap == null || gap.isUnset())
gap = defGap;
if (gap == null || gap.isUnset())
return null;
int[] ret = new int[3];
for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
UnitValue uv = gap.getSize(i);
ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
}
return ret;
}
/** Returns the gaps as pixel values.
* @param parent The parent. Used to get the pixel values.
* @param comp The component that the gap is for. If not for a component it is null.
* @param adjGap The gap that the adjacent component, if any, has towards comp.
* @param adjacentComp The adjacent component if any. May be null.
* @param refSize The reference size used to get the pixel sizes.
* @param adjacentSide What side the adjacentComp is on. 0 = top, 1 = left, 2 = bottom, 3 = right.
* @param tag The tag string that the component might be tagged with in the component constraints. May be null.
* @param isLTR If it is left-to-right.
* @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
* for gap sizes that are null. Returns null if there was no gap specified. A new and free to use array.
*/
int[] getComponentGaps(ContainerWrapper parent, ComponentWrapper comp, BoundSize adjGap, ComponentWrapper adjacentComp, String tag, int refSize, int adjacentSide, boolean isLTR)
{
BoundSize gap = adjacentSide < 2 ? gapBefore : gapAfter;
boolean hasGap = gap != null && gap.getGapPush();
if ((gap == null || gap.isUnset()) && (adjGap == null || adjGap.isUnset()) && comp != null)
gap = PlatformDefaults.getDefaultComponentGap(comp, adjacentComp, adjacentSide + 1, tag, isLTR);
if (gap == null)
return hasGap ? new int[] {0, 0, LayoutUtil.NOT_SET} : null;
int[] ret = new int[3];
for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
UnitValue uv = gap.getSize(i);
ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
}
return ret;
}
// ************************************************
// Persistence Delegate and Serializable combined.
// ************************************************
private Object readResolve() throws ObjectStreamException
{
return LayoutUtil.getSerializedObject(this);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
}
@Override
public void writeExternal(ObjectOutput out) throws IOException
{
if (getClass() == DimConstraint.class)
LayoutUtil.writeAsXML(out, this);
}
}
miglayout-5.1/core/src/main/java/net/miginfocom/layout/Grid.java 0000775 0000000 0000000 00000255262 13241015632 0024753 0 ustar 00root root 0000000 0000000 package net.miginfocom.layout;
import java.lang.ref.WeakReference;
import java.util.*;
/*
* License (BSD):
* ==============
*
* Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
* Neither the name of the MiG InfoCom AB nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* @version 1.0
* @author Mikael Grev, MiG InfoCom AB
* Date: 2006-sep-08
*/
/** Holds components in a grid. Does most of the logic behind the layout manager.
*/
public final class Grid
{
public static final boolean TEST_GAPS = true;
private static final Float[] GROW_100 = new Float[] {ResizeConstraint.WEIGHT_100};
private static final DimConstraint DOCK_DIM_CONSTRAINT = new DimConstraint();
static {
DOCK_DIM_CONSTRAINT.setGrowPriority(0);
}
/** This is the maximum grid position for "normal" components. Docking components use the space out to
* MAX_DOCK_GRID and below 0.
*/
private static final int MAX_GRID = 30000;
/** Docking components will use the grid coordinates -MAX_DOCK_GRID -> 0 and MAX_GRID -> MAX_DOCK_GRID.
*/
private static final int MAX_DOCK_GRID = 32767;
/** A constraint used for gaps.
*/
private static final ResizeConstraint GAP_RC_CONST = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, null);
private static final ResizeConstraint GAP_RC_CONST_PUSH = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, ResizeConstraint.WEIGHT_100);
/** Used for components that doesn't have a CC set. Not that it's really really important that the CC is never changed in this Grid class.
*/
private static final CC DEF_CC = new CC();
/** The constraints. Never null.
*/
private final LC lc;
/** The parent that is layout out and this grid is done for. Never null.
*/
private final ContainerWrapper container;
/** An x, y array implemented as a sparse array to accommodate for any grid size without wasting memory (or rather 15 bit (0-MAX_GRID * 0-MAX_GRID).
*/
private final LinkedHashMap grid = new LinkedHashMap(); // [(y << 16) + x] -> Cell. null key for absolute positioned compwraps
private HashMap wrapGapMap = null; // Row or Column index depending in the dimension that "wraps". Normally row indexes but may be column indexes if "flowy". 0 means before first row/col.
/** The size of the grid. Row count and column count.
*/
private final TreeSet rowIndexes = new TreeSet(), colIndexes = new TreeSet();
/** The row and column specifications.
*/
private final AC rowConstr, colConstr;
/** The in the constructor calculated min/pref/max sizes of the rows and columns.
*/
private FlowSizeSpec colFlowSpecs = null, rowFlowSpecs = null;
/** Components that are connections in one dimension (such as baseline alignment for instance) are grouped together and stored here.
* One for each row/column.
*/
private final ArrayList[] colGroupLists, rowGroupLists; //[(start)row/col number]
/** The in the constructor calculated min/pref/max size of the whole grid.
*/
private int[] width = null, height = null;
/** If debug is on contains the bounds for things to paint when calling {@link ContainerWrapper#paintDebugCell(int, int, int, int)}
*/
private ArrayList debugRects = null; // [x, y, width, height]
/** If any of the absolute coordinates for component bounds has links the name of the target is in this Set.
* Since it requires some memory and computations this is checked at the creation so that
* the link information is only created if needed later.
*
* The boolean is true for groups id:s and null for normal id:s.
*/
private HashMap linkTargetIDs = null;
private final int dockOffY, dockOffX;
private final Float[] pushXs, pushYs;
private final ArrayList callbackList;
/** Constructor.
* @param container The container that will be laid out.
* @param lc The form flow constraints.
* @param rowConstr The rows specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
* @param colConstr The columns specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
* @param ccMap The map containing the parsed constraints for each child component of parent. Will not be altered. Can have null CC which will use a common
* cached one.
* @param callbackList A list of callbacks or null if none. Will not be altered.
*/
public Grid(ContainerWrapper container, LC lc, AC rowConstr, AC colConstr, Map extends ComponentWrapper, CC> ccMap, ArrayList callbackList)
{
this.lc = lc;
this.rowConstr = rowConstr;
this.colConstr = colConstr;
this.container = container;
this.callbackList = callbackList;
int wrap = lc.getWrapAfter() != 0 ? lc.getWrapAfter() : (lc.isFlowX() ? colConstr : rowConstr).getConstaints().length;
boolean useVisualPadding = lc.isVisualPadding();
final ComponentWrapper[] comps = container.getComponents();
boolean hasTagged = false; // So we do not have to sort if it will not do any good
boolean hasPushX = false, hasPushY = false;
boolean hitEndOfRow = false;
final int[] cellXY = new int[2];
final ArrayList spannedRects = new ArrayList(2);
final DimConstraint[] specs = (lc.isFlowX() ? rowConstr : colConstr).getConstaints();
int sizeGroupsX = 0, sizeGroupsY = 0;
int[] dockInsets = null; // top, left, bottom, right insets for docks.
LinkHandler.clearTemporaryBounds(container.getLayout());
for (int i = 0; i < comps.length;) {
ComponentWrapper comp = comps[i];
CC rootCc = getCC(comp, ccMap);
addLinkIDs(rootCc);
int hideMode = comp.isVisible() ? -1 : rootCc.getHideMode() != -1 ? rootCc.getHideMode() : lc.getHideMode();
if (hideMode == 3) { // To work with situations where there are components that does not have a layout manager, or not this one.
setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
i++;
continue; // The "external" component should not be handled further.
}
if (rootCc.getHorizontal().getSizeGroup() != null)
sizeGroupsX++;
if (rootCc.getVertical().getSizeGroup() != null)
sizeGroupsY++;
// Special treatment of absolute positioned components.
if (getPos(comp, rootCc) != null || rootCc.isExternal()) {
CompWrap cw = new CompWrap(comp, rootCc, hideMode, useVisualPadding);
Cell cell = grid.get(null);
if (cell == null) {
grid.put(null, new Cell(cw));
} else {
cell.compWraps.add(cw);
}
if (!rootCc.isBoundsInGrid() || rootCc.isExternal()) {
setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
i++;
continue;
}
}
if (rootCc.getDockSide() != -1) {
if (dockInsets == null)
dockInsets = new int[] {-MAX_DOCK_GRID, -MAX_DOCK_GRID, MAX_DOCK_GRID, MAX_DOCK_GRID};
addDockingCell(dockInsets, rootCc.getDockSide(), new CompWrap(comp, rootCc, hideMode, useVisualPadding));
i++;
continue;
}
Boolean cellFlowX = rootCc.getFlowX();
Cell cell = null;
if (rootCc.isNewline()) {
wrap(cellXY, rootCc.getNewlineGapSize());
} else if (hitEndOfRow) {
wrap(cellXY, null);
}
hitEndOfRow = false;
final boolean rowNoGrid = lc.isNoGrid() || ((DimConstraint) LayoutUtil.getIndexSafe(specs, lc.isFlowX() ? cellXY[1] : cellXY[0])).isNoGrid();
// Move to a free y, x if no absolute grid specified
int cx = rootCc.getCellX();
int cy = rootCc.getCellY();
if ((cx < 0 || cy < 0) && rowNoGrid == false && rootCc.getSkip() == 0) { // 3.7.2: If skip, don't find an empty cell first.
while (isCellFree(cellXY[1], cellXY[0], spannedRects) == false) {
if (Math.abs(increase(cellXY, 1)) >= wrap)
wrap(cellXY, null);
}
} else {
if (cx >= 0 && cy >= 0) {
if (cy >= 0) {
cellXY[0] = cx;
cellXY[1] = cy;
} else { // Only one coordinate is specified. Use the current row (flowx) or column (flowy) to fill in.
if (lc.isFlowX()) {
cellXY[0] = cx;
} else {
cellXY[1] = cx;
}
}
ensureIndexSizes(cx, cy);
}
cell = getCell(cellXY[1], cellXY[0]); // Might be null
}
// Skip a number of cells. Changed for 3.6.1 to take wrap into account and thus "skip" to the next and possibly more rows.
for (int s = 0, skipCount = rootCc.getSkip(); s < skipCount; s++) {
do {
if (Math.abs(increase(cellXY, 1)) >= wrap)
wrap(cellXY, null);
} while (isCellFree(cellXY[1], cellXY[0], spannedRects) == false);
}
// If cell is not created yet, create it and set it.
if (cell == null) {
int spanx = Math.min(rowNoGrid && lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanX(), MAX_GRID - cellXY[0]);
int spany = Math.min(rowNoGrid && !lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanY(), MAX_GRID - cellXY[1]);
cell = new Cell(spanx, spany, cellFlowX != null ? cellFlowX : lc.isFlowX());
setCell(cellXY[1], cellXY[0], cell);
// Add a rectangle so we can know that spanned cells occupy more space.
if (spanx > 1 || spany > 1)
spannedRects.add(new int[] {cellXY[0], cellXY[1], spanx, spany});
}
// Add the one, or all, components that split the grid position to the same Cell.
boolean wrapHandled = false;
int splitLeft = rowNoGrid ? LayoutUtil.INF : rootCc.getSplit() - 1;
boolean splitExit = false;
final boolean spanRestOfRow = (lc.isFlowX() ? rootCc.getSpanX() : rootCc.getSpanY()) == LayoutUtil.INF;
for (; splitLeft >= 0 && i < comps.length; splitLeft--) {
ComponentWrapper compAdd = comps[i];
CC cc = getCC(compAdd, ccMap);
addLinkIDs(cc);
boolean visible = compAdd.isVisible();
hideMode = visible ? -1 : cc.getHideMode() != -1 ? cc.getHideMode() : lc.getHideMode();
if (cc.isExternal() || hideMode == 3) {
i++;
splitLeft++; // Added for 3.5.5 so that these components does not "take" a split slot.
continue; // To work with situations where there are components that does not have a layout manager, or not this one.
}
hasPushX |= (visible || hideMode > 1) && (cc.getPushX() != null);
hasPushY |= (visible || hideMode > 1) && (cc.getPushY() != null);
if (cc != rootCc) { // If not first in a cell
if (cc.isNewline() || cc.isBoundsInGrid() == false || cc.getDockSide() != -1)
break;
if (splitLeft > 0 && cc.getSkip() > 0) {
splitExit = true;
break;
}
}
CompWrap cw = new CompWrap(compAdd, cc, hideMode, useVisualPadding);
cell.compWraps.add(cw);
cell.hasTagged |= cc.getTag() != null;
hasTagged |= cell.hasTagged;
if (cc != rootCc) {
if (cc.getHorizontal().getSizeGroup() != null)
sizeGroupsX++;
if (cc.getVertical().getSizeGroup() != null)
sizeGroupsY++;
}
i++;
if ((cc.isWrap() || (spanRestOfRow && splitLeft == 0))) {
if (cc.isWrap()) {
wrap(cellXY, cc.getWrapGapSize());
} else {
hitEndOfRow = true;
}
wrapHandled = true;
break;
}
}
if (wrapHandled == false && rowNoGrid == false) {
int span = lc.isFlowX() ? cell.spanx : cell.spany;
if (Math.abs((lc.isFlowX() ? cellXY[0] : cellXY[1])) + span >= wrap) {
hitEndOfRow = true;
} else {
increase(cellXY, splitExit ? span - 1 : span);
}
}
}
// If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group.
if (sizeGroupsX > 0 || sizeGroupsY > 0) {
HashMap sizeGroupMapX = sizeGroupsX > 0 ? new HashMap(sizeGroupsX) : null;
HashMap sizeGroupMapY = sizeGroupsY > 0 ? new HashMap(sizeGroupsY) : null;
ArrayList sizeGroupCWs = new ArrayList(Math.max(sizeGroupsX, sizeGroupsY));
for (Cell cell : grid.values()) {
for (int i = 0; i < cell.compWraps.size(); i++) {
CompWrap cw = cell.compWraps.get(i);
String sgx = cw.cc.getHorizontal().getSizeGroup();
String sgy = cw.cc.getVertical().getSizeGroup();
if (sgx != null || sgy != null) {
if (sgx != null && sizeGroupMapX != null)
addToSizeGroup(sizeGroupMapX, sgx, cw.getSizes(true));
if (sgy != null && sizeGroupMapY != null)
addToSizeGroup(sizeGroupMapY, sgy, cw.getSizes(false));
sizeGroupCWs.add(cw);
}
}
}
// Set/equalize the sizeGroups to same the values.
for (CompWrap cw : sizeGroupCWs) {
if (sizeGroupMapX != null)
cw.setForcedSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true); // Target method handles null sizes
if (sizeGroupMapY != null)
cw.setForcedSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes
}
} // Component loop
if (hasTagged)
sortCellsByPlatform(grid.values(), container);
// Calculate gaps now that the cells are filled and we know all adjacent components.
boolean ltr = LayoutUtil.isLeftToRight(lc, container);
for (Cell cell : grid.values()) {
ArrayList cws = cell.compWraps;
for (int i = 0, lastI = cws.size() - 1; i <= lastI; i++) {
CompWrap cw = cws.get(i);
ComponentWrapper cwBef = i > 0 ? cws.get(i - 1).comp : null;
ComponentWrapper cwAft = i < lastI ? cws.get(i + 1).comp : null;
String tag = getCC(cw.comp, ccMap).getTag();
CC ccBef = cwBef != null ? getCC(cwBef, ccMap) : null;
CC ccAft = cwAft != null ? getCC(cwAft, ccMap) : null;
cw.calcGaps(cwBef, ccBef, cwAft, ccAft, tag, cell.flowx, ltr);
}
}
dockOffX = getDockInsets(colIndexes);
dockOffY = getDockInsets(rowIndexes);
// Add synthetic indexes for empty rows and columns so they can get a size
ensureIndexSizes(colConstr.getCount(), rowConstr.getCount());
colGroupLists = divideIntoLinkedGroups(false);
rowGroupLists = divideIntoLinkedGroups(true);
pushXs = hasPushX || lc.isFillX() ? getDefaultPushWeights(false) : null;
pushYs = hasPushY || lc.isFillY() ? getDefaultPushWeights(true) : null;
if (LayoutUtil.isDesignTime(container))
saveGrid(container, grid);
}
private void ensureIndexSizes(int colCount, int rowCount)
{
for (int i = 0; i < colCount; i++)
colIndexes.add(i);
for (int i = 0; i < rowCount; i++)
rowIndexes.add(i);
}
private static CC getCC(ComponentWrapper comp, Map extends ComponentWrapper, CC> ccMap)
{
CC cc = ccMap.get(comp);
return cc != null ? cc : DEF_CC;
}
private void addLinkIDs(CC cc)
{
String[] linkIDs = cc.getLinkTargets();
for (String linkID : linkIDs) {
if (linkTargetIDs == null)
linkTargetIDs = new HashMap();
linkTargetIDs.put(linkID, null);
}
}
/** If the container (parent) that this grid is laying out has changed its bounds, call this method to
* clear any cached values min/pref/max sizes of the components and rows/columns.
*
* If any component can have changed cell the grid needs to be recreated.
*/
public void invalidateContainerSize()
{
colFlowSpecs = null;
invalidateComponentSizes();
}
private void invalidateComponentSizes()
{
for (Cell cell : grid.values()) {
for (CompWrap compWrap : cell.compWraps)
compWrap.invalidateSizes();
}
}
/**
* @deprecated since 5.0 Last boolean is not needed and is gotten from the new {@link net.miginfocom.layout.ComponentWrapper#getContentBias()} instead;
*/
public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean notUsed)
{
return layoutImpl(bounds, alignX, alignY, debug, false);
}
/** Does the actual layout. Uses many values calculated in the constructor.
* @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height].
* @param alignX The alignment for the x-axis. Can be null.
* @param alignY The alignment for the y-axis. Can be null.
* @param debug If debug information should be saved in {@link #debugRects}.
* @return If the layout has changed the preferred size and there is need for a new layout. This can happen if one or more components
* in the grid has a content bias according to {@link net.miginfocom.layout.ComponentWrapper#getContentBias()}.
* @since 5.0
*/
public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug)
{
return layoutImpl(bounds, alignX, alignY, debug, false);
}
/** Does the actual layout. Uses many values calculated in the constructor.
* @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height].
* @param alignX The alignment for the x-axis. Can be null.
* @param alignY The alignment for the y-axis. Can be null.
* @param debug If debug information should be saved in {@link #debugRects}.
* @param trialRun If true the bounds calculated will not be transferred to the components. Only the internal size
* of the components will be calculated.
* @return If the layout has changed the preferred size and there is need for a new layout. This can happen if one or more components
* in the grid has a content bias according to {@link net.miginfocom.layout.ComponentWrapper#getContentBias()}.
* @since 5.0
*/
private boolean layoutImpl(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean trialRun)
{
if (debug)
debugRects = new ArrayList();
if (colFlowSpecs == null)
checkSizeCalcs(bounds[2], bounds[3]);
resetLinkValues(true, true);
layoutInOneDim(bounds[2], alignX, false, pushXs);
layoutInOneDim(bounds[3], alignY, true, pushYs);
HashMap endGrpXMap = null, endGrpYMap = null;
int compCount = container.getComponentCount();
// Transfer the calculated bound from the ComponentWrappers to the actual Components.
boolean addVisualPadding = lc.isVisualPadding();
boolean layoutAgain = false;
if (compCount > 0) {
for (int j = 0; j < (linkTargetIDs != null ? 2 : 1); j++) { // First do the calculations (maybe more than once) then set the bounds when done
boolean doAgain;
int count = 0;
do {
doAgain = false;
for (Cell cell : grid.values()) {
for (CompWrap cw : cell.compWraps) {
if (j == 0) {
doAgain |= doAbsoluteCorrections(cw, bounds);
if (!doAgain) { // If we are going to do this again, do not bother this time around
if (cw.cc.getHorizontal().getEndGroup() != null)
endGrpXMap = addToEndGroup(endGrpXMap, cw.cc.getHorizontal().getEndGroup(), cw.x + cw.w);
if (cw.cc.getVertical().getEndGroup() != null)
endGrpYMap = addToEndGroup(endGrpYMap, cw.cc.getVertical().getEndGroup(), cw.y + cw.h);
}
// @since 3.7.2 Needed or absolute "pos" pointing to "visual" or "container" didn't work if
// their bounds changed during the layout cycle. At least not in SWT.
if (linkTargetIDs != null && (linkTargetIDs.containsKey("visual") || linkTargetIDs.containsKey("container"))) {
layoutAgain = true;
}
}
if (linkTargetIDs == null || j == 1) {
if (cw.cc.getHorizontal().getEndGroup() != null)
cw.w = endGrpXMap.get(cw.cc.getHorizontal().getEndGroup()) - cw.x;
if (cw.cc.getVertical().getEndGroup() != null)
cw.h = endGrpYMap.get(cw.cc.getVertical().getEndGroup()) - cw.y;
cw.x += bounds[0];
cw.y += bounds[1];
if (!trialRun)
cw.transferBounds(addVisualPadding);
if (callbackList != null) {
for (LayoutCallback callback : callbackList)
callback.correctBounds(cw.comp);
}
}
}
}
clearGroupLinkBounds();
if (++count > ((compCount << 3) + 10)) {
System.err.println("Unstable cyclic dependency in absolute linked values.");
break;
}
} while (doAgain);
}
}
// Add debug shapes for the "cells". Use the CompWraps as base for inding the cells.
if (debug) {
for (Cell cell : grid.values()) {
ArrayList compWraps = cell.compWraps;
for (CompWrap cw : compWraps) {
LinkedDimGroup hGrp = getGroupContaining(colGroupLists, cw);
LinkedDimGroup vGrp = getGroupContaining(rowGroupLists, cw);
if (hGrp != null && vGrp != null)
debugRects.add(new int[]{hGrp.lStart + bounds[0] - (hGrp.fromEnd ? hGrp.lSize : 0), vGrp.lStart + bounds[1] - (vGrp.fromEnd ? vGrp.lSize : 0), hGrp.lSize, vGrp.lSize});
}
}
}
return layoutAgain;
}
public void paintDebug()
{
if (debugRects != null) {
container.paintDebugOutline(lc.isVisualPadding());
ArrayList painted = new ArrayList();
for (int[] r : debugRects) {
if (!painted.contains(r)) {
container.paintDebugCell(r[0], r[1], r[2], r[3]);
painted.add(r);
}
}
for (Cell cell : grid.values()) {
ArrayList compWraps = cell.compWraps;
for (CompWrap compWrap : compWraps)
compWrap.comp.paintDebugOutline(lc.isVisualPadding());
}
}
}
public ContainerWrapper getContainer()
{
return container;
}
public final int[] getWidth()
{
return getWidth(lastRefHeight);
}
public final int[] getWidth(int refHeight)
{
checkSizeCalcs(lastRefWidth, refHeight);
return width.clone();
}
public final int[] getHeight()
{
return getHeight(lastRefWidth);
}
public final int[] getHeight(int refWidth)
{
checkSizeCalcs(refWidth, lastRefHeight);
return height.clone();
}
private int lastRefWidth = 0, lastRefHeight = 0;
private void checkSizeCalcs(int refWidth, int refHeight)
{
if (colFlowSpecs == null)
calcGridSizes(refWidth, refHeight);
if ((refWidth > 0 && refWidth != lastRefWidth) || (refHeight > 0 && refHeight != lastRefHeight)) {
int[] refBounds = new int[] {0, 0, (refWidth > 0 ? refWidth : width[LayoutUtil.PREF]), (refHeight > 0 ? refHeight : height[LayoutUtil.PREF])};
layoutImpl(refBounds, null, null, false, true);
calcGridSizes(refWidth, refHeight);
}
lastRefWidth = refWidth;
lastRefHeight = refHeight;
}
private void calcGridSizes(int refWidth, int refHeight)
{
// Note, in these calls the grid can be invalidated and specs set to null. Therefore use local versions.
FlowSizeSpec colSpecs = calcRowsOrColsSizes(true, refWidth);
FlowSizeSpec rowSpecs = calcRowsOrColsSizes(false, refHeight);
colFlowSpecs = colSpecs;
rowFlowSpecs = rowSpecs;
width = getMinPrefMaxSumSize(true, colSpecs.sizes);
height = getMinPrefMaxSumSize(false, rowSpecs.sizes);
if (linkTargetIDs == null) {
resetLinkValues(false, true);
} else {
// This call makes some components flicker on SWT. They get their bounds changed twice since
// the change might affect the absolute size adjustment below. There's no way around this that
// I know of.
layout(new int[]{0, 0, refWidth, refHeight}, null, null, false);
resetLinkValues(false, false);
}
adjustSizeForAbsolute(true);
adjustSizeForAbsolute(false);
}
private UnitValue[] getPos(ComponentWrapper cw, CC cc)
{
UnitValue[] callbackPos = null;
if (callbackList != null) {
for (int i = 0; i < callbackList.size() && callbackPos == null; i++)
callbackPos = callbackList.get(i).getPosition(cw); // NOT a copy!
}
// If one is null, return the other (which many also be null)
UnitValue[] ccPos = cc.getPos(); // A copy!!
if (callbackPos == null || ccPos == null)
return callbackPos != null ? callbackPos : ccPos;
// Merge
for (int i = 0; i < 4; i++) {
UnitValue cbUv = callbackPos[i];
if (cbUv != null)
ccPos[i] = cbUv;
}
return ccPos;
}
private BoundSize[] getCallbackSize(ComponentWrapper cw)
{
if (callbackList != null) {
for (LayoutCallback callback : callbackList) {
BoundSize[] bs = callback.getSize(cw); // NOT a copy!
if (bs != null)
return bs;
}
}
return null;
}
private static int getDockInsets(TreeSet set)
{
int c = 0;
for (Integer i : set) {
if (i < -MAX_GRID) {
c++;
} else {
break; // Since they are sorted we can break
}
}
return c;
}
/**
* @param cw Never null.
* @param cc Never null.
* @param external The bounds should be stored even if they are not in {@link #linkTargetIDs}.
* @return If a change has been made.
*/
private boolean setLinkedBounds(ComponentWrapper cw, CC cc, int x, int y, int w, int h, boolean external)
{
String id = cc.getId() != null ? cc.getId() : cw.getLinkId();
if (id == null)
return false;
String gid = null;
int grIx = id.indexOf('.');
if (grIx != -1 ) {
gid = id.substring(0, grIx);
id = id.substring(grIx + 1);
}
Object lay = container.getLayout();
boolean changed = false;
if (external || (linkTargetIDs != null && linkTargetIDs.containsKey(id)))
changed = LinkHandler.setBounds(lay, id, x, y, w, h, !external, false);
if (gid != null && (external || (linkTargetIDs != null && linkTargetIDs.containsKey(gid)))) {
if (linkTargetIDs == null)
linkTargetIDs = new HashMap(4);
linkTargetIDs.put(gid, Boolean.TRUE);
changed |= LinkHandler.setBounds(lay, gid, x, y, w, h, !external, true);
}
return changed;
}
/** Go to next cell.
* @param p The point to increase
* @param cnt How many cells to advance.
* @return The new value in the "increasing" dimension.
*/
private int increase(int[] p, int cnt)
{
return lc.isFlowX() ? (p[0] += cnt) : (p[1] += cnt);
}
/** Wraps to the next row or column depending on if horizontal flow or vertical flow is used.
* @param cellXY The point to wrap and thus set either x or y to 0 and increase the other one.
* @param gapSize The gaps size specified in a "wrap XXX" or "newline XXX" or null if none.
*/
private void wrap(int[] cellXY, BoundSize gapSize)
{
boolean flowx = lc.isFlowX();
cellXY[0] = flowx ? 0 : cellXY[0] + 1;
cellXY[1] = flowx ? cellXY[1] + 1 : 0;
if (gapSize != null) {
if (wrapGapMap == null)
wrapGapMap = new HashMap(8);
wrapGapMap.put(cellXY[flowx ? 1 : 0], gapSize);
}
// add the row/column so that the gap in the last row/col will not be removed.
if (flowx) {
rowIndexes.add(cellXY[1]);
} else {
colIndexes.add(cellXY[0]);
}
}
/** Sort components (normally buttons in a button bar) so they appear in the correct order.
* @param cells The cells to sort.
* @param parent The parent.
*/
private static void sortCellsByPlatform(Collection cells, ContainerWrapper parent)
{
String order = PlatformDefaults.getButtonOrder();
String orderLo = order.toLowerCase();
int unrelSize = PlatformDefaults.convertToPixels(1, "u", true, 0, parent, null);
if (unrelSize == UnitConverter.UNABLE)
throw new IllegalArgumentException("'unrelated' not recognized by PlatformDefaults!");
int[] gapUnrel = new int[] {unrelSize, unrelSize, LayoutUtil.NOT_SET};
int[] flGap = new int[] {0, 0, LayoutUtil.NOT_SET};
for (Cell cell : cells) {
if (cell.hasTagged == false)
continue;
CompWrap prevCW = null;
boolean nextUnrel = false;
boolean nextPush = false;
ArrayList sortedList = new ArrayList(cell.compWraps.size());
for (int i = 0, iSz = orderLo.length(); i < iSz; i++) {
char c = orderLo.charAt(i);
if (c == '+' || c == '_') {
nextUnrel = true;
if (c == '+')
nextPush = true;
} else {
String tag = PlatformDefaults.getTagForChar(c);
if (tag != null) {
for (int j = 0, jSz = cell.compWraps.size(); j < jSz; j++) {
CompWrap cw = cell.compWraps.get(j);
if (tag.equals(cw.cc.getTag())) {
if (Character.isUpperCase(order.charAt(i)))
cw.adjustMinHorSizeUp((int) PlatformDefaults.getMinimumButtonWidthIncludingPadding(0, parent, cw.comp));
sortedList.add(cw);
if (nextUnrel) {
(prevCW != null ? prevCW : cw).mergeGapSizes(gapUnrel, cell.flowx, prevCW == null);
if (nextPush) {
cw.forcedPushGaps = 1;
nextUnrel = false;
nextPush = false;
}
}
// "unknown" components will always get an Unrelated gap.
if (c == 'u')
nextUnrel = true;
prevCW = cw;
}
}
}
}
}
// If we have a gap that was supposed to push but no more components was found to but the "gap before" then compensate.
if (sortedList.size() > 0) {
CompWrap cw = sortedList.get(sortedList.size() - 1);
if (nextUnrel) {
cw.mergeGapSizes(gapUnrel, cell.flowx, false);
if (nextPush)
cw.forcedPushGaps |= 2;
}
// Remove first and last gap if not set explicitly.
if (cw.cc.getHorizontal().getGapAfter() == null)
cw.setGaps(flGap, 3);
cw = sortedList.get(0);
if (cw.cc.getHorizontal().getGapBefore() == null)
cw.setGaps(flGap, 1);
}
// Exchange the unsorted CompWraps for the sorted one.
if (cell.compWraps.size() == sortedList.size()) {
cell.compWraps.clear();
} else {
cell.compWraps.removeAll(sortedList);
}
cell.compWraps.addAll(sortedList);
}
}
private Float[] getDefaultPushWeights(boolean isRows)
{
ArrayList[] groupLists = isRows ? rowGroupLists : colGroupLists;
Float[] pushWeightArr = GROW_100; // Only create specific if any of the components have grow.
for (int i = 0, ix = 1; i < groupLists.length; i++, ix += 2) {
ArrayList grps = groupLists[i];
Float rowPushWeight = null;
for (LinkedDimGroup grp : grps) {
for (int c = 0; c < grp._compWraps.size(); c++) {
CompWrap cw = grp._compWraps.get(c);
int hideMode = cw.comp.isVisible() ? -1 : cw.cc.getHideMode() != -1 ? cw.cc.getHideMode() : lc.getHideMode();
Float pushWeight = hideMode < 2 ? (isRows ? cw.cc.getPushY() : cw.cc.getPushX()) : null;
if (rowPushWeight == null || (pushWeight != null && pushWeight.floatValue() > rowPushWeight.floatValue()))
rowPushWeight = pushWeight;
}
}
if (rowPushWeight != null) {
if (pushWeightArr == GROW_100)
pushWeightArr = new Float[(groupLists.length << 1) + 1];
pushWeightArr[ix] = rowPushWeight;
}
}
return pushWeightArr;
}
private void clearGroupLinkBounds()
{
if (linkTargetIDs == null)
return;
for (Map.Entry o : linkTargetIDs.entrySet()) {
if (o.getValue() == Boolean.TRUE)
LinkHandler.clearBounds(container.getLayout(), o.getKey());
}
}
private void resetLinkValues(boolean parentSize, boolean compLinks)
{
Object lay = container.getLayout();
if (compLinks)
LinkHandler.clearTemporaryBounds(lay);
boolean defIns = !hasDocks();
int parW = parentSize ? lc.getWidth().constrain(container.getWidth(), getParentSize(container, true), container) : 0;
int parH = parentSize ? lc.getHeight().constrain(container.getHeight(), getParentSize(container, false), container) : 0;
int insX = LayoutUtil.getInsets(lc, 0, defIns).getPixels(0, container, null);
int insY = LayoutUtil.getInsets(lc, 1, defIns).getPixels(0, container, null);
int visW = parW - insX - LayoutUtil.getInsets(lc, 2, defIns).getPixels(0, container, null);
int visH = parH - insY - LayoutUtil.getInsets(lc, 3, defIns).getPixels(0, container, null);
LinkHandler.setBounds(lay, "visual", insX, insY, visW, visH, true, false);
LinkHandler.setBounds(lay, "container", 0, 0, parW, parH, true, false);
}
/** Returns the {@link net.miginfocom.layout.Grid.LinkedDimGroup} that has the {@link net.miginfocom.layout.Grid.CompWrap}
* cw.
* @param groupLists The lists to search in.
* @param cw The component wrap to find.
* @return The linked group or null if none had the component wrap.
*/
private static LinkedDimGroup getGroupContaining(ArrayList[] groupLists, CompWrap cw)
{
for (ArrayList groups : groupLists) {
for (int j = 0, jSz = groups.size(); j < jSz; j++) {
ArrayList cwList = groups.get(j)._compWraps;
for (int k = 0, kSz = cwList.size(); k < kSz; k++) {
if (cwList.get(k) == cw)
return groups.get(j);
}
}
}
return null;
}
private boolean doAbsoluteCorrections(CompWrap cw, int[] bounds)
{
boolean changed = false;
int[] stSz = getAbsoluteDimBounds(cw, bounds[2], true);
if (stSz != null)
cw.setDimBounds(stSz[0], stSz[1], true);
stSz = getAbsoluteDimBounds(cw, bounds[3], false);
if (stSz != null)
cw.setDimBounds(stSz[0], stSz[1], false);
// If there is a link id, store the new bounds.
if (linkTargetIDs != null)
changed = setLinkedBounds(cw.comp, cw.cc, cw.x, cw.y, cw.w, cw.h, false);
return changed;
}
/** Adjust grid's width or height for the absolute components' positions.
*/
private void adjustSizeForAbsolute(boolean isHor)
{
int[] curSizes = isHor ? width : height;
Cell absCell = grid.get(null);
if (absCell == null || absCell.compWraps.size() == 0)
return;
ArrayList cws = absCell.compWraps;
int maxEnd = 0;
for (int j = 0, cwSz = absCell.compWraps.size(); j < cwSz + 3; j++) { // "Do Again" max absCell.compWraps.size() + 3 times.
boolean doAgain = false;
for (int i = 0; i < cwSz; i++) {
CompWrap cw = cws.get(i);
int[] stSz = getAbsoluteDimBounds(cw, 0, isHor);
int end = stSz[0] + stSz[1];
if (maxEnd < end)
maxEnd = end;
// If there is a link id, store the new bounds.
if (linkTargetIDs != null)
doAgain |= setLinkedBounds(cw.comp, cw.cc, stSz[0], stSz[0], stSz[1], stSz[1], false);
}
if (doAgain == false)
break;
// We need to check this again since the coords may be smaller this round.
maxEnd = 0;
clearGroupLinkBounds();
}
maxEnd += LayoutUtil.getInsets(lc, isHor ? 3 : 2, !hasDocks()).getPixels(0, container, null);
if (curSizes[LayoutUtil.MIN] < maxEnd)
curSizes[LayoutUtil.MIN] = maxEnd;
if (curSizes[LayoutUtil.PREF] < maxEnd)
curSizes[LayoutUtil.PREF] = maxEnd;
}
private int[] getAbsoluteDimBounds(CompWrap cw, int refSize, boolean isHor)
{
if (cw.cc.isExternal()) {
if (isHor) {
return new int[] {cw.comp.getX(), cw.comp.getWidth()};
} else {
return new int[] {cw.comp.getY(), cw.comp.getHeight()};
}
}
UnitValue[] pad = cw.cc.getPadding();
// If no changes do not create a lot of objects
UnitValue[] pos = getPos(cw.comp, cw.cc);
if (pos == null && pad == null)
return null;
// Set start
int st = isHor ? cw.x : cw.y;
int sz = isHor ? cw.w : cw.h;
// If absolute, use those coordinates instead.
if (pos != null) {
UnitValue stUV = pos != null ? pos[isHor ? 0 : 1] : null;
UnitValue endUV = pos != null ? pos[isHor ? 2 : 3] : null;
int minSz = cw.getSize(LayoutUtil.MIN, isHor);
int maxSz = cw.getSize(LayoutUtil.MAX, isHor);
sz = Math.min(Math.max(cw.getSize(LayoutUtil.PREF, isHor), minSz), maxSz);
if (stUV != null) {
st = stUV.getPixels(stUV.getUnit() == UnitValue.ALIGN ? sz : refSize, container, cw.comp);
if (endUV != null) // if (endUV == null && cw.cc.isBoundsIsGrid() == true)
sz = Math.min(Math.max((isHor ? (cw.x + cw.w) : (cw.y + cw.h)) - st, minSz), maxSz);
}
if (endUV != null) {
if (stUV != null) { // if (stUV != null || cw.cc.isBoundsIsGrid()) {
sz = Math.min(Math.max(endUV.getPixels(refSize, container, cw.comp) - st, minSz), maxSz);
} else {
st = endUV.getPixels(refSize, container, cw.comp) - sz;
}
}
}
// If constraint has padding -> correct the start/size
if (pad != null) {
UnitValue uv = pad[isHor ? 1 : 0];
int p = uv != null ? uv.getPixels(refSize, container, cw.comp) : 0;
st += p;
uv = pad[isHor ? 3 : 2];
sz += -p + (uv != null ? uv.getPixels(refSize, container, cw.comp) : 0);
}
return new int[] {st, sz};
}
private void layoutInOneDim(int refSize, UnitValue align, boolean isRows, Float[] defaultPushWeights)
{
boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
FlowSizeSpec fss = isRows ? rowFlowSpecs : colFlowSpecs;
ArrayList[] rowCols = isRows ? rowGroupLists : colGroupLists;
int[] rowColSizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, defaultPushWeights, LayoutUtil.PREF, refSize);
if (LayoutUtil.isDesignTime(container)) {
TreeSet indexes = isRows ? rowIndexes : colIndexes;
int[] ixArr = new int[indexes.size()];
int ix = 0;
for (Integer i : indexes)
ixArr[ix++] = i;
putSizesAndIndexes(container.getComponent(), rowColSizes, ixArr, isRows);
}
int curPos = align != null ? align.getPixels(refSize - LayoutUtil.sum(rowColSizes), container, null) : 0;
if (fromEnd)
curPos = refSize - curPos;
for (int i = 0 ; i < rowCols.length; i++) {
ArrayList linkedGroups = rowCols[i];
int scIx = i - (isRows ? dockOffY : dockOffX);
int bIx = i << 1;
int bIx2 = bIx + 1;
curPos += (fromEnd ? -rowColSizes[bIx] : rowColSizes[bIx]);
DimConstraint primDC = scIx >= 0 ? primDCs[scIx >= primDCs.length ? primDCs.length - 1 : scIx] : DOCK_DIM_CONSTRAINT;
int rowSize = rowColSizes[bIx2];
for (LinkedDimGroup group : linkedGroups) {
int groupSize = rowSize;
if (group.span > 1)
groupSize = LayoutUtil.sum(rowColSizes, bIx2, Math.min((group.span << 1) - 1, rowColSizes.length - bIx2 - 1));
group.layout(primDC, curPos, groupSize, group.span);
}
curPos += (fromEnd ? -rowSize : rowSize);
}
}
private static void addToSizeGroup(HashMap sizeGroups, String sizeGroup, int[] size)
{
int[] sgSize = sizeGroups.get(sizeGroup);
if (sgSize == null) {
sizeGroups.put(sizeGroup, new int[] {size[LayoutUtil.MIN], size[LayoutUtil.PREF], size[LayoutUtil.MAX]});
} else {
sgSize[LayoutUtil.MIN] = Math.max(size[LayoutUtil.MIN], sgSize[LayoutUtil.MIN]);
sgSize[LayoutUtil.PREF] = Math.max(size[LayoutUtil.PREF], sgSize[LayoutUtil.PREF]);
sgSize[LayoutUtil.MAX] = Math.min(size[LayoutUtil.MAX], sgSize[LayoutUtil.MAX]);
}
}
private static HashMap addToEndGroup(HashMap endGroups, String endGroup, int end)
{
if (endGroup != null) {
if (endGroups == null)
endGroups = new HashMap(4);
Integer oldEnd = endGroups.get(endGroup);
if (oldEnd == null || end > oldEnd)
endGroups.put(endGroup, end);
}
return endGroups;
}
/** Calculates Min, Preferred and Max size for the columns OR rows.
* @param isHor If it is the horizontal dimension to calculate.
* @param containerSize The reference container size in the dimension. If <= 0 it will be replaced by the actual container's size.
* @return The sizes in a {@link net.miginfocom.layout.Grid.FlowSizeSpec}.
*/
private FlowSizeSpec calcRowsOrColsSizes(boolean isHor, int containerSize)
{
ArrayList[] groupsLists = isHor ? colGroupLists : rowGroupLists;
Float[] defPush = isHor ? pushXs : pushYs;
if (containerSize <= 0)
containerSize = isHor ? container.getWidth() : container.getHeight();
BoundSize cSz = isHor ? lc.getWidth() : lc.getHeight();
if (!cSz.isUnset())
containerSize = cSz.constrain(containerSize, getParentSize(container, isHor), container);
DimConstraint[] primDCs = (isHor? colConstr : rowConstr).getConstaints();
TreeSet primIndexes = isHor ? colIndexes : rowIndexes;
int[][] rowColBoundSizes = new int[primIndexes.size()][];
HashMap sizeGroupMap = new HashMap(4);
DimConstraint[] allDCs = new DimConstraint[primIndexes.size()];
Iterator primIt = primIndexes.iterator();
for (int r = 0; r < rowColBoundSizes.length; r++) {
int cellIx = primIt.next();
int[] rowColSizes = new int[3];
if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID) { // If not dock cell
allDCs[r] = primDCs[cellIx >= primDCs.length ? primDCs.length - 1 : cellIx];
} else {
allDCs[r] = DOCK_DIM_CONSTRAINT;
}
ArrayList groups = groupsLists[r];
int[] groupSizes = new int[] {
getTotalGroupsSizeParallel(groups, LayoutUtil.MIN, false),
getTotalGroupsSizeParallel(groups, LayoutUtil.PREF, false),
LayoutUtil.INF};
correctMinMax(groupSizes);
BoundSize dimSize = allDCs[r].getSize();
for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
int rowColSize = groupSizes[sType];
UnitValue uv = dimSize.getSize(sType);
if (uv != null) {
// If the size of the column is a link to some other size, use that instead
int unit = uv.getUnit();
if (unit == UnitValue.PREF_SIZE) {
rowColSize = groupSizes[LayoutUtil.PREF];
} else if (unit == UnitValue.MIN_SIZE) {
rowColSize = groupSizes[LayoutUtil.MIN];
} else if (unit == UnitValue.MAX_SIZE) {
rowColSize = groupSizes[LayoutUtil.MAX];
} else {
rowColSize = uv.getPixels(containerSize, container, null);
}
} else if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID && rowColSize == 0) {
rowColSize = LayoutUtil.isDesignTime(container) ? LayoutUtil.getDesignTimeEmptySize() : 0; // Empty rows with no size set gets XX pixels if design time
}
rowColSizes[sType] = rowColSize;
}
correctMinMax(rowColSizes);
addToSizeGroup(sizeGroupMap, allDCs[r].getSizeGroup(), rowColSizes);
rowColBoundSizes[r] = rowColSizes;
}
// Set/equalize the size groups to same the values.
if (sizeGroupMap.size() > 0) {
for (int r = 0; r < rowColBoundSizes.length; r++) {
if (allDCs[r].getSizeGroup() != null)
rowColBoundSizes[r] = sizeGroupMap.get(allDCs[r].getSizeGroup());
}
}
// Add the gaps
ResizeConstraint[] resConstrs = getRowResizeConstraints(allDCs);
boolean[] fillInPushGaps = new boolean[allDCs.length + 1];
int[][] gapSizes = getRowGaps(allDCs, containerSize, isHor, fillInPushGaps);
FlowSizeSpec fss = mergeSizesGapsAndResConstrs(resConstrs, fillInPushGaps, rowColBoundSizes, gapSizes);
// Spanning components are not handled yet. Check and adjust the multi-row min/pref they enforce.
adjustMinPrefForSpanningComps(allDCs, defPush, fss, groupsLists);
return fss;
}
private static int getParentSize(ComponentWrapper cw, boolean isHor)
{
ContainerWrapper p = cw.getParent();
return p != null ? (isHor ? cw.getWidth() : cw.getHeight()) : 0;
}
private int[] getMinPrefMaxSumSize(boolean isHor, int[][] sizes)
{
int[] retSizes = new int[3];
BoundSize sz = isHor ? lc.getWidth() : lc.getHeight();
for (int i = 0; i < sizes.length; i++) {
if (sizes[i] != null) {
int[] size = sizes[i];
for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
if (sz.getSize(sType) != null) {
if (i == 0)
retSizes[sType] = sz.getSize(sType).getPixels(getParentSize(container, isHor), container, null);
} else {
int s = size[sType];
if (s != LayoutUtil.NOT_SET) {
if (sType == LayoutUtil.PREF) {
int bnd = size[LayoutUtil.MAX];
if (bnd != LayoutUtil.NOT_SET && bnd < s)
s = bnd;
bnd = size[LayoutUtil.MIN];
if (bnd > s) // Includes s == LayoutUtil.NOT_SET since < 0.
s = bnd;
}
retSizes[sType] += s; // MAX compensated below.
}
// So that MAX is always correct.
if (size[LayoutUtil.MAX] == LayoutUtil.NOT_SET || retSizes[LayoutUtil.MAX] > LayoutUtil.INF)
retSizes[LayoutUtil.MAX] = LayoutUtil.INF;
}
}
}
}
correctMinMax(retSizes);
return retSizes;
}
private static ResizeConstraint[] getRowResizeConstraints(DimConstraint[] specs)
{
ResizeConstraint[] resConsts = new ResizeConstraint[specs.length];
for (int i = 0; i < resConsts.length; i++)
resConsts[i] = specs[i].resize;
return resConsts;
}
private static ResizeConstraint[] getComponentResizeConstraints(ArrayList compWraps, boolean isHor)
{
ResizeConstraint[] resConsts = new ResizeConstraint[compWraps.size()];
for (int i = 0; i < resConsts.length; i++) {
CC fc = compWraps.get(i).cc;
resConsts[i] = fc.getDimConstraint(isHor).resize;
// Always grow docking components in the correct dimension.
int dock = fc.getDockSide();
if (isHor ? (dock == 0 || dock == 2) : (dock == 1 || dock == 3)) {
ResizeConstraint dc = resConsts[i];
resConsts[i] = new ResizeConstraint(dc.shrinkPrio, dc.shrink, dc.growPrio, ResizeConstraint.WEIGHT_100);
}
}
return resConsts;
}
private static boolean[] getComponentGapPush(ArrayList compWraps, boolean isHor)
{
// Make one element bigger and or the after gap with the next before gap.
boolean[] barr = new boolean[compWraps.size() + 1];
for (int i = 0; i < barr.length; i++) {
boolean push = i > 0 && compWraps.get(i - 1).isPushGap(isHor, false);
if (push == false && i < (barr.length - 1))
push = compWraps.get(i).isPushGap(isHor, true);
barr[i] = push;
}
return barr;
}
/** Returns the row gaps in pixel sizes. One more than there are specs sent in.
* @param specs
* @param refSize
* @param isHor
* @param fillInPushGaps If the gaps are pushing. NOTE! this argument will be filled in and thus changed!
* @return The row gaps in pixel sizes. One more than there are specs sent in.
*/
private int[][] getRowGaps(DimConstraint[] specs, int refSize, boolean isHor, boolean[] fillInPushGaps)
{
BoundSize defGap = isHor ? lc.getGridGapX() : lc.getGridGapY();
if (defGap == null)
defGap = isHor ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
int[] defGapArr = defGap.getPixelSizes(refSize, container, null);
boolean defIns = !hasDocks();
UnitValue firstGap = LayoutUtil.getInsets(lc, isHor ? 1 : 0, defIns);
UnitValue lastGap = LayoutUtil.getInsets(lc, isHor ? 3 : 2, defIns);
int[][] retValues = new int[specs.length + 1][];
for (int i = 0, wgIx = 0; i < retValues.length; i++) {
DimConstraint specBefore = i > 0 ? specs[i - 1] : null;
DimConstraint specAfter = i < specs.length ? specs[i] : null;
// No gap if between docking components.
boolean edgeBefore = (specBefore == DOCK_DIM_CONSTRAINT || specBefore == null);
boolean edgeAfter = (specAfter == DOCK_DIM_CONSTRAINT || specAfter == null);
if (edgeBefore && edgeAfter)
continue;
BoundSize wrapGapSize = (wrapGapMap == null || isHor == lc.isFlowX() ? null : wrapGapMap.get(Integer.valueOf(wgIx++)));
if (wrapGapSize == null) {
int[] gapBefore = specBefore != null ? specBefore.getRowGaps(container, null, refSize, false) : null;
int[] gapAfter = specAfter != null ? specAfter.getRowGaps(container, null, refSize, true) : null;
if (edgeBefore && gapAfter == null && firstGap != null) {
int bef = firstGap.getPixels(refSize, container, null);
retValues[i] = new int[] {bef, bef, bef};
} else if (edgeAfter && gapBefore == null && firstGap != null) {
int aft = lastGap.getPixels(refSize, container, null);
retValues[i] = new int[] {aft, aft, aft};
} else {
retValues[i] = gapAfter != gapBefore ? mergeSizes(gapAfter, gapBefore) : new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
}
if (specBefore != null && specBefore.isGapAfterPush() || specAfter != null && specAfter.isGapBeforePush())
fillInPushGaps[i] = true;
} else {
if (wrapGapSize.isUnset()) {
retValues[i] = new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
} else {
retValues[i] = wrapGapSize.getPixelSizes(refSize, container, null);
}
fillInPushGaps[i] = wrapGapSize.getGapPush();
}
}
return retValues;
}
private static int[][] getGaps(ArrayList compWraps, boolean isHor)
{
int compCount = compWraps.size();
int[][] retValues = new int[compCount + 1][];
retValues[0] = compWraps.get(0).getGaps(isHor, true);
for (int i = 0; i < compCount; i++) {
int[] gap1 = compWraps.get(i).getGaps(isHor, false);
int[] gap2 = i < compCount - 1 ? compWraps.get(i + 1).getGaps(isHor, true) : null;
retValues[i + 1] = mergeSizes(gap1, gap2);
}
return retValues;
}
private boolean hasDocks()
{
return (dockOffX > 0 || dockOffY > 0 || rowIndexes.last() > MAX_GRID || colIndexes.last() > MAX_GRID);
}
/** Adjust min/pref size for columns(or rows) that has components that spans multiple columns (or rows).
* @param specs The specs for the columns or rows. Last index will be used if count is greater than this array's length.
* @param defPush The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
* @param fss
* @param groupsLists
*/
private void adjustMinPrefForSpanningComps(DimConstraint[] specs, Float[] defPush, FlowSizeSpec fss, ArrayList[] groupsLists)
{
for (int r = groupsLists.length - 1; r >= 0; r--) { // Since 3.7.3 Iterate from end to start. Will solve some multiple spanning components hard to solve problems.
ArrayList groups = groupsLists[r];
for (LinkedDimGroup group : groups) {
if (group.span == 1)
continue;
int[] sizes = group.getMinPrefMax();
for (int s = LayoutUtil.MIN; s <= LayoutUtil.PREF; s++) {
int cSize = sizes[s];
if (cSize == LayoutUtil.NOT_SET)
continue;
int rowSize = 0;
int sIx = (r << 1) + 1;
int len = Math.min((group.span << 1), fss.sizes.length - sIx) - 1;
for (int j = sIx; j < sIx + len; j++) {
int sz = fss.sizes[j][s];
if (sz != LayoutUtil.NOT_SET)
rowSize += sz;
}
if (rowSize < cSize && len > 0) {
for (int eagerness = 0, newRowSize = 0; eagerness < 4 && newRowSize < cSize; eagerness++)
newRowSize = fss.expandSizes(specs, defPush, cSize, sIx, len, s, eagerness);
}
}
}
}
}
/** For one dimension divide the component wraps into logical groups. One group for component wraps that share a common something,
* line the property to layout by base line.
* @param isRows If rows, and not columns, are to be divided.
* @return One ArrayList for every row/column.
*/
private ArrayList[] divideIntoLinkedGroups(boolean isRows)
{
boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
TreeSet primIndexes = isRows ? rowIndexes : colIndexes;
TreeSet secIndexes = isRows ? colIndexes : rowIndexes;
DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
@SuppressWarnings("unchecked")
ArrayList[] groupLists = new ArrayList[primIndexes.size()];
int gIx = 0;
for (int i : primIndexes) {
DimConstraint dc;
if (i >= -MAX_GRID && i <= MAX_GRID) { // If not dock cell
dc = primDCs[i >= primDCs.length ? primDCs.length - 1 : i];
} else {
dc = DOCK_DIM_CONSTRAINT;
}
ArrayList groupList = new ArrayList(4);
groupLists[gIx++] = groupList;
for (Integer ix : secIndexes) {
Cell cell = isRows ? getCell(i, ix) : getCell(ix, i);
if (cell == null || cell.compWraps.size() == 0)
continue;
int span = (isRows ? cell.spany : cell.spanx);
if (span > 1)
span = convertSpanToSparseGrid(i, span, primIndexes);
boolean isPar = (cell.flowx == isRows);
if ((isPar == false && cell.compWraps.size() > 1) || span > 1) {
int linkType = isPar ? LinkedDimGroup.TYPE_PARALLEL : LinkedDimGroup.TYPE_SERIAL;
LinkedDimGroup lg = new LinkedDimGroup("p," + ix, span, linkType, !isRows, fromEnd);
lg.setCompWraps(cell.compWraps);
groupList.add(lg);
} else {
for (int cwIx = 0; cwIx < cell.compWraps.size(); cwIx++) {
CompWrap cw = cell.compWraps.get(cwIx);
boolean rowBaselineAlign = (isRows && lc.isTopToBottom() && dc.getAlignOrDefault(!isRows) == UnitValue.BASELINE_IDENTITY); // Disable baseline for bottomToTop since I can not verify it working.
boolean isBaseline = isRows && cw.isBaselineAlign(rowBaselineAlign);
String linkCtx = isBaseline ? "baseline" : null;
// Find a group with same link context and put it in that group.
boolean foundList = false;
for (int glIx = 0, lastGl = groupList.size() - 1; glIx <= lastGl; glIx++) {
LinkedDimGroup group = groupList.get(glIx);
if (group.linkCtx == linkCtx || linkCtx != null && linkCtx.equals(group.linkCtx)) {
group.addCompWrap(cw);
foundList = true;
break;
}
}
// If none found and at last add a new group.
if (foundList == false) {
int linkType = isBaseline ? LinkedDimGroup.TYPE_BASELINE : LinkedDimGroup.TYPE_PARALLEL;
LinkedDimGroup lg = new LinkedDimGroup(linkCtx, 1, linkType, !isRows, fromEnd);
lg.addCompWrap(cw);
groupList.add(lg);
}
}
}
}
}
return groupLists;
}
/** Spanning is specified in the uncompressed grid number. They can for instance be more than 60000 for the outer
* edge dock grid cells. When the grid is compressed and indexed after only the cells that area occupied the span
* is erratic. This method use the row/col indexes and corrects the span to be correct for the compressed grid.
* @param span The span in the uncompressed grid. LayoutUtil.INF will be interpreted to span the rest
* of the column/row excluding the surrounding docking components.
* @param indexes The indexes in the correct dimension.
* @return The converted span.
*/
private static int convertSpanToSparseGrid(int curIx, int span, TreeSet indexes)
{
int lastIx = curIx + span;
int retSpan = 1;
for (Integer ix : indexes) {
if (ix <= curIx)
continue; // We have not arrived to the correct index yet
if (ix >= lastIx)
break;
retSpan++;
}
return retSpan;
}
private boolean isCellFree(int r, int c, ArrayList occupiedRects)
{
if (getCell(r, c) != null)
return false;
for (int[] rect : occupiedRects) {
if (rect[0] <= c && rect[1] <= r && rect[0] + rect[2] > c && rect[1] + rect[3] > r)
return false;
}
return true;
}
private Cell getCell(int r, int c)
{
return grid.get(Integer.valueOf((r << 16) + (c & 0xffff)));
}
private void setCell(int r, int c, Cell cell)
{
if (c < 0 || r < 0)
throw new IllegalArgumentException("Cell position cannot be negative. row: " + r + ", col: " + c);
if (c > MAX_GRID || r > MAX_GRID)
throw new IllegalArgumentException("Cell position out of bounds. Out of cells. row: " + r + ", col: " + c);
rowIndexes.add(r);
colIndexes.add(c);
grid.put((r << 16) + (c & 0xffff), cell);
}
/** Adds a docking cell. That cell is outside the normal cell indexes.
* @param dockInsets The current dock insets. Will be updated!
* @param side top == 0, left == 1, bottom = 2, right = 3.
* @param cw The compwrap to put in a cell and add.
*/
private void addDockingCell(int[] dockInsets, int side, CompWrap cw)
{
int r, c, spanx = 1, spany = 1;
switch (side) {
case 0:
case 2:
r = side == 0 ? dockInsets[0]++ : dockInsets[2]--;
c = dockInsets[1];
spanx = dockInsets[3] - dockInsets[1] + 1; // The +1 is for cell 0.
colIndexes.add(dockInsets[3]); // Make sure there is a receiving cell
break;
case 1:
case 3:
c = side == 1 ? dockInsets[1]++ : dockInsets[3]--;
r = dockInsets[0];
spany = dockInsets[2] - dockInsets[0] + 1; // The +1 is for cell 0.
rowIndexes.add(dockInsets[2]); // Make sure there is a receiving cell
break;
default:
throw new IllegalArgumentException("Internal error 123.");
}
rowIndexes.add(r);
colIndexes.add(c);
grid.put((r << 16) + (c & 0xffff), new Cell(cw, spanx, spany, spanx > 1));
}
/** A simple representation of a cell in the grid. Contains a number of component wraps, if they span more than one cell.
*/
private static class Cell
{
private final int spanx, spany;
private final boolean flowx;
private final ArrayList compWraps = new ArrayList(2);
private boolean hasTagged = false; // If one or more components have styles and need to be checked by the component sorter
private Cell(CompWrap cw)
{
this(cw, 1, 1, true);
}
private Cell(int spanx, int spany, boolean flowx)
{
this(null, spanx, spany, flowx);
}
private Cell(CompWrap cw, int spanx, int spany, boolean flowx)
{
if (cw != null)
compWraps.add(cw);
this.spanx = spanx;
this.spany = spany;
this.flowx = flowx;
}
}
/** A number of component wraps that share a layout "something" in one dimension
*/
private static class LinkedDimGroup
{
private static final int TYPE_SERIAL = 0;
private static final int TYPE_PARALLEL = 1;
private static final int TYPE_BASELINE = 2;
private final String linkCtx;
private final int span;
private final int linkType;
private final boolean isHor, fromEnd;
private final ArrayList _compWraps = new ArrayList(4);
private int lStart = 0, lSize = 0; // Currently mostly for debug painting
private LinkedDimGroup(String linkCtx, int span, int linkType, boolean isHor, boolean fromEnd)
{
this.linkCtx = linkCtx;
this.span = span;
this.linkType = linkType;
this.isHor = isHor;
this.fromEnd = fromEnd;
}
private void addCompWrap(CompWrap cw)
{
_compWraps.add(cw);
}
private void setCompWraps(ArrayList cws)
{
if (_compWraps != cws) {
_compWraps.clear();
_compWraps.addAll(cws);
}
}
private void layout(DimConstraint dc, int start, int size, int spanCount)
{
lStart = start;
lSize = size;
if (_compWraps.isEmpty())
return;
ContainerWrapper parent = _compWraps.get(0).comp.getParent();
if (linkType == TYPE_PARALLEL) {
layoutParallel(parent, _compWraps, dc, start, size, isHor, fromEnd);
} else if (linkType == TYPE_BASELINE) {
layoutBaseline(parent, _compWraps, dc, start, size, LayoutUtil.PREF, spanCount);
} else {
layoutSerial(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
}
}
/** Returns the min/pref/max sizes for this cell. Returned array must not be altered
* @return A shared min/pref/max array of sizes. Always of length 3 and never null. Will always be of type STATIC and PIXEL.
*/
private int[] getMinPrefMax()
{
int[] sizes = new int[3];
if (!_compWraps.isEmpty()) {
for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.PREF; sType++) {
if (linkType == TYPE_PARALLEL) {
sizes[sType] = getTotalSizeParallel(_compWraps, sType, isHor);
} else if (linkType == TYPE_BASELINE) {
int[] aboveBelow = getBaselineAboveBelow(_compWraps, sType, false);
sizes[sType] = aboveBelow[0] + aboveBelow[1];
} else {
sizes[sType] = getTotalSizeSerial(_compWraps, sType, isHor);
}
}
sizes[LayoutUtil.MAX] = LayoutUtil.INF;
}
return sizes;
}
}
/** Wraps a {@link java.awt.Component} together with its constraint. Caches a lot of information about the component so
* for instance not the preferred size has to be calculated more than once.
*
* Note! Does not ask the min/pref/max sizes again after the constructor. This means that
*/
private final class CompWrap
{
private final ComponentWrapper comp;
private final CC cc;
private final int eHideMode;
private final boolean useVisualPadding;
private boolean sizesOk = false;
private boolean isAbsolute;
private int[][] gaps; // [top,left(actually before),bottom,right(actually after)][min,pref,max]
private final int[] horSizes = new int[3];
private final int[] verSizes = new int[3];
private int x = LayoutUtil.NOT_SET, y = LayoutUtil.NOT_SET, w = LayoutUtil.NOT_SET, h = LayoutUtil.NOT_SET;
private int forcedPushGaps = 0; // 1 == before, 2 = after. Bitwise.
/**
* @param c
* @param cc
* @param eHideMode Effective hide mode. <= 0 means visible.
* @param useVisualPadding
*/
private CompWrap(ComponentWrapper c, CC cc, int eHideMode, boolean useVisualPadding)
{
this.comp = c;
this.cc = cc;
this.eHideMode = eHideMode;
this.useVisualPadding = useVisualPadding;
this.isAbsolute = cc.getHorizontal().getSize().isAbsolute() && cc.getVertical().getSize().isAbsolute();
if (eHideMode > 1) {
gaps = new int[4][];
for (int i = 0; i < gaps.length; i++)
gaps[i] = new int[3];
}
}
private int[] getSizes(boolean isHor)
{
validateSize();
return isHor ? horSizes : verSizes;
}
private void validateSize()
{
BoundSize[] callbackSz = getCallbackSize(comp);
if (isAbsolute && sizesOk && callbackSz == null)
return;
if (eHideMode <= 0) {
int contentBias = comp.getContentBias();
int sizeHint = contentBias == -1 ? -1 : (contentBias == 0 ? (w != LayoutUtil.NOT_SET ? w : comp.getWidth()) : (h != LayoutUtil.NOT_SET ? h : comp.getHeight()));
BoundSize hBS = (callbackSz != null && callbackSz[0] != null) ? callbackSz[0] : cc.getHorizontal().getSize();
BoundSize vBS = (callbackSz != null && callbackSz[1] != null) ? callbackSz[1] : cc.getVertical().getSize();
for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
switch (contentBias) {
case -1: // None
default:
horSizes[i] = getSize(hBS, i, true, useVisualPadding, -1);
verSizes[i] = getSize(vBS, i, false, useVisualPadding, -1);
break;
case 0: // Hor
horSizes[i] = getSize(hBS, i, true, useVisualPadding, -1);
verSizes[i] = getSize(vBS, i, false, useVisualPadding, sizeHint > 0 ? sizeHint : horSizes[i]);
break;
case 1: // Ver
verSizes[i] = getSize(vBS, i, false, useVisualPadding, -1);
horSizes[i] = getSize(hBS, i, true, useVisualPadding, sizeHint > 0 ? sizeHint : verSizes[i]);
break;
}
}
correctMinMax(horSizes);
correctMinMax(verSizes);
} else {
Arrays.fill(horSizes, 0); // Needed if component goes from visible -> invisible without recreating the grid.
Arrays.fill(verSizes, 0);
}
sizesOk = true;
}
private int getSize(BoundSize uvs, int sizeType, boolean isHor, boolean useVP, int sizeHint)
{
int size;
if (uvs == null || uvs.getSize(sizeType) == null) {
switch(sizeType) {
case LayoutUtil.MIN:
size = isHor ? comp.getMinimumWidth(sizeHint) : comp.getMinimumHeight(sizeHint);
break;
case LayoutUtil.PREF:
size = isHor ? comp.getPreferredWidth(sizeHint) : comp.getPreferredHeight(sizeHint);
break;
default:
size = isHor ? comp.getMaximumWidth(sizeHint) : comp.getMaximumHeight(sizeHint);
break;
}
if (useVP) {
//Do not include visual padding when calculating layout
int[] visualPadding = comp.getVisualPadding();
// Assume visualPadding is of length 4: top, left, bottom, right
if (visualPadding != null && visualPadding.length > 0)
size -= isHor ? (visualPadding[1] + visualPadding[3]) : (visualPadding[0] + visualPadding[2]);
}
} else {
ContainerWrapper par = comp.getParent();
float refValue = isHor ? par.getWidth() : par.getHeight();
size = uvs.getSize(sizeType).getPixels(refValue, par, comp);
}
return size;
}
private void calcGaps(ComponentWrapper before, CC befCC, ComponentWrapper after, CC aftCC, String tag, boolean flowX, boolean isLTR)
{
ContainerWrapper par = comp.getParent();
int parW = par.getWidth();
int parH = par.getHeight();
BoundSize befGap = before != null ? (flowX ? befCC.getHorizontal() : befCC.getVertical()).getGapAfter() : null;
BoundSize aftGap = after != null ? (flowX ? aftCC.getHorizontal() : aftCC.getVertical()).getGapBefore() : null;
mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, befGap, (flowX ? null : before), tag, parH, 0, isLTR), false, true);
mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, befGap, (flowX ? before : null), tag, parW, 1, isLTR), true, true);
mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, aftGap, (flowX ? null : after), tag, parH, 2, isLTR), false, false);
mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, aftGap, (flowX ? after : null), tag, parW, 3, isLTR), true, false);
}
private void setDimBounds(int start, int size, boolean isHor)
{
if (isHor) {
if (start != x || w != size) {
x = start;
w = size;
if (comp.getContentBias() == LayoutUtil.HORIZONTAL)
invalidateSizes(); // Only for components that have a bias the sizes will have changed.
}
} else {
if (start != y || h != size) {
y = start;
h = size;
if (comp.getContentBias() == LayoutUtil.VERTICAL)
invalidateSizes(); // Only for components that have a bias the sizes will have changed.
}
}
}
void invalidateSizes()
{
sizesOk = false;
}
private boolean isPushGap(boolean isHor, boolean isBefore)
{
if (isHor && ((isBefore ? 1 : 2) & forcedPushGaps) != 0)
return true; // Forced
DimConstraint dc = cc.getDimConstraint(isHor);
BoundSize s = isBefore ? dc.getGapBefore() : dc.getGapAfter();
return s != null && s.getGapPush();
}
/** Transfers the bounds to the component
*/
private void transferBounds(boolean addVisualPadding)
{
if (cc.isExternal())
return;
int compX = x;
int compY = y;
int compW = w;
int compH = h;
if (addVisualPadding) {
//Add the visual padding back to the component when changing its size
int[] visualPadding = comp.getVisualPadding();
if (visualPadding != null) {
//assume visualPadding is of length 4: top, left, bottom, right
compX -= visualPadding[1];
compY -= visualPadding[0];
compW += (visualPadding[1] + visualPadding[3]);
compH += (visualPadding[0] + visualPadding[2]);
}
}
comp.setBounds(compX, compY, compW, compH);
}
private void setForcedSizes(int[] sizes, boolean isHor)
{
if (sizes == null)
return;
System.arraycopy(sizes, 0, getSizes(isHor), 0, 3);
sizesOk = true;
}
private void setGaps(int[] minPrefMax, int ix)
{
if (gaps == null)
gaps = new int[][] {null, null, null, null};
gaps[ix] = minPrefMax;
}
private void mergeGapSizes(int[] sizes, boolean isHor, boolean isTL)
{
if (gaps == null)
gaps = new int[][] {null, null, null, null};
if (sizes == null)
return;
int gapIX = getGapIx(isHor, isTL);
int[] oldGaps = gaps[gapIX];
if (oldGaps == null) {
oldGaps = new int[] {0, 0, LayoutUtil.INF};
gaps[gapIX] = oldGaps;
}
oldGaps[LayoutUtil.MIN] = Math.max(sizes[LayoutUtil.MIN], oldGaps[LayoutUtil.MIN]);
oldGaps[LayoutUtil.PREF] = Math.max(sizes[LayoutUtil.PREF], oldGaps[LayoutUtil.PREF]);
oldGaps[LayoutUtil.MAX] = Math.min(sizes[LayoutUtil.MAX], oldGaps[LayoutUtil.MAX]);
}
private int getGapIx(boolean isHor, boolean isTL)
{
return isHor ? (isTL ? 1 : 3) : (isTL ? 0 : 2);
}
private int getSizeInclGaps(int sizeType, boolean isHor)
{
return filter(sizeType, getGapBefore(sizeType, isHor) + getSize(sizeType, isHor) + getGapAfter(sizeType, isHor));
}
private int getSize(int sizeType, boolean isHor)
{
return filter(sizeType, getSizes(isHor)[sizeType]);
}
private int getGapBefore(int sizeType, boolean isHor)
{
int[] gaps = getGaps(isHor, true);
return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
}
private int getGapAfter(int sizeType, boolean isHor)
{
int[] gaps = getGaps(isHor, false);
return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
}
private int[] getGaps(boolean isHor, boolean isTL)
{
return gaps[getGapIx(isHor, isTL)];
}
private int filter(int sizeType, int size)
{
if (size == LayoutUtil.NOT_SET)
return sizeType != LayoutUtil.MAX ? 0 : LayoutUtil.INF;
return constrainSize(size);
}
private boolean isBaselineAlign(boolean defValue)
{
Float g = cc.getVertical().getGrow();
if (g != null && g.intValue() != 0)
return false;
UnitValue al = cc.getVertical().getAlign();
return (al != null ? al == UnitValue.BASELINE_IDENTITY : defValue) && comp.hasBaseline();
}
private int getBaseline(int sizeType)
{
return comp.getBaseline(getSize(sizeType, true), getSize(sizeType, false));
}
public void adjustMinHorSizeUp(int minSize)
{
int[] sz = getSizes(true);
if (sz[LayoutUtil.MIN] < minSize)
sz[LayoutUtil.MIN] = minSize;
correctMinMax(sz);
}
}
//***************************************************************************************
//* Helper Methods
//***************************************************************************************
private static void layoutBaseline(ContainerWrapper parent, ArrayList compWraps, DimConstraint dc, int start, int size, int sizeType, int spanCount)
{
int[] aboveBelow = getBaselineAboveBelow(compWraps, sizeType, true);
int blRowSize = aboveBelow[0] + aboveBelow[1];
CC cc = compWraps.get(0).cc;
// Align for the whole baseline component array
UnitValue align = cc.getVertical().getAlign();
if (spanCount == 1 && align == null)
align = dc.getAlignOrDefault(false);
if (align == UnitValue.BASELINE_IDENTITY)
align = UnitValue.CENTER;
int offset = start + aboveBelow[0] + (align != null ? Math.max(0, align.getPixels(size - blRowSize, parent, null)) : 0);
for (CompWrap cw : compWraps) {
cw.y += offset;
if (cw.y + cw.h > start + size)
cw.h = start + size - cw.y;
}
}
private static void layoutSerial(ContainerWrapper parent, ArrayList compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
{
FlowSizeSpec fss = mergeSizesGapsAndResConstrs(
getComponentResizeConstraints(compWraps, isHor),
getComponentGapPush(compWraps, isHor),
getComponentSizes(compWraps, isHor),
getGaps(compWraps, isHor));
Float[] pushW = dc.isFill() ? GROW_100 : null;
int[] sizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, pushW, LayoutUtil.PREF, size);
setCompWrapBounds(parent, sizes, compWraps, dc.getAlignOrDefault(isHor), start, size, isHor, fromEnd);
}
private static void setCompWrapBounds(ContainerWrapper parent, int[] allSizes, ArrayList compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
{
int totSize = LayoutUtil.sum(allSizes);
CC cc = compWraps.get(0).cc;
UnitValue align = correctAlign(cc, rowAlign, isHor, fromEnd);
int cSt = start;
int slack = size - totSize;
if (slack > 0 && align != null) {
int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
cSt += (fromEnd ? -al : al);
}
for (int i = 0, bIx = 0, iSz = compWraps.size(); i < iSz; i++) {
CompWrap cw = compWraps.get(i);
if (fromEnd ) {
cSt -= allSizes[bIx++];
cw.setDimBounds(cSt - allSizes[bIx], allSizes[bIx], isHor);
cSt -= allSizes[bIx++];
} else {
cSt += allSizes[bIx++];
cw.setDimBounds(cSt, allSizes[bIx], isHor);
cSt += allSizes[bIx++];
}
}
}
private static void layoutParallel(ContainerWrapper parent, ArrayList compWraps, DimConstraint dc, int start, int size, boolean isHor, boolean fromEnd)
{
int[][] sizes = new int[compWraps.size()][]; // [compIx][gapBef,compSize,gapAft]
for (int i = 0; i < sizes.length; i++) {
CompWrap cw = compWraps.get(i);
DimConstraint cDc = cw.cc.getDimConstraint(isHor);
ResizeConstraint[] resConstr = new ResizeConstraint[] {
cw.isPushGap(isHor, true) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
cDc.resize,
cw.isPushGap(isHor, false) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
};
int[][] sz = new int[][] {
cw.getGaps(isHor, true), cw.getSizes(isHor), cw.getGaps(isHor, false)
};
Float[] pushW = dc.isFill() ? GROW_100 : null;
sizes[i] = LayoutUtil.calculateSerial(sz, resConstr, pushW, LayoutUtil.PREF, size);
}
UnitValue rowAlign = dc.getAlignOrDefault(isHor);
setCompWrapBounds(parent, sizes, compWraps, rowAlign, start, size, isHor, fromEnd);
}
private static void setCompWrapBounds(ContainerWrapper parent, int[][] sizes, ArrayList compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
{
for (int i = 0; i < sizes.length; i++) {
CompWrap cw = compWraps.get(i);
UnitValue align = correctAlign(cw.cc, rowAlign, isHor, fromEnd);
int[] cSizes = sizes[i];
int gapBef = cSizes[0];
int cSize = cSizes[1]; // No Math.min(size, cSizes[1]) here!
int gapAft = cSizes[2];
int cSt = fromEnd ? start - gapBef : start + gapBef;
int slack = size - cSize - gapBef - gapAft;
if (slack > 0 && align != null) {
int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
cSt += (fromEnd ? -al : al);
}
cw.setDimBounds(fromEnd ? cSt - cSize : cSt, cSize, isHor);
}
}
private static UnitValue correctAlign(CC cc, UnitValue rowAlign, boolean isHor, boolean fromEnd)
{
UnitValue align = (isHor ? cc.getHorizontal() : cc.getVertical()).getAlign();
if (align == null)
align = rowAlign;
if (align == UnitValue.BASELINE_IDENTITY)
align = UnitValue.CENTER;
if (fromEnd) {
if (align == UnitValue.LEFT)
align = UnitValue.RIGHT;
else if (align == UnitValue.RIGHT)
align = UnitValue.LEFT;
}
return align;
}
private static int[] getBaselineAboveBelow(ArrayList compWraps, int sType, boolean centerBaseline)
{
int maxAbove = Integer.MIN_VALUE;
int maxBelow = Integer.MIN_VALUE;
for (CompWrap cw : compWraps) {
int height = cw.getSize(sType, false);
if (height >= LayoutUtil.INF)
return new int[]{LayoutUtil.INF / 2, LayoutUtil.INF / 2};
int baseline = cw.getBaseline(sType);
int above = baseline + cw.getGapBefore(sType, false);
maxAbove = Math.max(above, maxAbove);
maxBelow = Math.max(height - baseline + cw.getGapAfter(sType, false), maxBelow);
if (centerBaseline)
cw.setDimBounds(-baseline, height, false);
}
return new int[] {maxAbove, maxBelow};
}
private static int getTotalSizeParallel(ArrayList compWraps, int sType, boolean isHor)
{
int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
for (CompWrap cw : compWraps) {
int cwSize = cw.getSizeInclGaps(sType, isHor);
if (cwSize >= LayoutUtil.INF)
return LayoutUtil.INF;
if (sType == LayoutUtil.MAX ? cwSize < size : cwSize > size)
size = cwSize;
}
return constrainSize(size);
}
private static int getTotalSizeSerial(ArrayList compWraps, int sType, boolean isHor)
{
int totSize = 0;
for (int i = 0, iSz = compWraps.size(), lastGapAfter = 0; i < iSz; i++) {
CompWrap wrap = compWraps.get(i);
int gapBef = wrap.getGapBefore(sType, isHor);
if (gapBef > lastGapAfter)
totSize += gapBef - lastGapAfter;
totSize += wrap.getSize(sType, isHor);
totSize += (lastGapAfter = wrap.getGapAfter(sType, isHor));
if (totSize >= LayoutUtil.INF)
return LayoutUtil.INF;
}
return constrainSize(totSize);
}
private static int getTotalGroupsSizeParallel(ArrayList groups, int sType, boolean countSpanning)
{
int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
for (LinkedDimGroup group : groups) {
if (countSpanning || group.span == 1) {
int grpSize = group.getMinPrefMax()[sType];
if (grpSize >= LayoutUtil.INF)
return LayoutUtil.INF;
if (sType == LayoutUtil.MAX ? grpSize < size : grpSize > size)
size = grpSize;
}
}
return constrainSize(size);
}
/**
* @param compWraps
* @param isHor
* @return Might contain LayoutUtil.NOT_SET
*/
private static int[][] getComponentSizes(ArrayList compWraps, boolean isHor)
{
int[][] compSizes = new int[compWraps.size()][];
for (int i = 0; i < compSizes.length; i++)
compSizes[i] = compWraps.get(i).getSizes(isHor);
return compSizes;
}
/** Merges sizes and gaps together with Resize Constraints. For gaps {@link #GAP_RC_CONST} is used.
* @param resConstr One resize constraint for every row/component. Can be lesser in length and the last element should be used for missing elements.
* @param gapPush If the corresponding gap should be considered pushing and thus want to take free space if left over. Should be one more than resConstrs!
* @param minPrefMaxSizes The sizes (min/pref/max) for every row/component.
* @param gapSizes The gaps before and after each row/component packed in one double sized array.
* @return A holder for the merged values.
*/
private static FlowSizeSpec mergeSizesGapsAndResConstrs(ResizeConstraint[] resConstr, boolean[] gapPush, int[][] minPrefMaxSizes, int[][] gapSizes)
{
int[][] sizes = new int[(minPrefMaxSizes.length << 1) + 1][]; // Make room for gaps around.
ResizeConstraint[] resConstsInclGaps = new ResizeConstraint[sizes.length];
sizes[0] = gapSizes[0];
for (int i = 0, crIx = 1; i < minPrefMaxSizes.length; i++, crIx += 2) {
// Component bounds and constraints
resConstsInclGaps[crIx] = resConstr[i];
sizes[crIx] = minPrefMaxSizes[i];
sizes[crIx + 1] = gapSizes[i + 1];
if (sizes[crIx - 1] != null)
resConstsInclGaps[crIx - 1] = gapPush[i < gapPush.length ? i : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
if (i == (minPrefMaxSizes.length - 1) && sizes[crIx + 1] != null)
resConstsInclGaps[crIx + 1] = gapPush[(i + 1) < gapPush.length ? (i + 1) : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
}
// Check for null and set it to 0, 0, 0.
for (int i = 0; i < sizes.length; i++) {
if (sizes[i] == null)
sizes[i] = new int[3];
}
return new FlowSizeSpec(sizes, resConstsInclGaps);
}
private static int[] mergeSizes(int[] oldValues, int[] newValues)
{
if (oldValues == null)
return newValues;
if (newValues == null)
return oldValues;
int[] ret = new int[oldValues.length];
for (int i = 0; i < ret.length; i++)
ret[i] = mergeSizes(oldValues[i], newValues[i], true);
return ret;
}
private static int mergeSizes(int oldValue, int newValue, boolean toMax)
{
if (oldValue == LayoutUtil.NOT_SET || oldValue == newValue)
return newValue;
if (newValue == LayoutUtil.NOT_SET)
return oldValue;
return toMax != oldValue > newValue ? newValue : oldValue;
}
private static int constrainSize(int s)
{
return s > 0 ? (s < LayoutUtil.INF ? s : LayoutUtil.INF) : 0;
}
private static void correctMinMax(int s[])
{
if (s[LayoutUtil.MIN] > s[LayoutUtil.MAX])
s[LayoutUtil.MIN] = s[LayoutUtil.MAX]; // Since MAX is almost always explicitly set use that
if (s[LayoutUtil.PREF] < s[LayoutUtil.MIN])
s[LayoutUtil.PREF] = s[LayoutUtil.MIN];
if (s[LayoutUtil.PREF] > s[LayoutUtil.MAX])
s[LayoutUtil.PREF] = s[LayoutUtil.MAX];
}
private static final class FlowSizeSpec
{
private final int[][] sizes; // [row/col index][min, pref, max]
private final ResizeConstraint[] resConstsInclGaps; // [row/col index]
private FlowSizeSpec(int[][] sizes, ResizeConstraint[] resConstsInclGaps)
{
this.sizes = sizes;
this.resConstsInclGaps = resConstsInclGaps;
}
/**
* @param specs The specs for the columns or rows. Last index will be used of fromIx + len is greater than this array's length.
* @param targetSize The size to try to meet.
* @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
* @param fromIx
* @param len
* @param sizeType
* @param eagerness How eager the algorithm should be to try to expand the sizes.
*
*
0 - Grow only rows/columns which have the sizeType set to be the containing components AND which has a grow weight > 0.
*
1 - Grow only rows/columns which have the sizeType set to be the containing components AND which has a grow weight > 0 OR unspecified.
*
2 - Grow all rows/columns that have a grow weight > 0.
*
3 - Grow all rows/columns that have a grow weight > 0 OR unspecified.
*
* @return The new size.
*/
private int expandSizes(DimConstraint[] specs, Float[] defGrow, int targetSize, int fromIx, int len, int sizeType, int eagerness)
{
ResizeConstraint[] resConstr = new ResizeConstraint[len];
int[][] sizesToExpand = new int[len][];
for (int i = 0; i < len; i++) {
int[] minPrefMax = sizes[i + fromIx];
sizesToExpand[i] = new int[] {minPrefMax[sizeType], minPrefMax[LayoutUtil.PREF], minPrefMax[LayoutUtil.MAX]};
if (eagerness <= 1 && i % 2 == 0) { // (i % 2 == 0) means only odd indexes, which is only rows/col indexes and not gaps.
int cIx = (i + fromIx - 1) >> 1;
DimConstraint spec = (DimConstraint) LayoutUtil.getIndexSafe(specs, cIx);
BoundSize sz = spec.getSize();
if ( (sizeType == LayoutUtil.MIN && sz.getMin() != null && sz.getMin().getUnit() != UnitValue.MIN_SIZE) ||
(sizeType == LayoutUtil.PREF && sz.getPreferred() != null && sz.getPreferred().getUnit() != UnitValue.PREF_SIZE)) {
continue;
}
}
resConstr[i] = (ResizeConstraint) LayoutUtil.getIndexSafe(resConstsInclGaps, i + fromIx);
}
Float[] growW = (eagerness == 1 || eagerness == 3) ? extractSubArray(specs, defGrow, fromIx, len): null;
int[] newSizes = LayoutUtil.calculateSerial(sizesToExpand, resConstr, growW, LayoutUtil.PREF, targetSize);
int newSize = 0;
for (int i = 0; i < len; i++) {
int s = newSizes[i];
sizes[i + fromIx][sizeType] = s;
newSize += s;
}
return newSize;
}
}
private static Float[] extractSubArray(DimConstraint[] specs, Float[] arr, int ix, int len)
{
if (arr == null || arr.length < ix + len) {
Float[] growLastArr = new Float[len];
// Handle a group where some rows (first one/few and/or last one/few) are docks.
for (int i = ix + len - 1; i >= 0; i -= 2) {
int specIx = (i >> 1);
if (specs[specIx] != DOCK_DIM_CONSTRAINT) {
growLastArr[i - ix] = ResizeConstraint.WEIGHT_100;
return growLastArr;
}
}
return growLastArr;
}
Float[] newArr = new Float[len];
for (int i = 0; i < len; i++)
newArr[i] = arr[ix + i];
return newArr;
}
private static WeakHashMap