aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes/com/jogamp/graph
diff options
context:
space:
mode:
authorSven Göthel <[email protected]>2024-01-20 05:11:28 +0100
committerSven Göthel <[email protected]>2024-01-20 05:11:28 +0100
commit018f2633ba8f7106439ec70829d2444abf0c389b (patch)
tree1be2e6b9090cfd25600d147ae819982b8053f926 /src/graphui/classes/com/jogamp/graph
parent5a24e0bbaaa0cdb61292e264b4919295fff40a2a (diff)
GraphUI Tooltip*: Allow user to trigger display via now(); Ensure TooltipShape.DestroyCallback gets passed the user provided Shape only
Diffstat (limited to 'src/graphui/classes/com/jogamp/graph')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Scene.java56
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Shape.java35
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Tooltip.java46
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java16
4 files changed, 108 insertions, 45 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
index fa11f2675..5c9c6859e 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
@@ -485,15 +485,8 @@ public final class Scene implements Container, GLEventListener {
syncDisplayedOnce.notifyAll();
}
final Tooltip tt = toolTipActive.get();
- if( null != tt && null == toolTipHUD.get() ) {
- final Shape[] hud = { null };
- if( tt.tick() && forOne(pmv, tt.getTool(), () -> {
- final AABBox toolMvBounds = tt.getToolMvBounds(pmv);
- hud[0] = tt.createTip(drawable, Scene.this, pmv, toolMvBounds);
- }) )
- {
- setToolTip( hud[0] );
- }
+ if( null != tt ) {
+ activateTooltipImpl(drawable, pmv, tt);
}
}
@@ -1103,7 +1096,7 @@ public final class Scene implements Container, GLEventListener {
@Override
public void mousePressed(final MouseEvent e) {
- clearToolTip();
+ // clearToolTip();
if( -1 == lId || e.getPointerId(0) == lId ) {
lx = e.getX();
ly = e.getY();
@@ -1117,7 +1110,7 @@ public final class Scene implements Container, GLEventListener {
@Override
public void mouseReleased(final MouseEvent e) {
- clearToolTip();
+ // clearToolTip();
// flip to GL window coordinates, origin bottom-left
final int glWinX = e.getX();
final int glWinY = getHeight() - e.getY() - 1;
@@ -1133,7 +1126,6 @@ public final class Scene implements Container, GLEventListener {
@Override
public void mouseClicked(final MouseEvent e) {
- clearToolTip();
// flip to GL window coordinates
final int glWinX = e.getX();
final int glWinY = getHeight() - e.getY() - 1;
@@ -1146,6 +1138,7 @@ public final class Scene implements Container, GLEventListener {
releaseActiveShape();
clear();
}
+ clearToolTip();
}
@Override
@@ -1158,8 +1151,8 @@ public final class Scene implements Container, GLEventListener {
// dragged .. delegate to active shape!
// flip to GL window coordinates, origin bottom-left
- final int glWinX = lx;
- final int glWinY = getHeight() - ly - 1;
+ final int glWinX = e.getX();
+ final int glWinY = getHeight() - e.getY() - 1;
dispatchMouseEventForShape(activeShape, e, glWinX, glWinY);
}
}
@@ -1175,7 +1168,6 @@ public final class Scene implements Container, GLEventListener {
@Override
public void mouseMoved(final MouseEvent e) {
- clearToolTip();
if( -1 == lId || e.getPointerId(0) == lId ) {
lx = e.getX();
ly = e.getY();
@@ -1184,9 +1176,12 @@ public final class Scene implements Container, GLEventListener {
final int glWinX = lx;
final int glWinY = getHeight() - ly - 1;
final Shape s = dispatchMouseEventPickShape(e, glWinX, glWinY);
+ clearToolTip();
if( null != s ) {
mouseOver = true;
- toolTipActive.set( s.startToolTip() );
+ synchronized( toolTipActive ) {
+ toolTipActive.set( s.startToolTip(true /* lookupParents */) );
+ }
} else {
mouseOver = false;
}
@@ -1222,20 +1217,39 @@ public final class Scene implements Container, GLEventListener {
}
private void clearToolTip() {
- final Tooltip tt = toolTipActive.getAndSet(null);
- if( null != tt ) {
- tt.stop();
+ final Tooltip tt;
+ synchronized( toolTipActive ) {
+ tt = toolTipActive.get();
+ if( null != tt && tt.stop(false) ) {
+ toolTipActive.set(null);
+ }
}
final Shape s = toolTipHUD.getAndSet(null);
if( null != s ) {
invoke(false, (final GLAutoDrawable drawable) -> {
- if( s == removeShape(s) ) {
- tt.destroyTip(drawable.getGL().getGL2ES2(), renderer, s);
+ if( null != tt ) {
+ if( s == removeShape(s) ) {
+ tt.destroyTip(drawable.getGL().getGL2ES2(), renderer, s);
+ }
+ } else {
+ removeShape(drawable.getGL().getGL2ES2(), renderer, s);
}
return true;
});
}
}
+ private void activateTooltipImpl(final GLAutoDrawable drawable, final PMVMatrix4f pmv, final Tooltip tt) {
+ if( null == toolTipHUD.get() ) {
+ final Shape[] hud = { null };
+ if( tt.tick() && forOne(pmv, tt.getTool(), () -> {
+ final AABBox toolMvBounds = tt.getToolMvBounds(pmv);
+ hud[0] = tt.createTip(drawable, Scene.this, pmv, toolMvBounds);
+ }) )
+ {
+ setToolTip( hud[0] );
+ }
+ }
+ }
/**
* Return a formatted status string containing avg fps and avg frame duration.
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Shape.java b/src/graphui/classes/com/jogamp/graph/ui/Shape.java
index 672aab9a7..36b15d739 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Shape.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Shape.java
@@ -214,7 +214,7 @@ public abstract class Shape {
private static final int DIRTY_SHAPE = 1 << 0 ;
private static final int DIRTY_STATE = 1 << 1 ;
- private Group parent;
+ private volatile Group parent = null;
protected final AABBox box;
private final Vec3f position = new Vec3f();
@@ -286,6 +286,7 @@ public abstract class Shape {
}
protected void setParent(final Group c) { parent = c; }
+
/**
* Returns the last parent container {@link Group} this shape has been added to or {@code null}.
* <p>
@@ -500,17 +501,17 @@ public abstract class Shape {
return this;
}
- private final Shape moveNotify(final float dtx, final float dty, final float dtz) {
- forwardMove(position.copy(), position.add(dtx, dty, dtz));
- return this;
- }
-
/** Move about scaled distance. Position ends up in PMVMatrix4f unmodified. No {@link MoveListener} notification will occur. */
public final Shape move(final Vec3f dt) {
position.add(dt);
return this;
}
+ private final Shape moveNotify(final float dtx, final float dty, final float dtz) {
+ forwardMove(position.copy(), position.add(dtx, dty, dtz));
+ return this;
+ }
+
private final void forwardMove(final Vec3f origin, final Vec3f dest) {
if( !origin.isEqual(dest) ) {
if( null != onMoveListener ) {
@@ -1389,7 +1390,7 @@ public abstract class Shape {
releaseInteraction();
final Tooltip tt = tooltip;
if( null != tt ) {
- tt.stop();
+ tt.stop(false);
}
}
if( DEBUG ) {
@@ -1429,7 +1430,7 @@ public abstract class Shape {
final Tooltip oldTT = this.tooltip;
this.tooltip = null;
if( null != oldTT ) {
- oldTT.stop();
+ oldTT.stop(true);
}
newTooltip.setTool(this);
this.tooltip = newTooltip;
@@ -1439,21 +1440,31 @@ public abstract class Shape {
final Tooltip tt = tooltip;
tooltip = null;
if( null != tt ) {
- tt.stop();
+ tt.stop(true);
tt.setTool(null);
}
}
private void stopToolTip() {
final Tooltip tt = tooltip;
if( null != tt ) {
- tt.stop();
+ tt.stop(true);
}
}
- /* pp */ Tooltip startToolTip() {
- final Tooltip tt = tooltip;
+ /* pp */ Tooltip startToolTip(final boolean lookupParents) {
+ Tooltip tt = tooltip;
if( null != tt ) {
tt.start();
return tt;
+ } else if( lookupParents ) {
+ Shape p = getParent();
+ while( null != p ) {
+ tt = p.startToolTip(false);
+ if( null != tt ) {
+ return tt;
+ } else {
+ p = p.getParent();
+ }
+ }
}
return null;
}
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java b/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java
index 7bed984f5..b7a79b4ca 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java
@@ -47,12 +47,18 @@ public abstract class Tooltip {
private final long delayMS;
/** Delay t1, time to show tooltip, i.e. t0 + delayMS */
private volatile long delayT1;
+ /** Toggle for forced tooltip display */
+ private volatile boolean forced;
/** Shape 'tool' owning this tooltip. */
private Shape tool;
protected final int renderModes;
protected final Vec4f backColor = new Vec4f(1, 1, 0, 1);
protected final Vec4f frontColor = new Vec4f(0.1f, 0.1f, 0.1f, 1);
+ @Override
+ public String toString() {
+ return "Tooltip[d "+delayMS+", next "+delayT1+", forced "+forced+"]";
+ }
/**
*
* @param backColor optional HUD tip background color
@@ -63,6 +69,7 @@ public abstract class Tooltip {
protected Tooltip(final Vec4f backColor, final Vec4f frontColor, final long delayMS, final int renderModes) {
this.delayMS = delayMS;
this.delayT1 = 0;
+ this.forced = false;
this.tool = null;
this.renderModes = renderModes;
if( null != backColor ) {
@@ -79,19 +86,45 @@ public abstract class Tooltip {
return tool;
}
- /** Stops the timer. */
- public final void stop() {
- this.delayT1 = 0;
+ /**
+ * Stops the timer if not enforced via {@link #now()} or {@code clearForced} is true.
+ * @param clearForced if true, also clears enforced flag set by {@link #now()}
+ * @return true if timer has been stopped, otherwise false
+ */
+ public final boolean stop(final boolean clearForced) {
+ if( clearForced ) {
+ this.delayT1 = 0;
+ this.forced = false;
+ return true;
+ } else if( !this.forced ) {
+ this.delayT1 = 0;
+ return true;
+ } else {
+ return false;
+ }
}
/** Starts the timer. */
public final void start() {
- this.delayT1 = Clock.currentMillis() + delayMS;
+ if( !this.forced ) {
+ this.delayT1 = Clock.currentMillis() + delayMS;
+ }
+ }
+
+ /** Enforce tooltip display with next {@link #tick()}. */
+ public final void now() {
+ this.forced = true;
+ this.delayT1 = Clock.currentMillis() - 1;
+ }
+
+ /** Returns true if display is enforced via {@link #now()}. */
+ public final boolean forced() {
+ return forced;
}
/**
* Send tick to this tooltip
- * @return true if timer has been reached to {@link #createTip(PMVMatrix4f)}, otherwise false
+ * @return true if {@link #start() started} timer has been reached or is enforced via {@link #now()} to {@link #createTip(PMVMatrix4f)}, otherwise false
*/
public final boolean tick() {
if( 0 == delayT1 ) {
@@ -101,6 +134,7 @@ public abstract class Tooltip {
return false;
}
this.delayT1 = 0;
+ this.forced = false;
return true;
}
@@ -136,7 +170,7 @@ public abstract class Tooltip {
* @param drawable current {@link GLAutoDrawable}
* @param scene the {@link Scene} caller for which this HUD tip shape is created
* @param pmv {@link PMVMatrix4f}, which shall be properly initialized, e.g. via {@link Scene#setupMatrix(PMVMatrix4f)}
- * @param toolMvBounds TODO
+ * @param toolMvBounds {@link AABBox} of the {@link #getTool()} in model-view (Mv) space of the given {@link Scene}
* @return newly created HUD tip shape
* @see #destroyTip(GL2ES2, RegionRenderer, Shape)
*/
diff --git a/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java b/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java
index ec3dbf45f..40cc8c66d 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java
@@ -30,7 +30,6 @@ package com.jogamp.graph.ui;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.graph.ui.layout.Alignment;
import com.jogamp.graph.ui.layout.BoxLayout;
-import com.jogamp.graph.ui.layout.GridLayout;
import com.jogamp.graph.ui.shapes.Rectangle;
import com.jogamp.math.Vec2f;
import com.jogamp.math.Vec4f;
@@ -50,7 +49,7 @@ public class TooltipShape extends Tooltip {
* </p>
* @param gl
* @param renderer
- * @param tip
+ * @param tip the user provided {@link Shape} as passed via {@link TooltipShape#TooltipShape(Vec4f, Vec4f, float, Vec2f, long, int, Shape, DestroyCallback)}.
* @see TooltipShape#TooltipShape(Vec2f, long, Shape, DestroyCallback)
* @see TooltipShape#createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox)
*/
@@ -106,8 +105,9 @@ public class TooltipShape extends Tooltip {
final float h = toolMvBounds.getHeight()*scale.y();
final Group g = new Group(new BoxLayout(w, h, Alignment.FillCenter));
- g.addShape(new Rectangle(renderModes, 1*w/h, 1, 0).setColor(backColor).setBorder(borderThickness).setBorderColor(frontColor));
- g.addShape(tip.move(0, 0, zEps)); // above back
+ g.addShape(new Rectangle(renderModes, 1*w/h, 1, 0).setColor(backColor).setBorder(borderThickness).setBorderColor(frontColor).move(0, 0, -zEps));
+ g.setName("TooltipShapeGroup");
+ g.addShape(tip);
g.setInteractive(false);
final Vec2f pos = getTipMvPosition(scene, toolMvBounds, w, h);
@@ -115,11 +115,15 @@ public class TooltipShape extends Tooltip {
return g;
}
@Override
- public void destroyTip(final GL2ES2 gl, final RegionRenderer renderer, final Shape tip) {
+ public void destroyTip(final GL2ES2 gl, final RegionRenderer renderer, final Shape tipGroup) {
if( null != dtorCallback ) {
+ // Remove user tip from our layout group first and dtor our group
+ // This allows the user to receive its own passed tip
+ ((Group)tipGroup).removeShape(tip);
+ tipGroup.destroy(gl, renderer);
dtorCallback.destroyTip(gl, renderer, tip);
} else {
- super.destroyTip(gl, renderer, tip);
+ super.destroyTip(gl, renderer, tipGroup);
}
}
}