aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java
blob: 6f6e610f6a25c768255a5d0f9cd663ac89d47100 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/**
 * 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;

import java.util.List;

import com.jogamp.graph.ui.Group;
import com.jogamp.graph.ui.Shape;
import com.jogamp.opengl.math.FloatUtil;
import com.jogamp.opengl.math.geom.AABBox;
import com.jogamp.opengl.util.PMVMatrix;

/**
 * GraphUI Stack {@link Group.Layout}.
 * <p>
 * A stack of {@link Shape}s
 * - size kept unscaled
 * - position depends on {@Link Padding} and {@link Margin}
 * - *cell* size can be set
 * </p>
 */
public class BoxLayout implements Group.Layout {
    private final float cellWidth, cellHeight;
    private final Margin margin;
    private final Padding padding;
    private final float borderThickness;

    public BoxLayout(final Padding padding) {
        this(0f, 0f, new Margin(), padding);
    }
    public BoxLayout(final float width, final float height, final Margin margin) {
        this(width, height, margin, new Padding());
    }
    public BoxLayout(final float width, final float height, final Margin margin, final Padding padding) {
        this.cellWidth = Math.max(0f, width);
        this.cellHeight = Math.max(0f, height);
        this.margin = margin;
        this.padding = padding;
        this.borderThickness = 0f;
    }

    public Padding getPadding() { return padding; }
    public Margin getMargin() { return margin; }

    @Override
    public void layout(final Group g, final AABBox box, final PMVMatrix pmv) {
        final boolean hasCellWidth = !FloatUtil.isZero(cellWidth);
        final boolean hasCellHeight = !FloatUtil.isZero(cellHeight);
        final List<Shape> shapes = g.getShapes();
        final AABBox sbox = new AABBox();
        for(int i=0; i < shapes.size(); ++i) {
            final Shape s = shapes.get(i);
            pmv.glPushMatrix();
            s.setTransform(pmv);
            s.getBounds().transformMv(pmv, sbox);
            pmv.glPopMatrix();

            // adjust size and position (centered)
            final float paddedWidth = sbox.getWidth() + padding.width();
            final float paddedHeight = sbox.getHeight() + padding.height();
            final float marginedWidth = paddedWidth + margin.width();
            final float marginedHeight = paddedHeight + margin.height();
            final float cellWidth2 = hasCellWidth ? cellWidth : marginedWidth;
            final float cellHeight2 = hasCellHeight ? cellHeight : marginedHeight;
            final float x, y;
            if( margin.isCenteredHoriz() || hasCellWidth && sbox.getWidth() + padding.width() + margin.width() > cellWidth2 ) {
                x = 0;
            } else {
                x = margin.left + padding.left;
            }
            if( margin.isCenteredVert() || hasCellHeight && sbox.getHeight() + padding.height() + margin.height() > cellHeight2 ) {
                y = 0;
            } else {
                y = margin.bottom + padding.bottom;
            }
            float dxh = 0, dyh = 0;
            if( margin.isCenteredHoriz() ) {
                dxh += 0.5f * ( cellWidth2 - paddedWidth ); // actual horiz-centered
            }
            if( margin.isCenteredVert() ) {
                dyh += 0.5f * ( cellHeight2 - paddedHeight ); // actual vert-centered
            }
            System.err.println("["+i+"].m: "+x+" / "+y+" + "+dxh+" / "+dyh+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight());
            s.moveTo( x + dxh, y + dyh, 0f ); // center the scaled artifact
            s.move( sbox.getLow().mul(-1f) ); // remove the bottom-left delta
            box.resize( x + cellWidth2 + padding.right, y + cellHeight2 + padding.top,    0);
            box.resize( x              - padding.left,  y -               padding.bottom, 0);
            System.err.println("["+i+"].x: "+x+" / "+y+" + "+dxh+" / "+dyh+" -> "+s.getPosition()+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight());
        }
    }

    @Override
    public String toString() {
        return "Box[cell["+cellWidth+" x "+cellHeight+"], "+margin+", "+padding+"]";
    }
}