aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui/classes
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2023-12-24 19:12:52 +0100
committerSven Gothel <[email protected]>2023-12-24 19:12:52 +0100
commitc6e39c6e313a34688ca0164d7a34b6465e92396f (patch)
treeca74beed22defac6f26f7ef82f228ff83a339e61 /src/graphui/classes
parentb5e6a852451f2a78a1783ca8fbd704005fbafd07 (diff)
GraphUI RangeSlider Widget: Add rectangular page-sized knob mode using a 'page size' of covered view. Resolve color-setup.
Tested with FontView01
Diffstat (limited to 'src/graphui/classes')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java12
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/RangeSlider.java420
2 files changed, 357 insertions, 75 deletions
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 3fc48306a..799a9e8ad 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/MediaPlayer.java
@@ -128,10 +128,14 @@ public class MediaPlayer extends Widget {
mButton.setName("mp.mButton").setInteractive(false);
mButton.setPerp().setPressedColorMod(1f, 1f, 1f, 0.85f);
- final RangeSlider ctrlSlider = new RangeSlider(renderModes, aratio, ctrlSliderHeight, 4.0f, 0, 100, 0);
+ final RangeSlider ctrlSlider;
{
- final float dy = ( ctrlSlider.getKnobSize() - ctrlSliderHeight ) * 0.5f;
- ctrlSlider.setPaddding(new Padding(0, 0, ctrlCellHeight-dy, 0));
+ final float knobScale = 3f;
+ final float knobHeight = ctrlSliderHeight * knobScale;
+ ctrlSlider = new RangeSlider(renderModes, new Vec2f(aratio - knobHeight, ctrlSliderHeight), knobScale, new Vec2f(0, 100), 0);
+ final float dx = knobHeight / 2f;
+ final float dy = ( knobHeight - ctrlSliderHeight ) * 0.5f;
+ ctrlSlider.setPaddding(new Padding(0, dx, ctrlCellHeight-dy, dx));
}
ctrlSlider.setName("mp.slider");
@@ -153,7 +157,7 @@ public class MediaPlayer extends Widget {
// System.err.println("MediaButton State: "+mp);
if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Init) ) {
System.err.println(mp.toString());
- ctrlSlider.setMinMax(0, mp.getDuration(), 0);
+ ctrlSlider.setMinMax(new Vec2f(0, mp.getDuration()), 0);
} else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Play) ) {
playButton.setToggle(true);
} else if( eventMask.isSet(GLMediaPlayer.EventMask.Bit.Pause) ) {
diff --git a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangeSlider.java b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangeSlider.java
index 495d81149..f6498974e 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangeSlider.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangeSlider.java
@@ -32,20 +32,26 @@ import com.jogamp.graph.curve.opengl.GLRegion;
import com.jogamp.graph.curve.opengl.RegionRenderer;
import com.jogamp.graph.ui.Group;
import com.jogamp.graph.ui.Shape;
+import com.jogamp.graph.ui.layout.Padding;
import com.jogamp.graph.ui.shapes.BaseButton;
import com.jogamp.graph.ui.shapes.Button;
import com.jogamp.graph.ui.shapes.Rectangle;
import com.jogamp.math.Vec2f;
import com.jogamp.math.Vec3f;
import com.jogamp.math.Vec4f;
+import com.jogamp.newt.event.KeyAdapter;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseEvent;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.util.texture.TextureSequence;
/**
- * RangeSlider {@link Widget}
- * @see #RangeSlider(int, float, float, float, float, float, float)
+ * RangeSlider {@link Widget} either utilizing a simple positional round knob
+ * or a rectangular page-sized knob.
+ * @see #RangeSlider(int, Vec2f, float, Vec2f, float)
+ * @see #RangeSlider(int, Vec2f, Vec2f, float, float)
*/
public final class RangeSlider extends Widget {
/**
@@ -59,7 +65,7 @@ public final class RangeSlider extends Widget {
/** Slider released down by user. */
void released(RangeSlider w, final MouseEvent e);
/**
- * Slide dragged by user
+ * Slide dragged by user (including clicked position)
* @param w the {@link RangeSlider} widget owning the slider
* @param old_val previous absolute value position of the slider
* @param val the absolute value position of the slider
@@ -69,60 +75,115 @@ public final class RangeSlider extends Widget {
void dragged(RangeSlider w, float old_val, float val, float old_val_pct, float val_pct);
}
+ private static final float pageKnobScale = 0.6f; // 0.6 * barWidth
+ private static final float pageBarLineScale = 0.25f; // 1/4 * ( barWidth - pageKnobWidth )
+ private static final float pageKnobSizePctMin = 5f/100f;
private final boolean horizontal;
- private final float knobSz;
- private final float width, height;
+ /** Width of knob orthogonal to sliding direction */
+ private float knobDiameter;
+ /** Half length of knob in sliding direction */
+ private float knobHalfLen;
+ private final Vec2f size;
private final Group barAndKnob;
private final Rectangle bar;
- private final BaseButton knob;
- private final Vec4f colBar = new Vec4f(0, 0, 1, 1);
- private final Vec4f colKnob = new Vec4f(1, 0, 0, 1);
+ private final Shape knob;
private SliderListener sliderListener = null;
- private float min, max;
- private float val, val_pct;
+ private final Vec2f minMax = new Vec2f(0, 100);
+ private float pageSize;
+ private float val=0, val_pct=0;
+ private boolean inverted=false;
/**
* Constructs a {@link RangeSlider}, i.e. its shapes and controls.
+ * <p>
+ * This slider comprises a background bar and a positional round knob.
+ * </p>
* @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
- * @param width width of this slider box. A horizontal slider has width >= height.
- * @param height height of this slider box. A vertical slider has width < height.
- * @param knobScale multiple of slider-bar height for {@link #getKnobSize()}
- * @param min minimum value of slider
- * @param max maximum value of slider
+ * @param size width and height of this slider box. A horizontal slider has width >= height.
+ * @param knobScale multiple of slider-bar height for {@link #getKnobHeight()}
+ * @param minMax minimum- and maximum-value of slider
* @param value current value of slider
*/
- public RangeSlider(final int renderModes, final float width, final float height, final float knobScale,
- final float min, final float max, final float value) {
- this.horizontal = width >= height;
- if( horizontal ) {
- knobSz = height*knobScale;
- this.width = width - knobSz; // half knobSz left and right
- this.height = height;
+ public RangeSlider(final int renderModes, final Vec2f size, final float knobScale,
+ final Vec2f minMax, final float value) {
+ this(renderModes, size, knobScale, minMax, Float.NaN, value);
+ }
+ /**
+ * Constructs a {@link RangeSlider}, i.e. its shapes and controls.
+ * <p>
+ * This slider comprises a framing bar and a rectangular page-sized knob.
+ * </p>
+ * @param renderModes Graph's {@link Region} render modes, see {@link GLRegion#create(GLProfile, int, TextureSequence) create(..)}.
+ * @param size width and height of this slider box. A horizontal slider has width >= height.
+ * @param minMax minimum- and maximum-value of slider
+ * @param pageSize size of one virtual-page, triggers rendering mode from knob to rectangle
+ * @param value current value of slider
+ */
+ public RangeSlider(final int renderModes, final Vec2f size,
+ final Vec2f minMax, final float pageSize, final float value) {
+ this(renderModes, size, 0, minMax, pageSize, value);
+ }
+ private RangeSlider(final int renderModes_, final Vec2f size, final float knobScale,
+ final Vec2f minMax, final float pageSz, final float value) {
+ // final int renderModes = ( renderModes_ & ~Region.AA_RENDERING_MASK ) | Region.COLORCHANNEL_RENDERING_BIT;
+ final int renderModes = renderModes_ & ~(Region.AA_RENDERING_MASK | Region.COLORCHANNEL_RENDERING_BIT);
+ this.pageSize = pageSz;
+ this.horizontal = size.x() >= size.y();
+ barAndKnob = new Group();
+ barAndKnob.setInteractive(true).setToggleable(false).setDraggable(false).setResizable(false);
+ this.size = new Vec2f(size);
+ if( Float.isNaN(pageSize) ) {
+ if( horizontal ) {
+ knobDiameter = size.y()*knobScale;
+ setPaddding(new Padding(knobHalfLen, 0, knobHalfLen, 0));
+ } else {
+ knobDiameter = size.x()*knobScale;
+ setPaddding(new Padding(0, knobHalfLen, 0, knobHalfLen));
+ }
+ knobHalfLen = knobDiameter * 0.5f;
+ bar = new Rectangle(renderModes, this.size.x(), this.size.y(), 0);
+ knob = new BaseButton(renderModes , knobDiameter*1.01f, knobDiameter);
+ setBackgroundBarColor(0.60f, 0.60f, 0.60f, 0.5f);
} else {
- knobSz = width*knobScale;
- this.width = width;
- this.height = height - knobSz; // half knobSz bottom and top
+ final float pageSizePct = Math.max(pageKnobSizePctMin, pageSize / getRange(minMax));
+ final float barLineWidth;
+ final float knobWidth, knobHeight;
+ if( horizontal ) {
+ knobHeight = size.y() * pageKnobScale;
+ knobWidth = pageSizePct * this.size.x();
+ barLineWidth = ( size.y() - knobHeight ) * pageBarLineScale;
+ knobHalfLen = knobWidth * 0.5f;
+ knobDiameter = knobHeight;
+ setPaddding(new Padding(size.y(), 0, size.y(), 0));
+ } else {
+ knobWidth = size.x() * pageKnobScale;
+ knobHeight = pageSizePct * this.size.y();
+ barLineWidth = ( size.x() - knobWidth ) * pageBarLineScale;
+ knobHalfLen = knobHeight * 0.5f;
+ knobDiameter = knobWidth;
+ setPaddding(new Padding(0, size.x(), 0, size.x()));
+ // System.err.println("ZZZ minMax "+minMax+", pageSize "+pageSize+" "+(pageSizePct*100f)+"% -> "+knobHeight+"/"+this.size.y());
+ }
+ bar = new Rectangle(renderModes, this.size.x(), this.size.y(), barLineWidth);
+ knob = new Rectangle(renderModes, knobWidth, knobHeight, 0);
}
- barAndKnob = new Group();
- barAndKnob.setInteractive(true).setDraggable(false).setToggleable(false);
- bar = new Rectangle(renderModes & ~Region.AA_RENDERING_MASK, this.width, this.height, 0);
- bar.setToggleable(false);
- bar.setColor(colBar);
- knob = new BaseButton(renderModes & ~Region.AA_RENDERING_MASK, knobSz*1.01f, knobSz);
- knob.setToggleable(false);
- knob.setColor(colKnob);
+ setColor(0.30f, 0.30f, 0.30f, 1.0f);
+
+ bar.setToggleable(false).setInteractive(false);
+ bar.setDraggable(false).setResizable(false);
+
+ knob.setToggleable(false).setResizable(false);
setName(getName());
barAndKnob.addShape( bar );
barAndKnob.addShape( knob );
addShape(barAndKnob);
- setMinMax(min, max, value);
+ setMinMax(minMax, value);
knob.onMove((final Shape s, final Vec3f origin, final Vec3f dest) -> {
final float old_val = val;
final float old_val_pct = val_pct;
- setValuePct( getKnobValuePct( dest.x(), dest.y(), knobSz*0.5f ) );
- // System.err.println("KnobMove "+getName()+": "+origin+" -> "+dest+": "+old_val+" -> "+val+", "+(old_val_pct*100f)+"% -> "+(val_pct*100f)+"%");
+ setValuePct( getKnobValuePct( dest.x(), dest.y(), knobHalfLen ) );
if( null != sliderListener ) {
sliderListener.dragged(this, old_val, val, old_val_pct, val_pct);
}
@@ -130,19 +191,61 @@ public final class RangeSlider extends Widget {
barAndKnob.addMouseListener(new Shape.MouseGestureAdapter() {
@Override
public void mouseClicked(final MouseEvent e) {
+ final float old_val = val;
+ final float old_val_pct = val_pct;
final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment();
setValuePct( getKnobValuePct( shapeEvent.objPos.x(), shapeEvent.objPos.y(), 0 ) );
if( null != sliderListener ) {
+ sliderListener.dragged(RangeSlider.this, old_val, val, old_val_pct, val_pct);
sliderListener.clicked(RangeSlider.this, e);
}
}
+ @Override
+ public void mouseWheelMoved(final MouseEvent e) {
+ final float old_val = val;
+ final float old_val_pct = val_pct;
+ float v = old_val;
+ if( !e.isControlDown() ) {
+ if( e.getRotation()[1] < 0f ) {
+ if( inverted ) {
+ v++;
+ } else {
+ v--;
+ }
+ } else {
+ if( inverted ) {
+ v--;
+ } else {
+ v++;
+ }
+ }
+ } else if( !Float.isNaN(pageSize) ){
+ if( e.getRotation()[1] < 0f ) {
+ if( inverted ) {
+ v+=pageSize;
+ } else {
+ v-=pageSize;
+ }
+ } else {
+ if( inverted ) {
+ v-=pageSize;
+ } else {
+ v+=pageSize;
+ }
+ }
+ }
+ setValue( v );
+ if( null != sliderListener ) {
+ sliderListener.dragged(RangeSlider.this, old_val, val, old_val_pct, val_pct);
+ }
+ }
});
knob.addMouseListener(new Shape.MouseGestureAdapter() {
@Override
public void mouseClicked(final MouseEvent e) {
- if( null != sliderListener ) {
- sliderListener.clicked(RangeSlider.this, e);
- }
+ // if( null != sliderListener ) {
+ // sliderListener.clicked(RangeSlider.this, e);
+ // }
}
@Override
public void mousePressed(final MouseEvent e) {
@@ -156,11 +259,75 @@ public final class RangeSlider extends Widget {
sliderListener.released(RangeSlider.this, e);
}
}
+ });
+ final KeyListener keyListener = new KeyAdapter() {
@Override
- public void mouseWheelMoved(final MouseEvent e) {
- // Support ?
+ public void keyReleased(final KeyEvent e) {
+ final float old_val = val;
+ final float old_val_pct = val_pct;
+ float v = old_val;
+ final short keySym = e.getKeySymbol();
+ boolean action = false;
+ if( horizontal ) {
+ if( keySym == KeyEvent.VK_RIGHT ) {
+ action = true;
+ if( inverted ) {
+ v--;
+ } else {
+ v++;
+ }
+ } else if( keySym == KeyEvent.VK_LEFT ) {
+ action = true;
+ if( inverted ) {
+ v++;
+ } else {
+ v--;
+ }
+ }
+ } else {
+ if( keySym == KeyEvent.VK_DOWN ) {
+ action = true;
+ if( inverted ) {
+ v++;
+ } else {
+ v--;
+ }
+ } else if( keySym == KeyEvent.VK_UP ) {
+ action = true;
+ if( inverted ) {
+ v--;
+ } else {
+ v++;
+ }
+ }
+ }
+ if( !action && !Float.isNaN(pageSize) ) {
+ if( keySym == KeyEvent.VK_PAGE_DOWN ) {
+ action = true;
+ if( inverted ) {
+ v+=pageSize;
+ } else {
+ v-=pageSize;
+ }
+ } else if( keySym == KeyEvent.VK_PAGE_UP ) {
+ action = true;
+ if( inverted ) {
+ v-=pageSize;
+ } else {
+ v+=pageSize;
+ }
+ }
+ }
+ if( action ) {
+ setValue( v );
+ if( null != sliderListener ) {
+ sliderListener.dragged(RangeSlider.this, old_val, val, old_val_pct, val_pct);
+ }
+ }
}
- });
+ };
+ barAndKnob.addKeyListener(keyListener);
+ knob.addKeyListener(keyListener);
}
@Override
@@ -180,44 +347,64 @@ public final class RangeSlider extends Widget {
}
public Rectangle getBar() { return bar; }
- public BaseButton getKnob() { return knob; }
+ public Shape getKnob() { return knob; }
- public final float getWidth() { return width; }
- public final float getHeight() { return height; }
- public final float getKnobSize() { return knobSz; }
+ public final Vec2f getSize() { return size; }
+ /** Height of knob orthogonal to sliding direction */
+ public final float getKnobHeight() { return knobDiameter; }
+ /** Length of knob in sliding direction */
+ public final float getKnobLength() { return knobHalfLen*2f; }
- public float getMin() { return min; }
- public float getMax() { return max; }
- public float getRange() { return max - min; }
+ public Vec2f getMinMax() { return minMax; }
+ public float getRange() { return minMax.y() - minMax.x(); }
+ private float getRange(final Vec2f minMax) { return minMax.y() - minMax.x(); }
public float getValue() { return val; }
public float getValuePct() { return val_pct; }
+ public RangeSlider setPageSize(final float v) {
+ if( Float.isNaN(this.pageSize) || Float.isNaN(v) ) {
+ return this;
+ }
+ this.pageSize = v;
+ final float pageSizePct = Math.max(pageKnobSizePctMin, pageSize / getRange());
+ final float knobWidth, knobHeight;
+ if( horizontal ) {
+ knobHeight = size.y() * pageKnobScale;
+ knobWidth = pageSizePct * this.size.x();
+ knobHalfLen = knobWidth * 0.5f;
+ knobDiameter = knobHeight;
+ } else {
+ knobWidth = size.x() * pageKnobScale;
+ knobHeight = pageSizePct * this.size.y();
+ knobHalfLen = knobHeight * 0.5f;
+ knobDiameter = knobWidth;
+ }
+ ((Rectangle)knob).setDimension(knobWidth, knobHeight, 0);
+ return this;
+ }
+ public float getPageSize() { return this.pageSize; }
+
+ public RangeSlider setInverted(final boolean v) { inverted = v; return setValue(val); }
+
/**
* Sets slider value range and current value
- * @param min minimum value of slider
- * @param max maximum value of slider
+ * @param minMax minimum- and maximum-value of slider
* @param value current value of slider
* @return this instance of chaining
*/
- public RangeSlider setMinMax(final float min, final float max, final float value) {
- this.min = min;
- this.max = max;
- this.val = Math.max(min, Math.min(max, value));
- this.val_pct = ( value - min ) / getRange();
- setKnob();
- return this;
+ public RangeSlider setMinMax(final Vec2f minMax, final float value) {
+ this.minMax.set(minMax);
+ return setValue( value );
}
public RangeSlider setValuePct(final float v) {
- val_pct = v;
- val = min + ( val_pct * getRange() );
- setKnob();
- return this;
+ final float pct = Math.max(0.0f, Math.min(1.0f, v));
+ return setValue( minMax.x() + ( pct * getRange() ) );
}
public RangeSlider setValue(final float v) {
- val = v;
- val_pct = ( val - min ) / getRange();
+ val = Math.max(minMax.x(), Math.min(minMax.y(), v));
+ val_pct = ( val - minMax.x() ) / getRange();
setKnob();
return this;
}
@@ -226,27 +413,118 @@ public final class RangeSlider extends Widget {
* Knob position reflects value on its center and ranges from zero to max.
*/
private Vec2f getKnobPos(final Vec2f posRes, final float val_pct) {
+ final float v = inverted ? 1f - val_pct : val_pct;
if( horizontal ) {
- posRes.setX( val_pct*width - knobSz*0.5f );
- posRes.setY( -( knobSz - height ) * 0.5f );
+ posRes.setX( Math.max(0, Math.min(size.x(), v*size.x() - knobHalfLen)) );
+ posRes.setY( -( knobDiameter - size.y() ) * 0.5f );
} else {
- posRes.setX( -( knobSz - width ) * 0.5f );
- posRes.setY( val_pct*height - knobSz*0.5f );
+ posRes.setX( -( knobDiameter - size.x() ) * 0.5f );
+ posRes.setY( Math.max(0, Math.min(size.y() - 2*knobHalfLen, v*size.y() - knobHalfLen)) );
}
return posRes;
}
private float getKnobValuePct(final float pos_x, final float pos_y, final float adjustment) {
final float v;
if( horizontal ) {
- v = ( pos_x + adjustment ) / width;
+ v = ( pos_x + adjustment ) / size.x();
} else {
- v = ( pos_y + adjustment ) / height;
+ v = ( pos_y + adjustment ) / size.y();
}
- return Math.max(0.0f, Math.min(1.0f, v));
+ return Math.max(0.0f, Math.min(1.0f, inverted ? 1f - v : v));
}
private void setKnob() {
final Vec2f pos = getKnobPos(new Vec2f(), val_pct);
knob.moveTo(pos.x(), pos.y(), Button.DEFAULT_LABEL_ZOFFSET);
}
+
+ /**
+ * Sets the slider knob color.
+ * <p>
+ * If this slider comprises a rectangular page-sized knob,
+ * its rectangular frame also shares the same color.
+ * </p>
+ * <p>
+ * Base color w/o color channel, will be modulated w/ pressed- and toggle color
+ * </p>
+ * <p>
+ * Default RGBA value is 0.30f, 0.30f, 0.30f, 1.0f
+ * </p>
+ */
+ @Override
+ public final Shape setColor(final float r, final float g, final float b, final float a) {
+ super.setColor(r, g, b, a);
+ knob.setColor(r, g, b, a);
+ if( !Float.isNaN(pageSize) ) {
+ bar.setColor(r, g, b, a);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the slider knob color.
+ * <p>
+ * If this slider comprises a rectangular page-sized knob,
+ * its rectangular frame also shares the same color.
+ * </p>
+ * <p>
+ * Base color w/o color channel, will be modulated w/ pressed- and toggle color
+ * </p>
+ * <p>
+ * Default RGBA value is 0.30f, 0.30f, 0.30f, 1.0f
+ * </p>
+ */
+ @Override
+ public Shape setColor(final Vec4f c) {
+ this.rgbaColor.set(c);
+ knob.setColor(c);
+ if( !Float.isNaN(pageSize) ) {
+ bar.setColor(c);
+ }
+ return this;
+ }
+
+ /**
+ * Sets the slider background bar color, if this slider comprises only a positional round knob.
+ * <p>
+ * Default RGBA value is 0.60f, 0.60f, 0.60f, 0.5f
+ * </p>
+ */
+ public Shape setBackgroundBarColor(final float r, final float g, final float b, final float a) {
+ if( Float.isNaN(pageSize) ) {
+ bar.setColor(r, g, b, a);
+ }
+ return this;
+ }
+ /**
+ * Sets the slider background bar color, if this slider comprises only a positional round knob.
+ * <p>
+ * Default RGBA value is 0.60f, 0.60f, 0.60f, 0.5f
+ * </p>
+ */
+ public Shape setBackgroundBarColor(final Vec4f c) {
+ if( Float.isNaN(pageSize) ) {
+ bar.setColor(c);
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Sets the slider bar and knob pressed color modulation.
+ * </p>
+ */
+ @Override
+ public final Shape setPressedColorMod(final float r, final float g, final float b, final float a) {
+ super.setPressedColorMod(r, g, b, a);
+ bar.setPressedColorMod(r, g, b, a);
+ knob.setPressedColorMod(r, g, b, a);
+ return this;
+ }
+
+ @Override
+ public String getSubString() {
+ return super.getSubString()+", range["+minMax+"] @ "+val+", "+(100f*val_pct)+"%";
+ }
}