diff options
Diffstat (limited to 'src')
6 files changed, 109 insertions, 57 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Container.java b/src/graphui/classes/com/jogamp/graph/ui/Container.java index 106ffcfe9..b2a100107 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Container.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Container.java @@ -28,16 +28,13 @@ package com.jogamp.graph.ui; import java.util.Collection; -import java.util.Comparator; import java.util.List; -import com.jogamp.graph.ui.Shape.Visitor2; import com.jogamp.math.Matrix4f; import com.jogamp.math.geom.AABBox; import com.jogamp.math.util.PMVMatrix4f; import com.jogamp.opengl.GL2ES2; import com.jogamp.graph.curve.opengl.RegionRenderer; -import com.jogamp.graph.ui.Shape.Visitor1; /** * Container interface of UI {@link Shape}s diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java index c44fbe110..157881483 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Group.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java @@ -91,7 +91,7 @@ public class Group extends Shape implements Container { private Rectangle border = null; private boolean relayoutOnDirtyShapes = true; - private boolean widgetMode = false; + private Scene topLevelHolder = null; private boolean clipOnBounds = false; private Frustum clipFrustum = null; @@ -305,8 +305,8 @@ public class Group extends Shape implements Container { @Override protected void clearImpl0(final GL2ES2 gl, final RegionRenderer renderer) { + disableTopLevelWidget(); for(final Shape s : shapes) { - // s.clearImpl0(gl, renderer); s.clear(gl, renderer); } shapes.clear(); @@ -317,6 +317,7 @@ public class Group extends Shape implements Container { @Override protected void destroyImpl0(final GL2ES2 gl, final RegionRenderer renderer) { + disableTopLevelWidget(); for(final Shape s : shapes) { // s.destroyImpl0(gl, renderer); s.destroy(gl, renderer); @@ -488,9 +489,9 @@ public class Group extends Shape implements Container { public boolean getRelayoutOnDirtyShapes() { return relayoutOnDirtyShapes; } /** - * Toggles widget behavior for this group, default is disabled. + * Enables top-level widget behavior for this group, default is disabled. * <p> - * Enabled widget behavior for a group causes + * Enabled top-level widget behavior for a group causes * <ul> * <li>the whole group to be shown on top on (mouse over) activation of one of its elements</li> * <li>this group's {@link #addActivationListener(Listener)} to handle all it's elements activation events</li> @@ -498,52 +499,49 @@ public class Group extends Shape implements Container { * </ul> * </p> * <p> - * This method modifies all elements of this group for enabled or disabled widget behavior. + * This method modifies all elements of this group for enabled or disabled top-level widget behavior. * </p> - * @param v enable or disable + * <p> + * Disable this behavior via {@link #disableTopLevelWidget()}, otherwise done per-default + * at {@link #clear(GL2ES2, RegionRenderer)} or {@link #destroy(GL2ES2, RegionRenderer)}. + * </p> + * @param scene the top-level widget holder where this {@link Group} gets registered * @return this group for chaining + * @see #disableTopLevelWidget() */ - public final Group setWidgetMode(final boolean v) { - widgetMode = v; - if( v ) { - enableUniActivationImpl(true, forwardActivation); - } else { - enableUniActivationImpl(false, null); + public final Group enableTopLevelWidget(final Scene scene) { + topLevelHolder = scene; + setWidgetChilds(true, forwardActivation); + scene.addTopLevel(this); + return this; + } + /** Disables top-level widget behavior as potentially set via {@link #enableTopLevelWidget(Scene)}. NOP if not enabled. */ + public final Group disableTopLevelWidget() { + final Scene tlh = topLevelHolder; + topLevelHolder = null; + if( null != tlh ) { + tlh.removeTopLevel(this); + setWidgetChilds(false, forwardActivation); } return this; } - protected final void enableUniActivationImpl(final boolean v, final Listener activationListener) { - for(final Shape s : shapes ) { - if( s.isGroup() ) { - // ((Group)s).enableUniActivationImpl(v, activationListener); - ((Group)s).setWidgetMode(v); + private final void setWidgetChilds(final boolean enable, final Listener fwdActivationListener) { + TreeTool.forAll(this, (final Shape s) -> { + if( enable ) { + s.addActivationListener(fwdActivationListener); + } else { + s.removeActivationListener(fwdActivationListener); } - s.addActivationListener(activationListener); - } + return false; + }); } - /** Returns whether {@link #setWidgetMode(boolean)} is enabled or disabled. */ - public final boolean getWidgetMode() { return widgetMode; } + /** Returns whether {@link #setTopLevelWidget(boolean)} is enabled or disabled. */ + public final boolean isTopLevelWidget() { return null != topLevelHolder; } @Override public boolean isActive() { - return super.isActive() || ( widgetMode && TreeTool.forAll(this, (final Shape gs) -> { return gs.isActive(); } ) ); - } - - @Override - public float getAdjustedZ() { - final float[] v = { getAdjustedZImpl() }; - if( widgetMode && !super.isActive() ) { - TreeTool.forAll(this, (final Shape gs) -> { - if( gs.isActive() ) { - v[0] = gs.getAdjustedZImpl(); - return true; - } else { - return false; - } - } ); - } - return v[0]; + return super.isActive() || ( isTopLevelWidget() && TreeTool.forAll(this, (final Shape gs) -> { return gs.isActive(); } ) ); } /** diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java index 31c45359d..2ae18c5f6 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java @@ -53,7 +53,6 @@ import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.graph.curve.opengl.RenderState; -import com.jogamp.graph.ui.Shape.Visitor2; import com.jogamp.math.FloatUtil; import com.jogamp.math.Matrix4f; import com.jogamp.math.Ray; @@ -62,7 +61,6 @@ import com.jogamp.math.Vec2f; import com.jogamp.math.Vec3f; import com.jogamp.math.geom.AABBox; import com.jogamp.math.util.PMVMatrix4f; -import com.jogamp.graph.ui.Shape.Visitor1; import com.jogamp.newt.event.GestureHandler; import com.jogamp.newt.event.InputEvent; import com.jogamp.newt.event.KeyEvent; @@ -114,6 +112,8 @@ public final class Scene implements Container, GLEventListener { public static final float DEFAULT_Z16_EPSILON = FloatUtil.getZBufferEpsilon(16 /* zBits */, DEFAULT_SCENE_DIST, DEFAULT_ZNEAR); /** Default Z precision scale, i.e. multiple of {@link #DEFAULT_Z16_EPSILON} for {@link #setActiveShapeZOffsetScale(float)}. Value is {@value}. */ public static final float DEFAULT_ACTIVE_ZOFFSET_SCALE = 10f; + /** Default Z precision scale, i.e. multiple of {@link #DEFAULT_Z16_EPSILON} for {@link #setActiveShapeZOffsetScale(float)}. Value is {@value}. */ + public static final float DEFAULT_ACTIVE_TOPLEVEL_ZOFFSET_SCALE = 100f; /** Default Z precision on 16-bit depth buffer using {@code -1} z-position and {@link #DEFAULT_ZNEAR}. Value is {@code 1.5256461E-4}. */ // public static final float DIST1_Z16_EPSILON = FloatUtil.getZBufferEpsilon(16 /* zBits */, -1, DEFAULT_ZNEAR); @@ -128,6 +128,7 @@ public final class Scene implements Container, GLEventListener { } private static final boolean DEBUG = false; + private static final boolean DEBUG_PICKING = DEBUG; private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>(); private Shape[] displayShapeArray = new Shape[0]; // reduce memory re-alloc @ display @@ -136,6 +137,7 @@ public final class Scene implements Container, GLEventListener { private volatile List<Shape> renderedShapes = renderedShapesB1; private final AtomicReference<Tooltip> toolTipActive = new AtomicReference<Tooltip>(); private final AtomicReference<Shape> toolTipHUD = new AtomicReference<Shape>(); + private final List<Group> topLevel = new ArrayList<Group>(); private boolean doFrustumCulling = false; @@ -148,6 +150,7 @@ public final class Scene implements Container, GLEventListener { private final AABBox planeBox = new AABBox(0f, 0f, 0f, 0f, 0f, 0f); private volatile Shape activeShape = null; + private volatile Group activeTopLevel = null; private SBCMouseListener sbcMouseListener = null; private SBCGestureListener sbcGestureListener = null; @@ -605,6 +608,7 @@ public final class Scene implements Container, GLEventListener { } } shapes.clear(); + topLevel.clear(); displayShapeArray = new Shape[0]; renderedShapesB0.clear(); renderedShapesB1.clear(); @@ -981,27 +985,83 @@ public final class Scene implements Container, GLEventListener { public void releaseActiveShape() { if( null != activeShape ) { + if( DEBUG_PICKING ) { + System.err.println("ACTIVE-RELEASE: "+activeShape); + } activeShape.setActive(false, 0); activeShape = null; + + final Group lastTL = activeTopLevel; + activeTopLevel = null; + if( null != lastTL ) { + lastTL.setZOffset(0); + } } } private void setActiveShape(final Shape shape) { - if( activeShape != shape && null != shape && - shape.setActive(true, activeZOffsetScale * getZEpsilon(16)) ) - { - if( null != activeShape ) { - activeShape.setActive(false, 0); + final Shape lastShape = activeShape; + if( lastShape != shape && null != shape ) { + final float zEpsilon = getZEpsilon(16); + final boolean isTopLevel = topLevel.contains(shape); + final float newZOffset = ( isTopLevel ? activeZOffsetScale : activeTopLevelZOffsetScale ) * zEpsilon; + if( shape.setActive(true, newZOffset) ) { + final Group lastTL = activeTopLevel; + final Group thisTL = isTopLevel ? (Group)shape : getTopLevelParent(shape); + int mode = 0; + if( null != lastShape && lastTL != lastShape ) { + lastShape.setActive(false, 0); + mode += 10; + } + if( lastTL != thisTL ) { + mode += 100; + if( null!=lastTL) { + lastTL.setZOffset(0); + mode += 1000; + } + if( null!=thisTL && !isTopLevel ) { + thisTL.setZOffset(activeTopLevelZOffsetScale * zEpsilon); + mode += 2000; + } + activeTopLevel = thisTL; + } + + if( DEBUG_PICKING ) { + System.err.println("ACTIVE-SHAPE: NEW mode "+mode+", isTopLevel "+isTopLevel+", s 0x"+Integer.toHexString(System.identityHashCode(shape))+", "+shape); + System.err.println("ACTIVE-SHAPE: NEW g 0x"+Integer.toHexString(System.identityHashCode(thisTL))+", "+thisTL); + System.err.println("ACTIVE-SHAPE: PRE s 0x"+Integer.toHexString(System.identityHashCode(lastShape))+", "+lastShape); + System.err.println("ACTIVE-SHAPE: PRE g 0x"+Integer.toHexString(System.identityHashCode(lastTL))+", "+lastTL); + // dumpTopLevelParent(); + } + mode = mode + 0; // (void)mode ;-) + activeShape = shape; } - activeShape = shape; } } private float activeZOffsetScale = DEFAULT_ACTIVE_ZOFFSET_SCALE; + private final float activeTopLevelZOffsetScale = DEFAULT_ACTIVE_TOPLEVEL_ZOFFSET_SCALE; /** Returns the active {@link Shape} Z-Offset scale, defaults to {@code 10.0}. */ public float getActiveShapeZOffsetScale() { return activeZOffsetScale; } /** Sets the active {@link Shape} Z-Offset scale, defaults to {@code 10.0}. */ public void setActiveShapeZOffsetScale(final float v) { activeZOffsetScale = v; } + protected void addTopLevel(final Group g) { topLevel.add(g); } + protected void removeTopLevel(final Group g) { topLevel.add(g); } + private Group getTopLevelParent(final Shape s) { + for(final Group g : topLevel) { + if(g.contains(s)) { + return g; + } + } + return null; + } + @SuppressWarnings("unused") + private void dumpTopLevelParent() { + for(final Group g : topLevel) { + System.err.printf("TL: %s/%s, %s%n", g.getClass().getSimpleName(), g.getName(), g); + } + } + private final class SBCGestureListener implements GestureHandler.GestureListener { @Override public void gestureDetected(final GestureEvent gh) { diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java index d7c91ed2f..c12749222 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java @@ -1523,7 +1523,7 @@ public abstract class Shape { } else { rotateS = ""; } - final String activeS = ", active["+(isIO(IO_ACTIVE) ? "SELF," : "")+(isGroup() && isActive()?"GROUP":"")+"]"; + final String activeS = ", active["+(isIO(IO_ACTIVE) ? "SELF," : "")+(isGroup() && isActive()?"GROUP":"")+", adjZ "+getAdjustedZ()+"]"; final String ps = hasPadding() ? padding.toString()+", " : ""; final String bs = hasBorder() ? "border[l "+getBorderThickness()+", c "+getBorderColor()+"], " : ""; final String idS = -1 != id ? ", id "+id : ""; @@ -1591,7 +1591,7 @@ public abstract class Shape { protected final boolean setActive(final boolean v, final float zOffset) { if( isActivable() ) { - this.zOffset = zOffset; + setZOffset(zOffset); setIO(IO_ACTIVE, v); if( !v ) { releaseInteraction(); @@ -1619,12 +1619,10 @@ public abstract class Shape { } }; - public float getAdjustedZ() { - return getAdjustedZImpl(); - } - protected final float getAdjustedZImpl() { + public final float getAdjustedZ() { return position.z() * getScale().z() + zOffset; } + /* pp */ final void setZOffset(final float v) { zOffset = v; } /** * Set's a new {@link Tooltip} for this shape. diff --git a/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java b/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java index ce810b3ef..327ce76ee 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java +++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java @@ -571,7 +571,7 @@ public class MediaPlayer extends Widget { ctrlGroup.addShape(cs); } } - this.setWidgetMode(true); + this.enableTopLevelWidget(scene); this.addActivationListener( (final Shape s) -> { if( this.isActive() ) { diff --git a/src/graphui/classes/jogamp/graph/ui/TreeTool.java b/src/graphui/classes/jogamp/graph/ui/TreeTool.java index d80a6c103..dcb847932 100644 --- a/src/graphui/classes/jogamp/graph/ui/TreeTool.java +++ b/src/graphui/classes/jogamp/graph/ui/TreeTool.java @@ -36,7 +36,6 @@ import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; import com.jogamp.graph.ui.Shape.Visitor1; import com.jogamp.graph.ui.Shape.Visitor2; -import com.jogamp.math.Matrix4f; import com.jogamp.math.util.PMVMatrix4f; /** Generic static {@link Shape} tree traversal tools, utilized by {@link Scene} and {@link Container} implementations. */ |