diff options
author | Sven Gothel <[email protected]> | 2023-04-12 19:20:24 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-04-12 19:20:24 +0200 |
commit | 6a0ac90182efba40b0e6dab8f6390898aced70e8 (patch) | |
tree | c263bb343b66755d30fb81564df5232a96992bd1 /src/graphui | |
parent | 92ec47e74eef3ba47627b04ddf78996fa3a2296f (diff) |
GraphUI GridLayout: Functional Grid Layout w/ Padding, demo'ed in UISceneDemo20 with button Groups
All layout magic is simply performed in Group.Layout.layout(..) @ validate, incl. updating the
bounding box to have the padding included.
This demonstrates GraphUI's capability to be used with correct layout,
i.e. its pure matrix based position, scale and rotation.
Diffstat (limited to 'src/graphui')
3 files changed, 198 insertions, 42 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java index b3ae5b41d..e349b1302 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Group.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java @@ -48,10 +48,22 @@ import jogamp.graph.ui.TreeTool; * @see Group.Layout */ public class Group extends Shape implements Container { - /** Layout for the group, called @ {@link Group#validate(GL2ES2)} or {@link Group#validate(GLProfile)}. */ + /** Layout for the GraphUI {@link Group}, called @ {@link Shape#validate(GL2ES2)} or {@link Shape#validate(GLProfile)}. */ public static interface Layout { - /** Performing the layout, called @ {@link Group#validate(GL2ES2)} or {@link Group#validate(GLProfile)}. */ - void layout(Group g); + /** + * Performing the layout of {@link Group#getShapes()}, called @ {@link Shape#validate(GL2ES2)} or {@link Shape#validate(GLProfile)}. + * <p> + * According to the implemented layout, method + * - may scale the {@Link Shape}s + * - may move the {@Link Shape}s + * - may reuse the given {@link PMVMatrix} `pmv` + * - must update the given {@link AABBox} `box` + * </p> + * @param g the {@link Group} to layout + * @param box the bounding box of {@link Group} to be updated by this method. + * @param pmv a {@link PMVMatrix} which can be reused. + */ + void layout(final Group g, final AABBox box, final PMVMatrix pmv); } private final List<Shape> shapes = new ArrayList<Shape>(); @@ -161,12 +173,6 @@ public class Group extends Shape implements Container { } } - private void layout() { - if( null != layouter ) { - layouter.layout(this); - } - } - private boolean doFrustumCulling = false; @Override @@ -200,21 +206,25 @@ public class Group extends Shape implements Container { @Override protected void validateImpl(final GLProfile glp, final GL2ES2 gl) { if( isShapeDirty() ) { - layout(); final PMVMatrix pmv = new PMVMatrix(); final AABBox tmpBox = new AABBox(); for(final Shape s : shapes) { - // s.validateImpl(glp, gl); if( null != gl ) { s.validate(gl); } else { s.validate(glp); } - pmv.glPushMatrix(); - s.setTransform(pmv); - s.getBounds().transformMv(pmv, tmpBox); - pmv.glPopMatrix(); - box.resize(tmpBox); + } + if( null != layouter ) { + layouter.layout(this, box, pmv); + } else { + for(final Shape s : shapes) { + pmv.glPushMatrix(); + s.setTransform(pmv); + s.getBounds().transformMv(pmv, tmpBox); + pmv.glPopMatrix(); + box.resize(tmpBox); + } } } } @@ -249,6 +259,11 @@ public class Group extends Shape implements Container { } @Override + public String getSubString() { + return super.getSubString()+", shapes "+shapes.size(); + } + + @Override public boolean forOne(final PMVMatrix pmv, final Shape shape, final Runnable action) { return TreeTool.forOne(shapes, pmv, shape, action); } diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java b/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java index bd2fd2d76..7d1739dd6 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java @@ -1,5 +1,5 @@ /** - * Copyright 2010-2023 JogAmp Community. All rights reserved. + * Copyright 2023 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -27,43 +27,135 @@ */ package com.jogamp.graph.ui.layout; +import java.util.List; + +import com.jogamp.graph.ui.GraphShape; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Shape; -import com.jogamp.graph.ui.Group.Layout; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.PMVMatrix; +/** + * GraphUI Grid {@link Group.Layout}. + */ public class GridLayout implements Group.Layout { - private final int columns; - private final float padX, padY; + /** Layout order for {@link Group#getShapes()}} after population. */ + public static enum Order { + /** COLUMN layout order of {@link Group#getShapes()}} is left to right and top to bottom. */ + COLUMN, + /** ROW layout order of {@link Group#getShapes()}} is top to bottom and left to right. */ + ROW + } + private final Order order; + private final int col_limit; + private final int row_limit; + private final float cellWidth, cellHeight; + private final Padding padding; + private int row_count, col_count; + + + /** + * Default layout order of {@link Group#getShapes()}} is {@link Order#COLUMN}. + * @param column_limit [1..inf) + * @param cellWidth + * @param cellHeight + */ + public GridLayout(final int column_limit, final float cellWidth, final float cellHeight) { + this(Math.max(1, column_limit), -1, cellWidth, cellHeight, new Padding()); + } + + /** + * Default layout order of {@link Group#getShapes()}} is {@link Order#COLUMN}. + * @param column_limit [1..inf) + * @param cellWidth + * @param cellHeight + * @param padding + */ + public GridLayout(final int column_limit, final float cellWidth, final float cellHeight, final Padding padding) { + this(Math.max(1, column_limit), -1, cellWidth, cellHeight, padding); + } /** - * - * @param columns [1..inf) - * @param padX - * @param padY + * Default layout order of {@link Group#getShapes()}} is {@link Order#ROW}. + * @param cellWidth + * @param cellHeight + * @param padding + * @param row_limit [1..inf) */ - public GridLayout(final int columns, final float padX, final float padY) { - this.columns = Math.max(1, columns); - this.padX = padX; - this.padY = padY; + public GridLayout(final float cellWidth, final float cellHeight, final Padding padding, final int row_limit) { + this(-1, Math.max(1, row_limit), cellWidth, cellHeight, padding); + } + + private GridLayout(final int column_limit, final int row_limit, final float cellWidth, final float cellHeight, final Padding padding) { + this.order = 0 < column_limit ? Order.COLUMN : Order.ROW; + this.col_limit = column_limit; + this.row_limit = row_limit; + this.cellWidth = cellWidth; + this.cellHeight = cellHeight; + this.padding = padding;; + row_count = 0; + col_count = 0; } + public Order getOrder() { return order; } + public int getColumnCount() { return col_count; } + public int getRowCount() { return row_count; } + @Override - public void layout(final Group g) { - int col = 0; - float x=0; - float y=0; - for(final Shape s : g.getShapes()) { - s.moveTo(x, y, 0); - if( col + 1 == columns ) { - col = 0; - // row++; - x = 0; - y -= padY; - } else { - col++; - x += padX; + public void layout(final Group g, final AABBox box, final PMVMatrix pmv) { + final List<Shape> shapes = g.getShapes(); + if( Order.COLUMN == order ) { + row_count = (int) Math.ceil( (double)shapes.size() / (double)col_limit ); + col_count = col_limit; + } else { // Order.ROW_MAJOR == order + row_count = row_limit; + col_count = (int) Math.ceil( (double)shapes.size() / (double)row_limit ); + } + int col_i = 0, row_i = 0; + final AABBox sbox = new AABBox(); + for(final Shape s : shapes) { + // measure size + pmv.glPushMatrix(); + s.setTransform(pmv); + s.getBounds().transformMv(pmv, sbox); + pmv.glPopMatrix(); + + // adjust size and position (centered) + final float x = ( ( col_i ) * ( cellWidth + padding.width() ) ) + padding.left; + final float y = ( ( row_count - row_i - 1 ) * ( cellHeight + padding.height() ) ) + padding.bottom; + final float sx = cellWidth / sbox.getWidth(); + final float sy = cellHeight/ sbox.getHeight(); + final float sxy = sx < sy ? sx : sy; + final float dxh = sbox.getWidth() * ( sx - sxy ) * 0.5f; + final float dyh = sbox.getHeight() * ( sy - sxy ) * 0.5f; + s.moveTo( x + dxh, y + dyh, 0f ); + s.scale( sxy, sxy, 1f); + box.resize( x + cellWidth + padding.right, y + cellHeight + padding.top, 0); + box.resize( x - padding.left, y - padding.bottom, 0); + // System.err.println("["+row_i+"]["+col_i+"]: "+x+" / "+y); + + // position for next cell + if( Order.COLUMN == order ) { + if( col_i + 1 == col_limit ) { + col_i = 0; + row_i++; + } else { + col_i++; + } + } else { // Order.ROW_MAJOR == order + if( row_i + 1 == row_limit ) { + row_i = 0; + col_i++; + } else { + row_i++; + } } } } + + @Override + public String toString() { + return "Grid["+row_count+"x"+col_count+", "+order+", cell["+cellWidth+" x "+cellHeight+"], "+padding+"]"; + } } diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java b/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java new file mode 100644 index 000000000..f4b35e723 --- /dev/null +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java @@ -0,0 +1,49 @@ +/** + * Copyright 2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``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 JogAmp Community 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. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.graph.ui.layout; + +/** + * GraphUI Padding of cells, e.g. {@link GridLayout}. + */ +public class Padding { + public final float left, right, bottom, top; + + public Padding() { + left = 0f; right = 0f; bottom = 0f; top = 0f; + } + public Padding(final float width, final float height) { + left = width/2f; right = width/2f; bottom = height/2f; top = height/2f; + } + public Padding(final float left, final float right, final float bottom, final float top) { + this.left = left; this.right = right; this.bottom = bottom; this.top = top; + } + public float width() { return left + right; } + public float height() { return bottom + top; } + @Override + public String toString() { return "Padding[l "+left+", r "+right+", b "+bottom+", t "+top+"]"; } +} |