aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph/ui
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-02-05 11:54:34 +0100
committerSven Göthel <[email protected]>2024-02-05 11:54:34 +0100
commit43a7899fedf2a570d20b03848bf15710f30b7f26 (patch)
tree2b3f8fbc69cbc78e8997d6f37f3c2b56ec88a00d /src/graphui/classes/com/jogamp/graph/ui
parent8df74578481431768b3c26294c6bd64ed7030ae5 (diff)
Bug 1498: Change Top-Level Widget Mode: Register a top-level Group in Scene, where its zOffset gets adjusted when activated..
.. instead of having a non-working complicated callback orgy setup. This also takes away the getAdjustedZ() overloading burden (or better uglyness) etc. Hence Group's setWidgetMode(boolean) became: - enableTopLevelWidget(Scene) - disableTopLevelWidget() The forwardActivation listener is still applied to all children as well as isActive() is also still overloaded for same required behavior. However, none of the children is set in 'widget mode' as well as the Group is simply added to (or removed from) the Scene's top-level Group list - the holder. Scene's setActiveShape(Shape) and releaseActiveShape() handle the top-level Group if affected, i.e. adding or zero'ing its ZOffset.
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph/ui')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Container.java3
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Group.java74
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Scene.java76
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Shape.java10
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java2
5 files changed, 109 insertions, 56 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() ) {