diff options
author | Sven Gothel <[email protected]> | 2023-04-28 12:40:23 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-04-28 12:40:23 +0200 |
commit | 87814f1c86b132a16ddf6822d05b83c3ed091fe2 (patch) | |
tree | 885134dd7398a748a0837b536a26771c933dafd2 /src/graphui | |
parent | bd10664189e944699492008776819a28a2d95ecf (diff) |
GraphUI Revise Padding and Border: Padding + Border belong to Shape's bounds. Account for both (seperately) and add border rendering to Group as well.
Diffstat (limited to 'src/graphui')
7 files changed, 159 insertions, 42 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java b/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java index 040b0a32c..7dccd41a0 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/GraphShape.java @@ -34,8 +34,10 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.layout.Padding; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.Vec3f; import com.jogamp.opengl.math.Vec4f; import com.jogamp.opengl.util.texture.TextureSequence; @@ -206,9 +208,18 @@ public abstract class GraphShape extends Shape { clearDirtyRegions(gl); } if( isShapeDirty() ) { + // box has been reset addShapeToRegion(glp, gl); // calls updateGLRegion(..) if( hasBorder() ) { + // Also takes padding into account addBorderOutline(); + } else if( hasPadding() ) { + final Padding p = getPadding(); + final Vec3f l = box.getLow(); + final Vec3f h = box.getHigh(); + box.resize(l.x() - p.left, l.y() - p.bottom, l.z()); + box.resize(h.x() + p.right, h.y() + p.top, l.z()); + setRotationPivot( box.getCenter() ); } region.setQuality(regionQuality); } else if( isStateDirty() ) { @@ -218,10 +229,11 @@ public abstract class GraphShape extends Shape { protected void addBorderOutline() { final OutlineShape shape = new OutlineShape(); - final float x1 = box.getMinX(); - final float x2 = box.getMaxX(); - final float y1 = box.getMinY(); - final float y2 = box.getMaxY(); + final Padding dist = null != getPadding() ? getPadding() : new Padding(); + final float x1 = box.getMinX() - dist.left; + final float x2 = box.getMaxX() + dist.right; + final float y1 = box.getMinY() - dist.bottom; + final float y2 = box.getMaxY() + dist.top; final float z = box.getCenter().z(); // 0; // box.getMinZ() + 0.025f; { // Outer OutlineShape as Winding.CCW. @@ -235,8 +247,7 @@ public abstract class GraphShape extends Shape { } { // Inner OutlineShape as Winding.CW. - final float dxy0 = box.getWidth() < box.getHeight() ? box.getWidth() : box.getHeight(); - final float dxy = dxy0 * getBorderThickness(); + final float dxy = getBorderThickness(); shape.moveTo(x1+dxy, y1+dxy, z); shape.lineTo(x1+dxy, y2-dxy, z); shape.lineTo(x2-dxy, y2-dxy, z); @@ -246,7 +257,9 @@ public abstract class GraphShape extends Shape { } shape.setIsQuadraticNurbs(); shape.setSharpness(oshapeSharpness); - region.addOutlineShape(shape, null, borderColor); + region.addOutlineShape(shape, null, getBorderColor()); + box.resize(shape.getBounds()); // border <-> shape = padding, and part of shape size + setRotationPivot( box.getCenter() ); } protected void clearImpl(final GL2ES2 gl, final RegionRenderer renderer) { } diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java index 1de20240d..d82df3a52 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Group.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java @@ -33,10 +33,14 @@ import java.util.Collection; import java.util.Comparator; import java.util.List; +import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.layout.Padding; +import com.jogamp.graph.ui.shapes.Rectangle; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.Vec3f; import com.jogamp.opengl.math.Vec4f; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.util.PMVMatrix; @@ -70,6 +74,7 @@ public class Group extends Shape implements Container { private final List<Shape> shapes = new ArrayList<Shape>(); private Layout layouter; + private Rectangle border = null; /** * Create a Graph based {@link GLRegion} UI {@link Shape}. @@ -126,7 +131,6 @@ public class Group extends Shape implements Container { /** Removes given shape and destroy it. */ public void removeShape(final GL2ES2 gl, final RegionRenderer renderer, final Shape s) { - s.setBorder(0f); shapes.remove(s); s.destroy(gl, renderer); } @@ -183,6 +187,10 @@ public class Group extends Shape implements Container { // s.destroyImpl0(gl, renderer); s.destroy(gl, renderer);; } + if( null != border ) { + border.destroy(gl, renderer); + border = null; + } } private boolean doFrustumCulling = false; @@ -208,7 +216,6 @@ public class Group extends Shape implements Container { shape.setTransform(pmv); if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { - // FIXME: Optimize to reuse modulated rgba if( null == rgba ) { shape.drawToSelect(gl, renderer, sampleCount); } else { @@ -218,11 +225,19 @@ public class Group extends Shape implements Container { pmv.glPopMatrix(); } } + if( null != border ) { + if( null == rgba ) { + border.drawToSelect(gl, renderer, sampleCount); + } else { + border.draw(gl, renderer, sampleCount); + } + } } @Override protected void validateImpl(final GLProfile glp, final GL2ES2 gl) { if( isShapeDirty() ) { + // box has been reset final PMVMatrix pmv = new PMVMatrix(); if( null != layouter ) { for(final Shape s : shapes) { @@ -248,6 +263,25 @@ public class Group extends Shape implements Container { box.resize(tsbox); } } + if( hasPadding() ) { + final Padding p = getPadding(); + final Vec3f l = box.getLow(); + final Vec3f h = box.getHigh(); + box.resize(l.x() - p.left, l.y() - p.bottom, l.z()); + box.resize(h.x() + p.right, h.y() + p.top, l.z()); + setRotationPivot( box.getCenter() ); + } + if( hasBorder() ) { + if( null == border ) { + border = new Rectangle(Region.VBAA_RENDERING_BIT, box, getBorderThickness()); + } else { + border.setEnabled(true); + border.setBounds(box, getBorderThickness()); + } + border.setColor(getBorderColor()); + } else if( null != border ) { + border.setEnabled(false); + } } } diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java index 4955e683a..4ddcc719c 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java @@ -110,7 +110,7 @@ public final class Scene implements Container, GLEventListener { private static final boolean DEBUG = false; private final List<Shape> shapes = new ArrayList<Shape>(); - private float dbgbox_thickness = 0f; + private float dbgBorderThickness = 0f; private boolean doFrustumCulling = false; private float[] clearColor = null; @@ -217,7 +217,7 @@ public final class Scene implements Container, GLEventListener { } @Override public void addShape(final Shape s) { - s.setBorder(dbgbox_thickness); + s.setBorder(dbgBorderThickness); shapes.add(s); } @Override @@ -315,11 +315,11 @@ public final class Scene implements Container, GLEventListener { } /** - * Sets the {@link #getBounds()} fractional thickness of the debug box ranging [0..1] for all shapes, zero for no debug box (default). - * @param v fractional thickness of {@link #getBounds()} ranging [0..1], zero for no debug box + * Sets the debug {@link Shape#setBorder(float) border} thickness for all existing or added shapes, zero for no debug border (default). + * @param v thickness debug border, zero for no border */ - public final void setDebugBox(final float v) { - dbgbox_thickness = v; + public final void setDebugBorderBox(final float v) { + dbgBorderThickness = v; for(int i=0; i<shapes.size(); i++) { shapes.get(i).setBorder(v); } diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java index 5ef40a57f..5f88550dd 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java @@ -35,6 +35,7 @@ import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.fixedfunc.GLMatrixFunc; import com.jogamp.graph.curve.opengl.RegionRenderer; +import com.jogamp.graph.ui.layout.Padding; import com.jogamp.newt.event.GestureHandler.GestureEvent; import com.jogamp.newt.event.GestureHandler.GestureListener; import com.jogamp.newt.event.MouseAdapter; @@ -63,6 +64,9 @@ import com.jogamp.opengl.util.PMVMatrix; * A shape is expected to have its 0/0 origin in its bottom-left corner, otherwise the drag-zoom sticky-edge will not work as expected. * </p> * <p> + * A shape's {@link #getBounds()} includes its optional {@link #getPadding()} and optional {@link #getBorderThickness()}. + * </p> + * <p> * GraphUI is GPU based and resolution independent. * </p> * <p> @@ -136,8 +140,9 @@ public abstract class Shape { private boolean resizable = true; private boolean interactive = true; private boolean enabled = true; - private float border_thickness = 0f; - protected final Vec4f borderColor = new Vec4f(0.75f, 0.75f, 0.75f, 1.0f); + private float borderThickness = 0f; + private Padding padding = null; + private final Vec4f borderColor = new Vec4f(0.0f, 0.0f, 0.0f, 1.0f); private ArrayList<MouseGestureListener> mouseListeners = new ArrayList<MouseGestureListener>(); private Listener onMoveListener = null; @@ -159,18 +164,49 @@ public abstract class Shape { public final Shape setEnabled(final boolean v) { enabled = v; return this; } /** - * Sets the thickness of the debug box, zero for no border (default). - * @param v border thickness, zero for no debug box + * Sets the padding for this shape, which is included in {@link #getBounds()B} and also includes the border. Default is zero. + * + * Method issues {@link #markShapeDirty()}. + * + * @param padding distance of shape to the border, i.e. padding + * @return this shape for chaining + * @see #getPadding() + * @see #hasPadding() + */ + public final Shape setPaddding(final Padding padding) { + this.padding = padding; + markShapeDirty(); + return this; + } + + /** + * Returns {@link Padding} of this shape, which is included in {@link #getBounds()B} and also includes the border. Default is zero. + * @see #setPaddding(Padding) + * @see #hasPadding() */ - public final Shape setBorder(final float v) { - border_thickness = Math.max(0f, v); + public Padding getPadding() { return padding; } + + /** Returns true if {@link #setPaddding(Padding)} added a non {@link Padding#zeroSumSize()} spacing to this shape. */ + public boolean hasPadding() { null != padding && !padding.zeroSumSize(); } + + /** + * Sets the thickness of the border, which is included in {@link #getBounds()} and is outside of {@link #getPadding()}. Default is zero for no border. + * + * Method issues {@link #markShapeDirty()}. + * + * @param thickness border thickness, zero for no border + * @return this shape for chaining + */ + public final Shape setBorder(final float thickness) { + borderThickness = Math.max(0f, thickness); + markShapeDirty(); return this; } - /** Returns true if a border has been enabled via {@link #setBorder(float)}. */ - public final boolean hasBorder() { return !FloatUtil.isZero(border_thickness); } + /** Returns true if a border has been enabled via {@link #setBorder(float, Padding)}. */ + public final boolean hasBorder() { return !FloatUtil.isZero(borderThickness); } - /** Returns the border thickness, see {@link #setBorder(float)}. */ - public final float getBorderThickness() { return border_thickness; } + /** Returns the border thickness, see {@link #setBorder(float, Padding)}. */ + public final float getBorderThickness() { return borderThickness; } /** * Clears all data and reset all states as if this instance was newly created @@ -319,8 +355,10 @@ public abstract class Shape { /** * Returns the unscaled bounding {@link AABBox} for this shape, borrowing internal instance. * - * The returned {@link AABBox} will only cover this unscaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} + * The returned {@link AABBox} will cover the unscaled shape + * as well as its optional {@link #getPadding()} and optional {@link #getBorderThickness()}. + * + * The returned {@link AABBox} is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} * or {@link #validate(GL2ES2)}. * * @see #getBounds(GLProfile) @@ -330,8 +368,10 @@ public abstract class Shape { /** * Returns the scaled width of the bounding {@link AABBox} for this shape. * - * The returned width will only cover the scaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} + * The returned width will cover the scaled shape + * as well as its optional scaled {@link #getPadding()} and optional scaled {@link #getBorderThickness()}. + * + * The returned width is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} * or {@link #validate(GL2ES2)}. * * @see #getBounds() @@ -343,8 +383,10 @@ public abstract class Shape { /** * Returns the scaled height of the bounding {@link AABBox} for this shape. * - * The returned height will only cover the scaled shape - * after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} + * The returned height will cover the scaled shape + * as well as its optional scaled {@link #getPadding()} and optional scaled {@link #getBorderThickness()}. + * + * The returned height is only valid after an initial call to {@link #draw(GL2ES2, RegionRenderer, int[]) draw(..)} * or {@link #validate(GL2ES2)}. * * @see #getBounds() diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/Margin.java b/src/graphui/classes/com/jogamp/graph/ui/layout/Margin.java index f78c9dea9..fde7217b6 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/Margin.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/Margin.java @@ -30,7 +30,7 @@ package com.jogamp.graph.ui.layout; import com.jogamp.opengl.math.FloatUtil; /** - * GraphUI CSS property Margin, space between or around elements. + * GraphUI CSS property Margin, space between or around elements and not included in the element's size. * * The CSS margin properties are used to create space around elements, outside of any defined borders. * diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java b/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java index 52c46bc3a..1d5eca002 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/Padding.java @@ -30,7 +30,7 @@ package com.jogamp.graph.ui.layout; import com.jogamp.opengl.math.FloatUtil; /** - * GraphUI CSS property Padding, space belonging to the element. + * GraphUI CSS property Padding, space belonging to the element and included in the element's size. * * The CSS padding properties are used to generate space around an element's content, inside of any defined borders. */ diff --git a/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java b/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java index 90433a45e..2b9698e3a 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java +++ b/src/graphui/classes/com/jogamp/graph/ui/shapes/Rectangle.java @@ -31,42 +31,70 @@ import com.jogamp.graph.curve.OutlineShape; import com.jogamp.graph.ui.GraphShape; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.math.geom.AABBox; /** - * A GraphUI Rectangle {@link GraphShape} + * A GraphUI rectangle {@link GraphShape} * <p> * GraphUI is GPU based and resolution independent. * </p> */ public class Rectangle extends GraphShape { - private float width, height, lineWidth; + private float minX, minY, zPos; + private float width; + private float height; + private float lineWidth; - public Rectangle(final int renderModes, final float width, final float height, final float linewidth) { + public Rectangle(final int renderModes, final float minX, final float minY, final float width, final float height, final float lineWidth, final float zPos) { super(renderModes); + this.minX = minX; + this.minY = minY; + this.zPos = zPos; this.width = width; this.height = height; - this.lineWidth = linewidth; + this.lineWidth = lineWidth; + } + + public Rectangle(final int renderModes, final AABBox abox, final float lineWidth) { + this( renderModes, abox.getMinX(), abox.getMinY(), abox.getWidth(), abox.getHeight(), lineWidth, abox.getCenter().z()); + } + + public Rectangle(final int renderModes, final float minX, final float minY, final float width, final float height, final float lineWidth) { + this( renderModes, minX, minY, width, height, lineWidth, 0); + } + public Rectangle(final int renderModes, final float width, final float height, final float lineWidth) { + this( renderModes, 0, 0, width, height, lineWidth, 0); } public final float getWidth() { return width; } public final float getHeight() { return height; } public final float getLineWidth() { return lineWidth; } + public void setPosition(final float minX, final float minY, final float zPos) { + this.minX = minX; + this.minY = minY; + this.zPos = zPos; + markShapeDirty(); + } public void setDimension(final float width, final float height, final float lineWidth) { this.width = width; this.height = height; this.lineWidth = lineWidth; markShapeDirty(); } + public void setBounds(final AABBox abox, final float lineWidth) { + setPosition(abox.getMinX(), abox.getMinY(), abox.getCenter().z()); + setDimension(abox.getWidth(), abox.getHeight(), lineWidth); + } @Override protected void addShapeToRegion(final GLProfile glp, final GL2ES2 gl) { final OutlineShape shape = new OutlineShape(); - final float x1 = 0f; - final float y1 = 0f; - final float x2 = getWidth(); - final float y2 = getHeight(); - final float z = 0f; + final float x1 = minX; + final float y1 = minY; + final float x2 = minX + getWidth(); + final float y2 = minY + getHeight(); + final float z = zPos; { // Outer OutlineShape as Winding.CCW. shape.moveTo(x1, y1, z); |