diff options
4 files changed, 102 insertions, 63 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java index ff1bebbd5..7e45b44b1 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java @@ -906,9 +906,9 @@ public final class Scene implements Container, GLEventListener { private float activeZOffsetScale = DEFAULT_ACTIVE_ZOFFSET_SCALE; private float activeTopLevelZOffsetScale = DEFAULT_ACTIVE_TOPLEVEL_ZOFFSET_SCALE; - /** Returns the active {@link Shape} Z-Offset scale, defaults to {@code 10.0}. */ + /** Returns the active {@link Shape} Z-Offset scale, defaults to {@link #DEFAULT_ACTIVE_ZOFFSET_SCALE}. */ public float getActiveShapeZOffsetScale() { return activeZOffsetScale; } - /** Sets the active {@link Shape} Z-Offset scale, defaults to {@code 10.0}. */ + /** Sets the active {@link Shape} Z-Offset scale, defaults to {@link #DEFAULT_ACTIVE_ZOFFSET_SCALE}. */ public void setActiveShapeZOffsetScale(final float v) { activeZOffsetScale = v; } /** Returns the general {@link Group#enableTopLevelWidget(Scene) top-level widget} Z-Offset scale, defaults to {@link #DEFAULT_ACTIVE_ZOFFSET_SCALE}. */ @@ -1347,7 +1347,7 @@ public final class Scene implements Container, GLEventListener { final Shape[] hud = { null }; if( tt.tick() && TreeTool.forOne(this, pmv, tt.getTool(), () -> { final AABBox toolMvBounds = tt.getToolMvBounds(pmv); - hud[0] = tt.createTip(drawable, Scene.this, pmv, toolMvBounds); + hud[0] = tt.createTip(Scene.this, toolMvBounds); }) ) { setToolTip( hud[0] ); diff --git a/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java b/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java index c8ab813aa..5aafa7bd9 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Tooltip.java @@ -32,11 +32,11 @@ import com.jogamp.graph.curve.Region; import com.jogamp.graph.curve.opengl.GLRegion; import com.jogamp.graph.curve.opengl.RegionRenderer; import com.jogamp.math.Vec2f; +import com.jogamp.math.Vec3f; import com.jogamp.math.Vec4f; import com.jogamp.math.geom.AABBox; import com.jogamp.math.util.PMVMatrix4f; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.util.texture.TextureSequence; @@ -56,8 +56,8 @@ public abstract class Tooltip { private Shape tool; /** Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. */ protected final int renderModes; - protected final Vec4f backColor = new Vec4f(0.9f, 0.9f, 0.9f, 0.9f); - protected final Vec4f frontColor = new Vec4f(0.1f, 0.1f, 0.1f, 0.9f); + protected final Vec4f backColor = new Vec4f(1, 1, 1, 0.9f); + protected final Vec4f frontColor = new Vec4f(0.2f, 0.2f, 0.2f, 1); @Override public String toString() { @@ -65,8 +65,8 @@ public abstract class Tooltip { } /** * - * @param backColor optional HUD tip background color, if null a slightly transparent light-grey background is used - * @param frontColor optional HUD tip front color, if null an slightly transparent almost-black is used + * @param backColor optional HUD tip background color, if null a slightly transparent white background is used + * @param frontColor optional HUD tip front color, if null an opaque almost-black is used * @param delayMS delay until HUD tip is visible after timer start (mouse moved), zero implies no time based alarm * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. */ @@ -142,22 +142,32 @@ public abstract class Tooltip { return true; } - /** Little helper for {@link #createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox)} returning the Mv {@link AABBox} of the tool within {@link Scene} Mv space. */ + /** + * Little helper for {@link #createTip(Scene, AABBox)} returning the Mv {@link AABBox} of the tool within {@link Scene} Mv space. + * <p> + * Method uses {@link #getTool()} + * <pre> + * return getTool().getBounds().transform(pmv.getMv(), new AABBox()); + * </pre> + * </p> + */ public AABBox getToolMvBounds(final PMVMatrix4f pmv) { return getTool().getBounds().transform(pmv.getMv(), new AABBox()); } - /** Little helper for {@link #createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox)} returning the Mv position of the tip within {@link Scene} Mv space. */ + /** Little helper for {@link #createTip(Scene, AABBox)} returning the Mv position of the tip within {@link Scene} Mv space. */ public Vec2f getTipMvPosition(final Scene scene, final PMVMatrix4f pmv, final float tipWidth, final float tipHeight) { return getTipMvPosition(scene, getToolMvBounds(pmv), tipWidth, tipHeight); } - /** Little helper for {@link #createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox)} returning the Mv position of the tip within {@link Scene} Mv space. */ + /** Little helper for {@link #createTip(Scene, AABBox)} returning the Mv position of the tip @ center within {@link Scene} Mv space. */ public Vec2f getTipMvPosition(final Scene scene, final AABBox toolMvBounds, final float tipWidth, final float tipHeight) { final AABBox sceneAABox = scene.getBounds(); final Vec2f pos = new Vec2f(); - if( toolMvBounds.getCenter().x() - tipWidth/2 >= sceneAABox.getLow().x() ) { - pos.setX( toolMvBounds.getCenter().x()-tipWidth/2 ); - } else { + if( toolMvBounds.getCenter().x() - tipWidth/2 < sceneAABox.getLow().x() ) { pos.setX( sceneAABox.getLow().x() ); + } else if( toolMvBounds.getCenter().x() + tipWidth/2 > sceneAABox.getHigh().x() ) { + pos.setX( sceneAABox.getHigh().x() - tipWidth); + } else { + pos.setX( toolMvBounds.getCenter().x()-tipWidth/2 ); } if( toolMvBounds.getCenter().y() + tipHeight <= sceneAABox.getHigh().y() ) { pos.setY( toolMvBounds.getCenter().y() ); @@ -168,20 +178,36 @@ public abstract class Tooltip { } return pos; } + /** Little helper for {@link #createTip(Scene, AABBox)} returning the Mv position of the tip @ center within {@link Scene} Mv space. */ + public Vec2f getTipMvPosition(final Scene scene, final Vec3f toolMvPos, final float tipWidth, final float tipHeight) { + final AABBox sceneAABox = scene.getBounds(); + final Vec2f pos = new Vec2f(); + if( toolMvPos.x() - tipWidth/2 < sceneAABox.getLow().x() ) { + pos.setX( sceneAABox.getLow().x() ); + } else if( toolMvPos.x() + tipWidth/2 > sceneAABox.getHigh().x() ) { + pos.setX( sceneAABox.getHigh().x() - tipWidth); + } else { + pos.setX( toolMvPos.x()-tipWidth/2 ); + } + if( toolMvPos.y() + tipHeight <= sceneAABox.getHigh().y() ) { + pos.setY( toolMvPos.y() ); + } else { + pos.setY( sceneAABox.getHigh().y() - tipHeight ); + } + return pos; + } /** * Create a new HUD tip shape, usually called by {@link Scene} - * @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 {@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) */ - public abstract Shape createTip(final GLAutoDrawable drawable, final Scene scene, final PMVMatrix4f pmv, AABBox toolMvBounds); + public abstract Shape createTip(final Scene scene, AABBox toolMvBounds); /** - * Destroy a {@link #createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox) created} HUD tip. + * Destroy a {@link #createTip(Scene, AABBox) created} HUD tip. * <p> * Called after {@link Scene#removeShape(Shape)}, allowing implementation to perform certain * resource cleanup tasks. Even keeping the {@link Shape} tip alive is possible. @@ -191,8 +217,8 @@ public abstract class Tooltip { * </p> * @param gl current {@link GL2ES2} * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param tip - * @see #createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox) + * @param tip created tip {@link Shape} via {@link #createTip(Scene, AABBox)} + * @see #createTip(Scene, AABBox) */ public void destroyTip(final GL2ES2 gl, final RegionRenderer renderer, final Shape tip) { tip.destroy(gl, renderer); diff --git a/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java b/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java index f8152635d..82ad63ace 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java +++ b/src/graphui/classes/com/jogamp/graph/ui/TooltipShape.java @@ -37,15 +37,13 @@ import com.jogamp.graph.ui.shapes.Rectangle; import com.jogamp.math.Vec2f; import com.jogamp.math.Vec4f; import com.jogamp.math.geom.AABBox; -import com.jogamp.math.util.PMVMatrix4f; import com.jogamp.opengl.GL2ES2; -import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.util.texture.TextureSequence; import jogamp.graph.ui.TreeTool; -/** A HUD {@link Shape} {@link Tooltip} for {@link Shape}, see {@link Shape#setToolTip(Tooltip)}. */ +/** A HUD {@link Shape} {@link Tooltip} for client {@link Shape}, see {@link Shape#setToolTip(Tooltip)}. */ public class TooltipShape extends Tooltip { /** * Optional HUD tip {@link #destroy(TooltipShape, GL2ES2, RegionRenderer, Shape) destroy callback} @@ -60,7 +58,7 @@ public class TooltipShape extends Tooltip { * the provided implementation shall do nothing, i.e. use {@link TooltipShape#NoOpDtor}. * </p> * @see TooltipShape#TooltipShape(Vec2f, long, Shape, DestroyCallback) - * @see TooltipShape#createTip(GLAutoDrawable, Scene, PMVMatrix4f, AABBox) + * @see TooltipShape#createTip(Scene, AABBox) */ public static interface DestroyCallback { /** @@ -79,7 +77,7 @@ public class TooltipShape extends Tooltip { }; /** Shape of this tooltip */ - private volatile Shape tip; + private final Shape clientShape; private final Vec2f scale; private final float borderThickness; private final Padding padding; @@ -88,73 +86,73 @@ public class TooltipShape extends Tooltip { /** * Ctor of {@link TooltipShape}. * <p> - * The {@link Shape} is destroyed via {@link #destroyTip(GL2ES2, RegionRenderer, Shape)}, + * The tip {@link Shape} including the user provided {@code clientShape} will be destroyed via {@link #destroyTip(GL2ES2, RegionRenderer, Shape)}, * since no {@link DestroyCallback} is being provided via {@link TooltipShape#TooltipShape(Vec2f, long, Shape, DestroyCallback)}. * </p> * @param scale HUD tip scale for the tip shape * @param delayMS delay until HUD tip is visible after timer start (mouse moved) * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param tip HUD tip shape + * @param clientShape user/client {@link Shape} to be presented in the HUD tip */ - public TooltipShape(final Vec2f scale, final long delayMS, final int renderModes, final Shape tip) { - this(null, null, 0, null, scale, delayMS, renderModes, tip, null); + public TooltipShape(final Vec2f scale, final long delayMS, final int renderModes, final Shape clientShape) { + this(null, null, 0, null, scale, delayMS, renderModes, clientShape, null); } /** * Ctor of {@link TooltipShape}. * <p> - * The {@link Shape} is destroyed via provided {@link DestroyCallback} {@code dtor} if not {@code null}, + * The tip {@link Shape} will be destroyed via provided {@link DestroyCallback} {@code dtor} if not {@code null}, * otherwise the default {@link Tooltip#destroyTip(GL2ES2, RegionRenderer, Shape)} gets called. * </p> * <p> - * In case {@link DestroyCallback} {@code dtor} is being used, the user {@code tip} - * is removed from internal layout shapes before they get destroyed and the single {@code tip} + * In case {@link DestroyCallback} {@code dtor} is being used, the user {@code clientShape} + * is removed from internal layout shapes before they get destroyed and the single {@code clientShape} * gets passed to {@link DestroyCallback#destroy(TooltipShape, GL2ES2, RegionRenderer, Shape)}. * </p> * <p> - * In case user provided {@code tip} is reused within a DAG, + * In case user provided {@code clientShape} is reused within a DAG, * the provided implementation shall do nothing, i.e. use {@link TooltipShape#NoOpDtor}. * </p> * @param backColor optional background color * @param borderColor optional border color * @param borderThickness border thickness - * @param padding optional padding for the given {@code tip} for the internal wrapper group - * @param scale HUD tip scale for the tip shape + * @param padding optional padding for the given {@code clientShape} for the internal wrapper group + * @param scale scale for the HUD tip * @param delayMS delay until HUD tip is visible after timer start (mouse moved) * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. - * @param tip HUD tip shape + * @param clientShape user/client {@link Shape} to be presented in the HUD tip * @param dtor optional {@link DestroyCallback} */ public TooltipShape(final Vec4f backColor, final Vec4f borderColor, final float borderThickness, final Padding padding, final Vec2f scale, - final long delayMS, final int renderModes, final Shape tip, final DestroyCallback dtor) { + final long delayMS, final int renderModes, final Shape clientShape, final DestroyCallback dtor) { super(backColor, borderColor, delayMS, renderModes); - this.tip = tip; + this.clientShape = clientShape; this.scale = scale; this.borderThickness = borderThickness; this.padding = padding; this.dtorCallback = dtor; } - public void setTip(final Shape tip) { - this.tip = tip; - } + public Shape getClientShape() { return this.clientShape; } @Override - public Shape createTip(final GLAutoDrawable drawable, final Scene scene, final PMVMatrix4f pmv, final AABBox toolMvBounds) { + public Shape createTip(final Scene scene, final AABBox toolMvBounds) { final float zEps = scene.getZEpsilon(16); final float w = toolMvBounds.getWidth()*scale.x(); final float h = toolMvBounds.getHeight()*scale.y(); - // tipWrapper ensures user 'tip' shape won't get mutated (scale, move) for DAG - final Group tipWrapper = new Group("TTSWrapper", null, null, tip); + // tipWrapper ensures user 'clientShape' won't get mutated (scale, move) for DAG + final Group tipWrapper = new Group("TTS.wrapper", null, null, clientShape); if( null != padding ) { tipWrapper.setPaddding(padding); } final Group tipGroup = new Group(new BoxLayout(w, h, Alignment.FillCenter)); - tipGroup.addShape(new Rectangle(renderModes, 1*w/h, 1, 0).setColor(backColor).setBorder(borderThickness).setBorderColor(frontColor).move(0, 0, -zEps)); - tipGroup.setName("TTSGroup"); + tipGroup.addShape(new Rectangle(renderModes, 1*w/h, 1, 0).setColor(backColor) + .setBorder(borderThickness).setBorderColor(frontColor) + .setName("TTS.frame").move(0, 0, -zEps)); + tipGroup.setName("TTS.group"); tipGroup.addShape(tipWrapper); tipGroup.setInteractive(false); @@ -162,24 +160,41 @@ public class TooltipShape extends Tooltip { tipGroup.moveTo(pos.x(), pos.y(), 100*zEps); return tipGroup; } - @Override - 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 - final Group tipGroup = (Group)tipGroup_; + + /** + * Removed the user provided client {@link Shape} from the {@link #createTip(Scene, AABBox) created} HUD {@code tipGroup}, + * i.e. {@link TooltipShape}'s layout {@link Group}. + * <p> + * This allows the user to release its own passed tip back, e.g. before destruction. + * </p> + * @param tip created tip {@link Shape} via {@link #createTip(Scene, AABBox)} + * @return the user provided client {@link Shape} + * @see #createTip(Scene, AABBox) + */ + public Shape removeTip(final Shape tip) { + final Shape cs = clientShape; + if( null != cs ) { + final Group tipGroup = (Group)tip; final Group tipWrapper = (Group)tipGroup.getShapeByIdx(1); - if( null == tipWrapper.removeShape(tip) ) { - System.err.println("TooltipShape.destroyTip: Warning: Tip "+tip.getName()+" not contained in "+tipWrapper.getName()+"; Internal Group: "); + if( null == tipWrapper.removeShape(cs) ) { + System.err.println("TooltipShape.destroyTip: Warning: ClientShape "+cs.getName()+" not contained in "+tipWrapper.getName()+"; Internal Group: "); TreeTool.forAll(tipGroup, (final Shape s) -> { System.err.println("- "+s.getName()); return false; }); } - tipGroup.destroy(gl, renderer); - dtorCallback.destroy(this, gl, renderer, tip); + } + return cs; + } + + @Override + public void destroyTip(final GL2ES2 gl, final RegionRenderer renderer, final Shape tip) { + if( null != dtorCallback ) { + final Shape cs = removeTip(tip); + tip.destroy(gl, renderer); + dtorCallback.destroy(this, gl, renderer, cs); } else { - super.destroyTip(gl, renderer, tipGroup_); + super.destroyTip(gl, renderer, tip); } } } diff --git a/src/graphui/classes/com/jogamp/graph/ui/TooltipText.java b/src/graphui/classes/com/jogamp/graph/ui/TooltipText.java index b02c420cf..b8947c37c 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/TooltipText.java +++ b/src/graphui/classes/com/jogamp/graph/ui/TooltipText.java @@ -36,8 +36,6 @@ import com.jogamp.math.Vec2f; import com.jogamp.math.Vec4f; import com.jogamp.math.geom.AABBox; import com.jogamp.math.geom.plane.AffineTransform; -import com.jogamp.math.util.PMVMatrix4f; -import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLProfile; /** A round {@link Button HUD text} {@link Tooltip} for {@link Shape}, see {@link Shape#setToolTip(Tooltip)}. */ @@ -52,8 +50,8 @@ public class TooltipText extends Tooltip { * Ctor of {@link TooltipText}. * @param tipText HUD tip text * @param tipFont HUD tip font - * @param backColor HUD tip background color - * @param labelColor HUD tip label color + * @param backColor optional HUD tip background color, if null a slightly transparent white background is used + * @param labelColor optional HUD tip front color, if null an opaque almost-black is used * @param scaleY HUD tip vertical scale against tool height * @param delayMS delay until HUD tip is visible after timer start (mouse moved) * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}. @@ -68,7 +66,7 @@ public class TooltipText extends Tooltip { } /** * Ctor of {@link TooltipText} using {@link Tooltip#DEFAULT_DELAY}, {@link Region#VBAA_RENDERING_BIT} - * and a slightly transparent light-grey background with an slightly transparent almost-black text color. + * and a slightly transparent white background with an opaque almost-black text color. * @param tipText HUD tip text * @param tipFont HUD tip font * @param scaleY HUD tip vertical scale against tool height @@ -79,7 +77,7 @@ public class TooltipText extends Tooltip { } @Override - public Shape createTip(final GLAutoDrawable gl, final Scene scene, final PMVMatrix4f pmv, final AABBox toolMvBounds) { + public Shape createTip(final Scene scene, final AABBox toolMvBounds) { final float zEps = scene.getZEpsilon(16); // Precompute text-box size .. guessing pixelSize |