diff options
-rw-r--r-- | make/scripts/tests.sh | 3 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java | 28 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBox01.java (renamed from src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo12.java) | 161 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutGrid01.java | 503 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java | 2 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03b.java | 48 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo11.java | 5 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java | 48 | ||||
-rw-r--r-- | src/graphui/classes/com/jogamp/graph/ui/layout/Alignment.java | 2 | ||||
-rw-r--r-- | src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java | 67 | ||||
-rw-r--r-- | src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java | 356 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/graph/FontViewListener01.java | 5 |
12 files changed, 1072 insertions, 156 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index f30de91fd..847704e46 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -1032,8 +1032,9 @@ function testawtswt() { #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo03b $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo10 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo11 $* -testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo12 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UISceneDemo20 $* +testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutGrid01 $* +#testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutBox01 $* #testnoawt com.jogamp.opengl.demos.graph.ui.FontView01 $* #testnoawt com.jogamp.opengl.test.junit.graph.TestTextRendererNEWT21 $* diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java index 8803fbf14..a8d82fcc4 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/FontView01.java @@ -40,8 +40,9 @@ import com.jogamp.graph.font.FontScale; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.layout.Alignment; +import com.jogamp.graph.ui.layout.Gap; import com.jogamp.graph.ui.layout.GridLayout; -import com.jogamp.graph.ui.layout.Padding; import com.jogamp.graph.ui.shapes.GlyphShape; import com.jogamp.graph.ui.shapes.Label; import com.jogamp.graph.ui.shapes.Rectangle; @@ -62,11 +63,11 @@ import com.jogamp.opengl.util.Animator; * This may become a little font viewer application, having FontForge as its role model. */ public class FontView01 { - private static float gridWidth = 2/3f; + private static float GlyphGridWidth = 2/3f; static GraphUIDemoArgs options = new GraphUIDemoArgs(1280, 720, Region.VBAA_RENDERING_BIT); public static void main(final String[] args) throws IOException { - float mmPerCell = 10f; + float mmPerCell = 8f; String fontfilename = null; int gridCols = -1; int gridRows = -1; @@ -153,15 +154,16 @@ public class FontView01 { System.err.println("mmPerCell "+mmPerCell); } if( 0 >= gridCols ) { - gridCols = (int)( ( window.getSurfaceWidth() * gridWidth / ppmm[0] ) / mmPerCell ); + gridCols = (int)( ( window.getSurfaceWidth() * GlyphGridWidth / ppmm[0] ) / mmPerCell ); } if( 0 >= gridRows ) { gridRows = (int)( ( window.getSurfaceHeight() / ppmm[1] ) / mmPerCell ); } final int cellCount = gridCols * gridRows; + final float gridSize = gridCols > gridRows ? 1f/gridCols : 1f/gridRows; System.err.println("Grid "+gridCols+" x "+gridRows+", "+cellCount+" cells, gridSize "+gridSize); - final Group mainGrid = new Group(new GridLayout(gridCols, gridSize, gridSize, new Padding(gridSize*0.05f, gridSize*0.05f))); + final Group mainGrid = new Group(new GridLayout(gridCols, gridSize, gridSize, Alignment.Fill, new Gap(gridSize*0.10f))); final Group glyphCont = new Group(); { @@ -175,7 +177,7 @@ public class FontView01 { glyphInfo.setColor(0.1f, 0.1f, 0.1f, 1.0f); infoCont.addShape(glyphInfo); } - final Group infoGrid = new Group(new GridLayout(1/2f, 1/2f, new Padding(1/2f*0.005f, 1/2f*0.005f), 2)); + final Group infoGrid = new Group(new GridLayout(1/2f, 1/2f, Alignment.Fill, new Gap(1/2f*0.01f), 2)); infoGrid.addShape(glyphCont); infoGrid.addShape(infoCont); @@ -243,19 +245,19 @@ public class FontView01 { final AABBox sceneBox = scene.getBounds(); System.err.println("SceneBox "+sceneBox); final AABBox mainGridBox = mainGrid.getBounds(); - final float sgxy; - if( mainGridBox.getWidth() > mainGridBox.getHeight() ) { - sgxy = sceneBox.getWidth() * gridWidth / mainGridBox.getWidth(); - } else { - sgxy = sceneBox.getHeight() / mainGridBox.getHeight(); + final float sxy; + { + final float sx = sceneBox.getWidth() * GlyphGridWidth / mainGridBox.getWidth(); + final float sy = sceneBox.getHeight() / mainGridBox.getHeight(); + sxy = sx < sy ? sx : sy; } - mainGrid.scale(sgxy, sgxy, 1f); + mainGrid.scale(sxy, sxy, 1f); mainGrid.moveTo(sceneBox.getMinX(), sceneBox.getMinY(), 0f); scene.addShape(mainGrid); // late add at correct position and size System.err.println("Grid "+mainGrid); System.err.println("Grid "+mainGrid.getLayout()); System.err.println("Grid[0] "+mainGrid.getShapes().get(0)); - final float rightWidth = sceneBox.getWidth() * ( 1f - gridWidth ); + final float rightWidth = sceneBox.getWidth() * ( 1f - GlyphGridWidth ); { final float icScale = sceneBox.getHeight(); infoGrid.validate(reqGLP); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo12.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBox01.java index 4a0fa9a90..754614ed4 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo12.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBox01.java @@ -36,14 +36,15 @@ import com.jogamp.graph.font.FontSet; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.Scene.PMVMatrixSetup; import com.jogamp.graph.ui.layout.BoxLayout; -import com.jogamp.graph.ui.layout.GridLayout; import com.jogamp.graph.ui.layout.Margin; import com.jogamp.graph.ui.layout.Padding; import com.jogamp.graph.ui.shapes.Button; import com.jogamp.graph.ui.shapes.Label; import com.jogamp.graph.ui.shapes.Rectangle; import com.jogamp.graph.ui.shapes.BaseButton; +import com.jogamp.newt.event.MouseEvent; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; @@ -51,19 +52,58 @@ import com.jogamp.opengl.GL; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.demos.graph.ui.util.GraphUIDemoArgs; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Recti; +import com.jogamp.opengl.math.Vec3f; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.PMVMatrix; /** - * Res independent {@link Shape}s in a {@link Group} using a {@link GridLayout}, contained within a Scene attached to GLWindow. + * Res independent {@link Shape}s in a {@link Group} using a {@link BoxLayout}, contained within a Scene attached to GLWindow. * <p> * Pass '-keep' to main-function to keep running after animation, * then user can test Shape drag-move and drag-resize w/ 1-pointer. * </p> */ -public class UISceneDemo12 { +public class UILayoutBox01 { static GraphUIDemoArgs options = new GraphUIDemoArgs(1280, 720, Region.VBAA_RENDERING_BIT); + /** + * Our PMVMatrixSetup: + * - gluPerspective like Scene's default + * - no normal scale to 1, keep a longer distance to near plane for rotation effects. We scale Shapes + */ + public static class MyPMVMatrixSetup implements PMVMatrixSetup { + static float Z_DIST = -1f; + @Override + public void set(final PMVMatrix pmv, final Recti viewport) { + final float ratio = (float)viewport.width()/(float)viewport.height(); + pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmv.glLoadIdentity(); + pmv.gluPerspective(Scene.DEFAULT_ANGLE, ratio, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR); + pmv.glTranslatef(0f, 0f, Z_DIST); // Scene.DEFAULT_SCENE_DIST); + + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + } + + @Override + public void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, final Recti viewport) { + final float orthoDist = -Z_DIST; // Scene.DEFAULT_SCENE_DIST; + final Vec3f obj00Coord = new Vec3f(); + final Vec3f obj11Coord = new Vec3f(); + + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.x(), viewport.y(), orthoDist, obj00Coord); + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.width(), viewport.height(), orthoDist, obj11Coord); + + planeBox.setSize( obj00Coord, obj11Coord ); + } + }; + + static final boolean reLayout = false; + public static void main(final String[] args) throws IOException { if( 0 != args.length ) { final int[] idx = { 0 }; @@ -90,11 +130,11 @@ public class UISceneDemo12 { final GLWindow window = GLWindow.create(caps); window.setSize(options.surface_width, options.surface_height); - window.setTitle(UISceneDemo12.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.setTitle(UILayoutBox01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); window.addWindowListener(new WindowAdapter() { @Override public void windowResized(final WindowEvent e) { - window.setTitle(UISceneDemo12.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.setTitle(UILayoutBox01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); } @Override public void windowDestroyNotify(final WindowEvent e) { @@ -104,6 +144,7 @@ public class UISceneDemo12 { final Scene scene = new Scene(); + scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); scene.setClearParams(new float[] { 1f, 1f, 1f, 1f}, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); scene.setFrustumCullingEnabled(true); scene.attachInputListenerTo(window); @@ -114,6 +155,23 @@ public class UISceneDemo12 { animator.setUpdateFPSFrames(1*60, null); // System.err); animator.add(window); animator.start(); + + /** + * We can share this instance w/ all UI elements, + * since only mouse action / gesture is complete for a single one (press, drag, released and click). + */ + final Shape.MouseGestureAdapter dragZoomRotateListener = new Shape.MouseGestureAdapter() { + @Override + public void mouseWheelMoved(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final Shape shape = shapeEvent.shape; + final Vec3f rot = new Vec3f(e.getRotation()).scale( FloatUtil.PI / 180.0f ); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot.x(); rot.setX( rot.y() ); rot.setY( tmp ); + shape.getRotation().rotateByEuler( rot.scale( 2f ) ); + } + }; + // // Resolution independent, no screen size // @@ -123,16 +181,17 @@ public class UISceneDemo12 { final AABBox sceneBox = scene.getBounds(); System.err.println("SceneBox "+sceneBox); - final float sxy = 1/8f; + final float sxy = 1/8f * sceneBox.getWidth(); float nextPos = 0; final Group groupA0 = new Group(new BoxLayout( new Padding(0.15f, 0.15f) ) ); { groupA0.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); - groupA0.addShape( new Button(options.renderModes, font, "stack1", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupA0.addShape( new Label(options.renderModes, font, 0.70f/4f, "pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); + groupA0.addShape( new Button(options.renderModes, font, "stack-0", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); + groupA0.addShape( new Label(options.renderModes, font, 0.70f/4f, "A0 pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); } groupA0.setInteractive(true); + groupA0.addMouseListener(dragZoomRotateListener); groupA0.scale(sxy, sxy, 1); groupA0.moveTo(sceneBox.getLow()).move(nextPos, 0, 0); groupA0.validate(reqGLP); @@ -145,11 +204,13 @@ public class UISceneDemo12 { final Group groupA1 = new Group(new BoxLayout( 1f, 1f, new Margin(0.05f, 0.05f), new Padding(0.10f, 0.10f) ) ); { - groupA1.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); - groupA1.addShape( new Button(options.renderModes, font, "stack2", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupA1.addShape( new Label(options.renderModes, font, 0.70f/4f, "pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); + // groupA1.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); + groupA1.addShape( new BaseButton(options.renderModes | Region.COLORCHANNEL_RENDERING_BIT, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) + .setBorder(0.01f).setPaddding(new Padding(0.0f)) ); + groupA1.addShape( new Button(options.renderModes, font, "stack-1", 0.50f, 0.50f/2f).setCorner(0f).addMouseListener(dragZoomRotateListener) ); + groupA1.addShape( new Label(options.renderModes, font, 0.70f/4f, "A1 pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); } - groupA1.setInteractive(true); + // groupA1.setInteractive(true); groupA1.scale(sxy, sxy, 1); groupA1.moveTo(sceneBox.getLow()).move(nextPos, 0, 0); groupA1.validate(reqGLP); @@ -157,14 +218,20 @@ public class UISceneDemo12 { System.err.println("Group-A1 Layout "+groupA1.getLayout()); groupA1.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); scene.addShape(groupA1); - scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); + // scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); + scene.addShape( new Button(options.renderModes, font, "stack-1b", 0.50f, 0.50f/2f).setCorner(0f) + .scale(sxy, sxy, 1f).moveTo(sceneBox.getLow()).move(nextPos, groupA1.getScaledHeight(), 0) + .addMouseListener(dragZoomRotateListener) ); + nextPos += groupA1.getScaledWidth() * 1.5f; final Group groupA2 = new Group(new BoxLayout( 1f, 1f, new Margin(0.10f, Margin.CENTER), new Padding(0.05f, 0) ) ); { - groupA2.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); - groupA2.addShape( new Button(options.renderModes, font, "stack3", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupA2.addShape( new Label(options.renderModes, font, 0.70f/4f, "pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); + // groupA2.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); + groupA2.addShape( new BaseButton(options.renderModes | Region.COLORCHANNEL_RENDERING_BIT, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) + .setBorder(0.01f).setPaddding(new Padding(0.0f)).setBorderColor(1, 0, 0, 1) ); + groupA2.addShape( new Button(options.renderModes, font, "stack-2", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); + groupA2.addShape( new Label(options.renderModes, font, 0.70f/4f, "A2 pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); } groupA2.setInteractive(true); groupA2.scale(sxy, sxy, 1); @@ -174,48 +241,58 @@ public class UISceneDemo12 { System.err.println("Group-A2 Layout "+groupA2.getLayout()); groupA2.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); scene.addShape(groupA2); - scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); + // scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); nextPos += groupA2.getScaledWidth() * 1.5f; - final Group groupA3 = new Group(new BoxLayout( 1f, 1f, new Margin(Margin.CENTER) ) ); + final Group groupA3 = new Group(new BoxLayout( 1f, 1f, new Margin(0.10f, Margin.CENTER), new Padding(0.05f, 0f) ) ); { - groupA3.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); - groupA3.addShape( new Button(options.renderModes, font, "stack4", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupA3.addShape( new Label(options.renderModes, font, 0.70f/4f, "pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); + // groupA3.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); + groupA3.addShape( new BaseButton(options.renderModes | Region.COLORCHANNEL_RENDERING_BIT, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) + .setBorder(0.01f).setPaddding(new Padding(0.0f)).setBorderColor(0, 0, 1, 1) ); + groupA3.addShape( new Button(options.renderModes, font, "stack-3", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); + groupA3.addShape( new Label(options.renderModes, font, 0.70f/4f, "A3 pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); } - groupA3.setInteractive(true); groupA3.scale(sxy, sxy, 1); groupA3.moveTo(sceneBox.getLow()).move(nextPos, 0, 0); groupA3.validate(reqGLP); - System.err.println("Group-A1 "+groupA3); - System.err.println("Group-A1 Layout "+groupA3.getLayout()); + System.err.println("Group-A3 "+groupA3); + System.err.println("Group-A3 Layout "+groupA3.getLayout()); groupA3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); scene.addShape(groupA3); - scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); + // scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); nextPos += groupA3.getScaledWidth() * 1.5f; + final Group groupA4 = new Group(new BoxLayout( 1f, 1f, new Margin(Margin.CENTER), new Padding(0.0f, 0f) ) ); + { + // groupA4.addShape( new BaseButton(options.renderModes, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) ); + groupA4.addShape( new BaseButton(options.renderModes | Region.COLORCHANNEL_RENDERING_BIT, 0.70f, 0.70f).setCorner(0f).setInteractive(false).setColor(0, 1, 0, 1) + .setBorder(0.01f).setPaddding(new Padding(0.0f)).setBorderColor(0f, 0f, 0f, 1) ); + groupA4.addShape( new Button(options.renderModes, font, "stack-4", 0.50f, 0.50f/2f).setCorner(0f).setDragAndResizeable(false) ); + groupA4.addShape( new Label(options.renderModes, font, 0.70f/4f, "A4 pajq").setDragAndResizeable(false).setColor(0, 0, 1, 1) ); + } + groupA4.scale(sxy, sxy, 1); + groupA4.moveTo(sceneBox.getLow()).move(nextPos, 0, 0); + groupA4.validate(reqGLP); + System.err.println("Group-A4 "+groupA4); + System.err.println("Group-A4 Layout "+groupA4.getLayout()); + groupA4.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA4); + // scene.addShape( new Rectangle(options.renderModes, 1f, 1f, 0.01f).scale(sxy, sxy, 1).moveTo(sceneBox.getLow()).move(nextPos, 0, 0).setInteractive(false).setColor(0, 0, 0, 1) ); + nextPos += groupA4.getScaledWidth() * 1.5f; + + if( reLayout ) { + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + groupA4.markShapeDirty(); + groupA4.validate(reqGLP); + System.err.println("Group-A4.2 "+groupA4); + System.err.println("Group-A4 Layout.2 "+groupA4.getLayout()); + } + // // // nextPos = 0; - final Group groupB0 = new Group(new GridLayout(2, 1f, 1/2f, new Padding(0.05f, 0.05f))); - { - groupB0.addShape( new Button(options.renderModes, font, "r1 c1", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupB0.addShape( new Button(options.renderModes, font, "r1 c2", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupB0.addShape( new Button(options.renderModes, font, "r2 c1", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); - groupB0.addShape( new Button(options.renderModes, font, "r2 c2", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); - } - groupB0.setInteractive(true); - groupB0.scale(sxy, sxy, 1); - groupB0.moveTo(sceneBox.getLow()).move(nextPos, sceneBox.getHeight()/2f, 0); - groupB0.validate(reqGLP); - System.err.println("Group-B0 "+groupB0); - System.err.println("Group-B0 Layout "+groupB0.getLayout()); - groupB0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); - scene.addShape(groupB0); - nextPos = groupB0.getScaledWidth() * 1.5f; - try { Thread.sleep(1000); } catch (final InterruptedException e1) { } if( !options.stayOpen ) { window.destroy(); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutGrid01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutGrid01.java new file mode 100644 index 000000000..a62a5a65a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutGrid01.java @@ -0,0 +1,503 @@ +/** + * Copyright 2010-2023 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package com.jogamp.opengl.demos.graph.ui; + +import java.io.IOException; + +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.font.Font; +import com.jogamp.graph.font.FontFactory; +import com.jogamp.graph.font.FontSet; +import com.jogamp.graph.ui.Group; +import com.jogamp.graph.ui.Scene; +import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.Scene.PMVMatrixSetup; +import com.jogamp.graph.ui.layout.Alignment; +import com.jogamp.graph.ui.layout.Gap; +import com.jogamp.graph.ui.layout.GridLayout; +import com.jogamp.graph.ui.layout.Padding; +import com.jogamp.graph.ui.shapes.Button; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.WindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.GL; +import com.jogamp.opengl.GLCapabilities; +import com.jogamp.opengl.GLProfile; +import com.jogamp.opengl.demos.graph.ui.util.GraphUIDemoArgs; +import com.jogamp.opengl.fixedfunc.GLMatrixFunc; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Recti; +import com.jogamp.opengl.math.Vec3f; +import com.jogamp.opengl.math.Vec4f; +import com.jogamp.opengl.math.geom.AABBox; +import com.jogamp.opengl.util.Animator; +import com.jogamp.opengl.util.PMVMatrix; + +/** + * Res independent {@link Shape}s in a {@link Group} using a {@link GridLayout}, contained within a Scene attached to GLWindow. + * <p> + * Pass '-keep' to main-function to keep running after animation, + * then user can test Shape drag-move and drag-resize w/ 1-pointer. + * </p> + */ +public class UILayoutGrid01 { + static GraphUIDemoArgs options = new GraphUIDemoArgs(1280, 720, Region.VBAA_RENDERING_BIT); + + /** + * Our PMVMatrixSetup: + * - gluPerspective like Scene's default + * - no normal scale to 1, keep a longer distance to near plane for rotation effects. We scale Shapes + */ + public static class MyPMVMatrixSetup implements PMVMatrixSetup { + static float Z_DIST = -1f; + @Override + public void set(final PMVMatrix pmv, final Recti viewport) { + final float ratio = (float)viewport.width()/(float)viewport.height(); + pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmv.glLoadIdentity(); + pmv.gluPerspective(Scene.DEFAULT_ANGLE, ratio, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR); + pmv.glTranslatef(0f, 0f, Z_DIST); // Scene.DEFAULT_SCENE_DIST); + + pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmv.glLoadIdentity(); + } + + @Override + public void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, final Recti viewport) { + final float orthoDist = -Z_DIST; // Scene.DEFAULT_SCENE_DIST; + final Vec3f obj00Coord = new Vec3f(); + final Vec3f obj11Coord = new Vec3f(); + + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.x(), viewport.y(), orthoDist, obj00Coord); + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.width(), viewport.height(), orthoDist, obj11Coord); + + planeBox.setSize( obj00Coord, obj11Coord ); + } + }; + + static final boolean reLayout = false; + static final int reLayoutSleep = 500; + + public static void main(final String[] args) throws IOException { + if( 0 != args.length ) { + final int[] idx = { 0 }; + for (idx[0] = 0; idx[0] < args.length; ++idx[0]) { + if( options.parse(args, idx) ) { + continue; + } + } + } + options.renderModes |= Region.COLORCHANNEL_RENDERING_BIT; + System.err.println(options); + + final GLProfile reqGLP = GLProfile.get(options.glProfileName); + System.err.println("GLProfile: "+reqGLP); + + final Animator animator = new Animator(); + + final GLCapabilities caps = new GLCapabilities(reqGLP); + caps.setAlphaBits(4); + if( options.sceneMSAASamples > 0 ) { + caps.setSampleBuffers(true); + caps.setNumSamples(options.sceneMSAASamples); + } + System.out.println("Requested: " + caps); + + final GLWindow window = GLWindow.create(caps); + window.setSize(options.surface_width, options.surface_height); + window.setTitle(UILayoutGrid01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowResized(final WindowEvent e) { + window.setTitle(UILayoutGrid01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + } + @Override + public void windowDestroyNotify(final WindowEvent e) { + animator.stop(); + } + }); + + + final Scene scene = new Scene(); + scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); + scene.setClearParams(new float[] { 1f, 1f, 1f, 1f}, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + scene.setFrustumCullingEnabled(true); + scene.attachInputListenerTo(window); + window.addGLEventListener(scene); + window.setVisible(true); + scene.waitUntilDisplayed(); + + animator.setUpdateFPSFrames(1*60, null); // System.err); + animator.add(window); + animator.start(); + + /** + * We can share this instance w/ all UI elements, + * since only mouse action / gesture is complete for a single one (press, drag, released and click). + */ + final Shape.MouseGestureAdapter dragZoomRotateListener = new Shape.MouseGestureAdapter() { + @Override + public void mouseWheelMoved(final MouseEvent e) { + final Shape.EventInfo shapeEvent = (Shape.EventInfo) e.getAttachment(); + final Shape shape = shapeEvent.shape; + final Vec3f rot = new Vec3f(e.getRotation()).scale( FloatUtil.PI / 180.0f ); + // swap axis for onscreen rotation matching natural feel + final float tmp = rot.x(); rot.setX( rot.y() ); rot.setY( tmp ); + shape.getRotation().rotateByEuler( rot.scale( 2f ) ); + } + }; + + // + // Resolution independent, no screen size + // + final Font font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF); + System.err.println("Font: "+font.getFullFamilyName()); + + final AABBox sceneBox = scene.getBounds(); + System.err.println("SceneBox "+sceneBox); + + final Vec4f borderColor = new Vec4f(0, 0, 1f, 0.6f); + final float borderThickness = 0.01f; + final float sxy = 1/10f * sceneBox.getWidth(); + float nextXPos = 0, nextYTop = sceneBox.getHeight(); + + final Group groupA0 = new Group(new GridLayout(1, 1f, 1/2f, Alignment.Fill, new Gap(0.10f))); + groupA0.addShape( new Button(options.renderModes, font, "ro co", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupA0.setBorder(borderThickness).setBorderColor(borderColor); + groupA0.scale(sxy, sxy, 1); + groupA0.setInteractive(true); + groupA0.validate(reqGLP); + groupA0.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupA0.getScaledHeight(), 0); + System.err.println("Group-A0 "+groupA0); + System.err.println("Group-A0 Layout "+groupA0.getLayout()); + groupA0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA0); + nextXPos += groupA0.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupA0.markShapeDirty(); + groupA0.validate(reqGLP); + System.err.println("Group-A0.2 "+groupA0); + System.err.println("Group-A0 Layout.2 "+groupA0.getLayout()); + groupA0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupA1 = new Group(new GridLayout(1, 1, 1/2f, Alignment.Fill, new Gap(0.10f))); + groupA1.addShape( new Button(options.renderModes, font, "ro co", 1f, 1/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA1.addShape( new Button(options.renderModes, font, "r1 r1", 1f, 1/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA1.setBorder(sxy*borderThickness).setBorderColor(borderColor); + groupA1.scale(sxy, sxy, 1); + groupA1.setInteractive(true); + groupA1.validate(reqGLP); + groupA1.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupA1.getScaledHeight(), 0); + System.err.println("Group-A1 "+groupA1); + System.err.println("Group-A1 Layout "+groupA1.getLayout()); + groupA1.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA1); + nextXPos += groupA1.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupA1.markShapeDirty(); + groupA1.validate(reqGLP); + System.err.println("Group-A1.2 "+groupA1); + System.err.println("Group-A1 Layout.2 "+groupA1.getLayout()); + groupA1.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupA2 = new Group(new GridLayout(1, 1/2f, Alignment.Fill, new Gap(0.10f), 1)); + groupA2.addShape( new Button(options.renderModes, font, "ro co", 1f, 1/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA2.addShape( new Button(options.renderModes, font, "r1 c1", 1f, 1/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA2.setBorder(sxy*borderThickness).setBorderColor(borderColor); + groupA2.scale(sxy, sxy, 1); + groupA2.setInteractive(true); + groupA2.validate(reqGLP); + groupA2.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupA2.getScaledHeight(), 0); + System.err.println("Group-A2 "+groupA2); + System.err.println("Group-A2 Layout "+groupA2.getLayout()); + groupA2.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA2); + nextXPos += groupA2.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupA2.markShapeDirty(); + groupA2.validate(reqGLP); + System.err.println("Group-A2.2 "+groupA2); + System.err.println("Group-A2 Layout.2 "+groupA2.getLayout()); + groupA2.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupA3 = new Group(new GridLayout(2, 1f, 1/2f, Alignment.Fill, new Gap(0.10f))); + { + groupA3.addShape( new Button(options.renderModes, font, "ro co", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupA3.addShape( new Button(options.renderModes, font, "r1 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA3.addShape( new Button(options.renderModes, font, "r2 c1", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA3.addShape( new Button(options.renderModes, font, "r2 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + } + groupA3.setBorder(borderThickness).setBorderColor(borderColor); + groupA3.scale(sxy, sxy, 1); + groupA3.setInteractive(true); + groupA3.validate(reqGLP); + groupA3.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupA3.getScaledHeight(), 0); + System.err.println("Group-A3 "+groupA3); + System.err.println("Group-A3 Layout "+groupA3.getLayout()); + groupA3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA3); + nextXPos += groupA3.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupA3.markShapeDirty(); + groupA3.validate(reqGLP); + System.err.println("Group-A3.2 "+groupA3); + System.err.println("Group-A3 Layout.2 "+groupA3.getLayout()); + groupA3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupA4 = new Group(new GridLayout(2, 1f, 1/2f, Alignment.Fill, new Gap(0.10f))); + { + groupA4.addShape( new Button(options.renderModes, font, "ro co", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupA4.addShape( new Button(options.renderModes, font, "r1 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA4.addShape( new Button(options.renderModes, font, "r2 c1", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupA4.addShape( new Button(options.renderModes, font, "r2 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupA4.addShape( new Button(options.renderModes, font, "r3 c1", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + } + groupA4.setBorder(borderThickness).setBorderColor(borderColor); + groupA4.scale(sxy, sxy, 1); + groupA4.setInteractive(true); + groupA4.validate(reqGLP); + groupA4.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupA4.getScaledHeight(), 0); + System.err.println("Group-A4 "+groupA4); + System.err.println("Group-A4 Layout "+groupA4.getLayout()); + groupA4.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupA4); + nextXPos += groupA4.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupA4.markShapeDirty(); + groupA4.validate(reqGLP); + System.err.println("Group-A4.2 "+groupA4); + System.err.println("Group-A4 Layout.2 "+groupA4.getLayout()); + groupA4.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + // next line + nextXPos = 0; + nextYTop = 2f*sceneBox.getHeight()/3f; + + final Group groupB0 = new Group(new GridLayout(2, sxy, sxy/2f, Alignment.Fill, new Gap(sxy*0.10f))); + { + groupB0.addShape( new Button(options.renderModes, font, "ro co", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB0.addShape( new Button(options.renderModes, font, "r1 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupB0.addShape( new Button(options.renderModes, font, "r2 c1", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupB0.addShape( new Button(options.renderModes, font, "r2 c2", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB0.addShape( new Button(options.renderModes, font, "r3 c1", 1f, 1f/2f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + } + groupB0.setBorder(sxy*borderThickness).setBorderColor(borderColor); + // groupB0.scale(2*sxy, 2*sxy, 1); + groupB0.setInteractive(true); + groupB0.validate(reqGLP); + groupB0.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupB0.getScaledHeight(), 0); + System.err.println("Group-B0 "+groupB0); + System.err.println("Group-B0 Layout "+groupB0.getLayout()); + groupB0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupB0); + nextXPos += groupB0.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupB0.markShapeDirty(); + groupB0.validate(reqGLP); + System.err.println("Group-B0.2 "+groupB0); + System.err.println("Group-B0 Layout.2 "+groupB0.getLayout()); + groupB0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupB1 = new Group(new GridLayout(2, sxy, sxy/2f, Alignment.FillCenter, new Gap(sxy*0.10f))); + { + final Padding p = new Padding(0.05f); + groupB1.addShape( new Button(options.renderModes, font, "ro co", 1, 1/2f).setCorner(0f).setPaddding(p).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB1.addShape( new Button(options.renderModes, font, "r1 c2", 1, 1/2f).setCorner(0f).setPaddding(p).setBorder(borderThickness).setDragAndResizeable(false) ); + groupB1.addShape( new Button(options.renderModes, font, "r2 c1", 1, 1/2f).setCorner(0f).setPaddding(p).setBorder(borderThickness).setDragAndResizeable(false) ); + groupB1.addShape( new Button(options.renderModes, font, "r2 c2", 1, 1/2f).setCorner(0f).setPaddding(p).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB1.addShape( new Button(options.renderModes, font, "r3 c1", 1, 1/2f).setCorner(0f).setPaddding(p).setBorder(borderThickness).addMouseListener(dragZoomRotateListener) ); + } + groupB1.setBorder(sxy*borderThickness).setBorderColor(borderColor); + // groupB1.scale(2*sxy, 2*sxy, 1); + groupB1.setInteractive(true); + groupB1.validate(reqGLP); + groupB1.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupB1.getScaledHeight(), 0); + System.err.println("Group-B1 "+groupB1); + System.err.println("Group-B1 Layout "+groupB1.getLayout()); + groupB1.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupB1); + nextXPos += groupB1.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupB1.markShapeDirty(); + groupB1.validate(reqGLP); + System.err.println("Group-B1.2 "+groupB1); + System.err.println("Group-B1 Layout.2 "+groupB1.getLayout()); + groupB1.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupB2 = new Group(new GridLayout(2, sxy, sxy/2f, Alignment.FillCenter, new Gap(sxy*0.10f))); + { + final Padding p = new Padding(sxy/2f*0.05f); + groupB2.addShape( new Button(options.renderModes, font, "ro co", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB2.addShape( new Button(options.renderModes, font, "r1 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).setDragAndResizeable(false) ); + groupB2.addShape( new Button(options.renderModes, font, "r2 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).setDragAndResizeable(false) ); + groupB2.addShape( new Button(options.renderModes, font, "r2 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB2.addShape( new Button(options.renderModes, font, "r3 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + } + groupB2.setBorder(sxy*borderThickness).setBorderColor(borderColor); + // groupB2.scale(2*sxy, 2*sxy, 1); + groupB2.setInteractive(true); + groupB2.validate(reqGLP); + groupB2.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupB2.getScaledHeight(), 0); + System.err.println("Group-B2 "+groupB2); + System.err.println("Group-B2 Layout "+groupB2.getLayout()); + groupB2.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupB2); + nextXPos += groupB2.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupB2.markShapeDirty(); + groupB2.validate(reqGLP); + System.err.println("Group-B2.2 "+groupB2); + System.err.println("Group-B2 Layout.2 "+groupB2.getLayout()); + groupB2.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupB3 = new Group(new GridLayout(2, sxy, sxy/2f, Alignment.Fill, new Gap(sxy*0.10f))); + { + final Padding p = new Padding(sxy/2f*0.05f); + groupB3.addShape( new Button(options.renderModes, font, "ro co", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB3.addShape( new Button(options.renderModes, font, "r1 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).setDragAndResizeable(false) ); + groupB3.addShape( new Button(options.renderModes, font, "r2 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).setDragAndResizeable(false) ); + groupB3.addShape( new Button(options.renderModes, font, "r2 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupB3.addShape( new Button(options.renderModes, font, "r3 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy/2f*borderThickness).addMouseListener(dragZoomRotateListener) ); + } + groupB3.setBorder(sxy*borderThickness).setBorderColor(borderColor); + // groupB3.scale(2*sxy, 2*sxy, 1); + groupB3.setInteractive(true); + groupB3.validate(reqGLP); + groupB3.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupB3.getScaledHeight(), 0); + System.err.println("Group-B3 "+groupB3); + System.err.println("Group-B3 Layout "+groupB3.getLayout()); + groupB3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupB3); + nextXPos += groupB3.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupB3.markShapeDirty(); + groupB3.validate(reqGLP); + System.err.println("Group-B3.2 "+groupB3); + System.err.println("Group-B3 Layout.2 "+groupB3.getLayout()); + groupB3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + // next line + nextXPos = 0; + nextYTop = sceneBox.getHeight()/3f; + + final Group groupC0 = new Group(new GridLayout(2, 0, 0, Alignment.Fill, new Gap(0.03f))); + { + final Group glyphGrid = new Group(new GridLayout(2, 0.3f, 0.3f, Alignment.Fill, new Gap(0.3f * 0.10f))); + glyphGrid.addShape( new Button(options.renderModes, font, "0.0", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + glyphGrid.addShape( new Button(options.renderModes, font, "0.1", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + glyphGrid.addShape( new Button(options.renderModes, font, "1.0", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + glyphGrid.addShape( new Button(options.renderModes, font, "1.1", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupC0.addShape(glyphGrid.setBorder(borderThickness)); + + final Group infoGrid = new Group(new GridLayout(1, 1/4f, 1/2f, Alignment.Fill, new Gap(0.02f))); + // final Group glyphView = new Group(); + // glyphView.addShape(new Rectangle(options.renderModes, 1f, 1f, 0.005f).setInteractive(false)); + // glyphView.addShape(new Button(options.renderModes, font, "S", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + // infoGrid.addShape(glyphView.setBorder(borderThickness)); + infoGrid.addShape(new Button(options.renderModes, font, " S ", 1/2f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + + // final Group infoView = new Group(); + // infoView.addShape(new Button(options.renderModes, font, "Info", 1f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + // infoGrid.addShape(infoView.setBorder(borderThickness)); + infoGrid.addShape(new Button(options.renderModes, font, " Info ", 1/2f, 1f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + groupC0.addShape(infoGrid.setBorder(borderThickness)); + // groupC0.addShape(new Button(options.renderModes, font, "S", 1/4f, 0.5f).setCorner(0f).setBorder(borderThickness).setDragAndResizeable(false) ); + } + groupC0.setBorder(sxy*borderThickness).setBorderColor(borderColor); + groupC0.scale(2*sxy, 2*sxy, 1); + groupC0.setInteractive(true); + groupC0.validate(reqGLP); + groupC0.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupC0.getScaledHeight(), 0); + System.err.println("Group-C0 "+groupC0); + System.err.println("Group-C0 Layout "+groupC0.getLayout()); + groupC0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupC0); + nextXPos += groupC0.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupC0.markShapeDirty(); + groupC0.validate(reqGLP); + System.err.println("Group-C0.2 "+groupC0); + System.err.println("Group-C0 Layout.2 "+groupC0.getLayout()); + groupC0.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + final Group groupC3 = new Group(new GridLayout(2, sxy, sxy/2f, Alignment.Center, new Gap(sxy*0.10f))); + { + final Padding p = new Padding(sxy*0.05f); + groupC3.addShape( new Button(options.renderModes, font, "ro co", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupC3.addShape( new Button(options.renderModes, font, "r1 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy*borderThickness).setDragAndResizeable(false) ); + groupC3.addShape( new Button(options.renderModes, font, "r2 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy*borderThickness).setDragAndResizeable(false) ); + groupC3.addShape( new Button(options.renderModes, font, "r2 c2", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy*borderThickness).addMouseListener(dragZoomRotateListener) ); + groupC3.addShape( new Button(options.renderModes, font, "r3 c1", sxy/2f, sxy/4f).setCorner(0f).setPaddding(p).setBorder(sxy*borderThickness).addMouseListener(dragZoomRotateListener) ); + } + groupC3.setBorder(sxy*borderThickness).setBorderColor(borderColor); + // groupC3.scale(2*sxy, 2*sxy, 1); + groupC3.setInteractive(true); + groupC3.validate(reqGLP); + groupC3.moveTo(sceneBox.getLow()).move(nextXPos, nextYTop-groupC3.getScaledHeight(), 0); + System.err.println("Group-C3 "+groupC3); + System.err.println("Group-C3 Layout "+groupC3.getLayout()); + groupC3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(groupC3); + nextXPos += groupC3.getScaledWidth() * 1.1f; + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + groupC3.markShapeDirty(); + groupC3.validate(reqGLP); + System.err.println("Group-C3.2 "+groupC3); + System.err.println("Group-C3 Layout.2 "+groupC3.getLayout()); + groupC3.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + scene.screenshot(true, scene.nextScreenshotFile(null, UILayoutGrid01.class.getSimpleName(), options.renderModes, caps, null)); + if( !options.stayOpen ) { + window.destroy(); + } + } +} diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java index c5aa32d55..0c00508d8 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03.java @@ -128,7 +128,7 @@ public class UISceneDemo03 { final Scene scene = new Scene(); scene.setClearParams(new float[] { 1f, 1f, 1f, 1f }, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); - scene.setDebugBox(options.debugBoxThickness); + scene.setDebugBorderBox(options.debugBoxThickness); final Group glyphGroup = new Group(); scene.addShape(glyphGroup); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03b.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03b.java index 1668ec883..805d9dafc 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03b.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo03b.java @@ -100,7 +100,9 @@ public class UISceneDemo03b { } public static void main(final String[] args) throws IOException { - int autoSpeed = 0; + int autoSpeed = -1; + setVelocity(80/1000f); + options.keepRunning = true; if (0 != args.length) { final int[] idx = { 0 }; @@ -110,6 +112,7 @@ public class UISceneDemo03b { } else if (args[idx[0]].equals("-v")) { ++idx[0]; setVelocity(MiscUtils.atoi(args[idx[0]], (int) velocity * 1000) / 1000f); + autoSpeed = 0; } else if(args[idx[0]].equals("-aspeed")) { autoSpeed = -1; setVelocity(80/1000f); @@ -134,12 +137,12 @@ public class UISceneDemo03b { final Scene scene = new Scene(); scene.setClearParams(new float[] { 1f, 1f, 1f, 1f }, GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); - scene.setDebugBox(options.debugBoxThickness); + scene.setDebugBorderBox(options.debugBoxThickness); final Group glyphGroup = new Group(); scene.addShape(glyphGroup); - // scene.setFrustumCullingEnabled(true); + scene.setFrustumCullingEnabled(true); glyphGroup.setFrustumCullingEnabled(true); final Animator animator = new Animator(); @@ -212,6 +215,13 @@ public class UISceneDemo03b { final GLProfile hasGLP = window.getChosenGLCapabilities().getGLProfile(); final AABBox sceneBox = scene.getBounds(); + glyphGroup.addShape( new Rectangle(options.renderModes, sceneBox, sceneBox.getWidth()*0.01f) ); + // glyphGroup.addShape( new Rectangle(options.renderModes, sceneBox.getMinX(), sceneBox.getMinY(), sceneBox.getWidth(), sceneBox.getHeight(), sceneBox.getWidth()*0.01f) ); + // glyphGroup.addShape( new Rectangle(options.renderModes, sceneBox.getMinX()*0.5f, sceneBox.getMinY()*0.5f, sceneBox.getWidth()*0.5f, sceneBox.getHeight()*0.5f, sceneBox.getWidth()*0.5f*0.01f, sceneBox.getMinZ()) ); + glyphGroup.scale(0.8f, 0.8f, 1f); + // glyphGroup.scale(0.5f, 0.5f, 1f); + glyphGroup.setRotationPivot(0, 0, 0); + glyphGroup.validate(hasGLP); System.err.println("SceneBox " + sceneBox); System.err.println("Frustum " + scene.getMatrix().getFrustum()); System.err.println("GlyphGroup.0: "+glyphGroup); @@ -259,7 +269,8 @@ public class UISceneDemo03b { // Setup the moving glyphs // - final List<GlyphShape> glyphShapes = new ArrayList<GlyphShape>(); + final List<GlyphShape> glyphShapesAnim = new ArrayList<GlyphShape>(); + final List<GlyphShape> glyphShapesAll = new ArrayList<GlyphShape>(); final float pixPerMM, dpiV; { @@ -271,12 +282,14 @@ public class UISceneDemo03b { boolean z_only = true; int txt_idx = 0; - final AABBox glyphBox = glyphGroup.getBounds().resize(sceneBox); + final AABBox glyphBox = glyphGroup.getBounds(); final float g_w = glyphBox.getWidth(); final float g_h = glyphBox.getHeight(); - glyphGroup.scale(0.8f, 0.8f, 1f); - glyphGroup.validate(hasGLP); + + // glyphGroup.scale(0.8f, 0.8f, 1f); + // glyphGroup.validate(hasGLP); System.err.println("GlyphBox " + glyphBox); + System.err.println("GlyphGroup " + glyphGroup); glyphGroup.addMouseListener( new Shape.MouseGestureAdapter() { @Override @@ -361,11 +374,11 @@ public class UISceneDemo03b { } z_only = !z_only; window.invoke(true, (drawable) -> { - glyphGroup.removeAllShapes(drawable.getGL().getGL2ES2(), scene.getRenderer()); + glyphGroup.removeShapes(drawable.getGL().getGL2ES2(), scene.getRenderer(), glyphShapesAll); return true; }); - glyphGroup.addShape( new Rectangle(options.renderModes, g_w, g_h, g_w*0.01f) ); - glyphGroup.getShapes().get(0).setInteractive(false); + glyphShapesAll.clear(); + glyphShapesAnim.clear(); final float[] movingGlyphPixPerShapeUnit; { @@ -378,9 +391,9 @@ public class UISceneDemo03b { final int[] movingGlyphSizePx = testGlyph.getSurfaceSize(scene, pmv, new int[2]); // [px] movingGlyphPixPerShapeUnit = testGlyph.getPixelPerShapeUnit(movingGlyphSizePx, new float[2]); // [px]/[shapeUnit] - final AABBox box = GlyphShape.processString(glyphShapes, options.renderModes, font, originalTexts[txt_idx]); + final AABBox box = GlyphShape.processString(glyphShapesAll, options.renderModes, font, originalTexts[txt_idx]); System.err.println("Shapes: "+box); - for(final GlyphShape gs : glyphShapes) { + for(final GlyphShape gs : glyphShapesAll) { gs.setScale(fontScale, fontScale, 1f); gs.setColor(0.1f, 0.1f, 0.1f, 1); final Vec3f target = gs.getOrigPos(fontScale).add(glyphBox.getMinX(), 0f, 0f); @@ -396,14 +409,15 @@ public class UISceneDemo03b { testGlyph.setEnabled(false); glyphGroup.addShape(testGlyph); } - glyphGroup.addShapes(glyphShapes); + glyphGroup.addShapes(glyphShapesAll); + glyphShapesAnim.addAll(glyphShapesAll); final float pos_eps = FloatUtil.EPSILON * 5000; // ~= 0.0005960 final float rot_eps = FloatUtil.adegToRad(0.5f); // 1 adeg ~= 0.01745 rad final long t0_us = Clock.currentNanos() / 1000; // [us] final long[] t2_us = { t0_us }; - while (!glyphShapes.isEmpty()) { + while (!glyphShapesAnim.isEmpty()) { window.invoke(true, (drawable) -> { final long t3_us = Clock.currentNanos() / 1000; final float dt_s = (t3_us - t2_us[0]) / 1e6f; @@ -413,8 +427,8 @@ public class UISceneDemo03b { final float velocity_obj = velocity_px / movingGlyphPixPerShapeUnit[0]; // [shapeUnit]/[s] final float dxy = velocity_obj * dt_s; // [shapeUnit] - for (int idx = glyphShapes.size() - 1; 0 <= idx; --idx) { - final GlyphShape glyph = glyphShapes.get(idx); + for (int idx = glyphShapesAnim.size() - 1; 0 <= idx; --idx) { + final GlyphShape glyph = glyphShapesAnim.get(idx); final Vec3f pos = new Vec3f(glyph.getPosition()); final Vec3f target = glyph.getOrigPos(fontScale).add(glyphBox.getMinX(), 0f, 0f); final Vec3f p_t = target.minus(pos); @@ -435,7 +449,7 @@ public class UISceneDemo03b { } glyph.moveTo(target.x(), target.y(), target.z()); q.setIdentity(); - glyphShapes.remove(idx); + glyphShapesAnim.remove(idx); continue; } if( !pos_ok ) { diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo11.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo11.java index 001f585fd..6c20247c2 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo11.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo11.java @@ -37,8 +37,9 @@ import com.jogamp.graph.font.FontSet; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.layout.Alignment; +import com.jogamp.graph.ui.layout.Gap; import com.jogamp.graph.ui.layout.GridLayout; -import com.jogamp.graph.ui.layout.Padding; import com.jogamp.graph.ui.shapes.Button; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; @@ -81,7 +82,7 @@ public class UISceneDemo11 { final Font font = FontFactory.get(FontFactory.UBUNTU).get(FontSet.FAMILY_LIGHT, FontSet.STYLE_SERIF); System.err.println("Font: "+font.getFullFamilyName()); - final Group groupA0 = new Group(new GridLayout(2, 1f, 1/2f, new Padding(0.05f, 0.05f))); + final Group groupA0 = new Group(new GridLayout(2, 1f, 1/2f, Alignment.Fill, new Gap(0.10f))); { groupA0.addShape( new Button(options.renderModes, font, "r1 c1", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); groupA0.addShape( new Button(options.renderModes, font, "r1 c2", 1f, 1f/2f).setCorner(0f).setDragAndResizeable(false) ); diff --git a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java index d732795ca..eeb52082f 100644 --- a/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UISceneDemo20.java @@ -49,8 +49,9 @@ import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; import com.jogamp.graph.ui.Scene.PMVMatrixSetup; +import com.jogamp.graph.ui.layout.Alignment; +import com.jogamp.graph.ui.layout.Gap; import com.jogamp.graph.ui.layout.GridLayout; -import com.jogamp.graph.ui.layout.Padding; import com.jogamp.graph.ui.shapes.Button; import com.jogamp.graph.ui.shapes.GLButton; import com.jogamp.graph.ui.shapes.ImageButton; @@ -307,7 +308,7 @@ public class UISceneDemo20 implements GLEventListener { scene.setPMVMatrixSetup(new MyPMVMatrixSetup()); scene.getRenderState().setHintMask(RenderState.BITHINT_GLOBAL_DEPTH_TEST_ENABLED); // scene.setSampleCount(3); // easy on embedded devices w/ just 3 samples (default is 4)? - scene.setDebugBox(options.debugBoxThickness); + scene.setDebugBorderBox(options.debugBoxThickness); scene.addShape(buttonsLeft); scene.addShape(buttonsRight); } @@ -384,12 +385,12 @@ public class UISceneDemo20 implements GLEventListener { final float buttonLWidth = buttonXSizeNorm; final float buttonLHeight = buttonLWidth / 2.5f; - buttonsLeft.setLayout(new GridLayout(buttonLWidth, buttonLHeight, new Padding(buttonLHeight*0.25f, buttonLWidth*0.05f), 7)); + buttonsLeft.setLayout(new GridLayout(buttonLWidth, buttonLHeight, Alignment.Fill, new Gap(buttonLHeight*0.50f, buttonLWidth*0.10f), 7)); final float buttonRWidth = 2f*buttonLWidth; final float buttonRHeight = 2f*buttonLHeight; - buttonsRight.setLayout(new GridLayout(1, buttonRWidth, buttonRHeight, new Padding(buttonLHeight*0.25f, buttonLWidth*0.05f))); + buttonsRight.setLayout(new GridLayout(1, buttonRWidth, buttonRHeight, Alignment.Fill, new Gap(buttonLHeight*0.50f, buttonLWidth*0.10f))); System.err.println("Button Size: "+buttonLWidth+" x "+buttonLHeight); @@ -861,20 +862,22 @@ public class UISceneDemo20 implements GLEventListener { buttonsRight.setScale(button_sxy, button_sxy, 1f); final float dz = 0f; - final float dyTop = sceneHeight * relTop; + final float dxLeft = sceneBox.getMinX(); + final float dyBottom = sceneBox.getMinY(); + final float dyTop = dyBottom + sceneHeight * relTop; System.err.println("XXX: dw "+sceneWidth+", dh "+sceneHeight+", dyTop "+dyTop); System.err.println("BL "+buttonsLeft); System.err.println("BL "+buttonsLeft.getLayout()); System.err.println("BR "+buttonsRight); System.err.println("BR "+buttonsRight.getLayout()); - buttonsLeft.moveTo(0f, dyTop - buttonsLeft.getScaledHeight(), dz); - buttonsRight.moveTo(sceneWidth - buttonsRight.getScaledWidth(), dyTop - buttonsRight.getScaledHeight(), dz); + buttonsLeft.moveTo(dxLeft, dyTop - buttonsLeft.getScaledHeight(), dz); + buttonsRight.moveTo(dxLeft + sceneWidth - buttonsRight.getScaledWidth(), dyTop - buttonsRight.getScaledHeight(), dz); jogampLabel.setScale(sceneHeight, sceneHeight, 1f); - final float dxMiddleAbs = sceneWidth * relMiddle; - final float dyTopLabelAbs = sceneHeight - jogampLabel.getScaledLineHeight(); + final float dxMiddleAbs = dxLeft + sceneWidth * relMiddle; + final float dyTopLabelAbs = dyBottom + sceneHeight - jogampLabel.getScaledLineHeight(); jogampLabel.moveTo(dxMiddleAbs, dyTopLabelAbs - jogampLabel.getScaledLineHeight(), dz); { final float pixelSize10Pt = FontScale.toPixels(fontSizePt, dpiV); @@ -920,8 +923,8 @@ public class UISceneDemo20 implements GLEventListener { if(null == labels[currentText]) { final AABBox sbox = scene.getBounds(); final float sceneHeight = sbox.getHeight(); - final float dyTop = sbox.getHeight() - jogampLabel.getScaledLineHeight(); - final float dxMiddle = sbox.getWidth() * relMiddle; + final float dyTop = sbox.getMinY() + sbox.getHeight() - jogampLabel.getScaledLineHeight(); + final float dxMiddle = sbox.getMinX() + sbox.getWidth() * relMiddle; labels[currentText] = new Label(renderModes, font, fontSizeFixedNorm, strings[currentText]); labels[currentText].setScale(sceneHeight, sceneHeight, 1f); labels[currentText].setColor(0.1f, 0.1f, 0.1f, 1.0f); @@ -984,32 +987,33 @@ public class UISceneDemo20 implements GLEventListener { /** * Our PMVMatrixSetup: * - gluPerspective like Scene's default - * - no normal scale to 1, keep distance to near plane for rotation effects. We scale Shapes - * - translate origin to bottom-left + * - no normal scale to 1, keep a longer distance to near plane for rotation effects. We scale Shapes */ public static class MyPMVMatrixSetup implements PMVMatrixSetup { + static float Z_DIST = -1f; @Override public void set(final PMVMatrix pmv, final Recti viewport) { final float ratio = (float)viewport.width()/(float)viewport.height(); pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); pmv.glLoadIdentity(); pmv.gluPerspective(Scene.DEFAULT_ANGLE, ratio, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR); - pmv.glTranslatef(0f, 0f, Scene.DEFAULT_SCENE_DIST); + pmv.glTranslatef(0f, 0f, Z_DIST); pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); pmv.glLoadIdentity(); - - // Translate origin to bottom-left - final AABBox planeBox0 = new AABBox(); - setPlaneBox(planeBox0, pmv, viewport); - pmv.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - pmv.glTranslatef(planeBox0.getMinX(), planeBox0.getMinY(), 0f); - pmv.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); } @Override public void setPlaneBox(final AABBox planeBox, final PMVMatrix pmv, final Recti viewport) { - Scene.getDefaultPMVMatrixSetup().setPlaneBox(planeBox, pmv, viewport); + // Scene.getDefaultPMVMatrixSetup().setPlaneBox(planeBox, pmv, viewport); + final float orthoDist = -Z_DIST; // Scene.DEFAULT_SCENE_DIST; + final Vec3f obj00Coord = new Vec3f(); + final Vec3f obj11Coord = new Vec3f(); + + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.x(), viewport.y(), orthoDist, obj00Coord); + Scene.winToPlaneCoord(pmv, viewport, Scene.DEFAULT_ZNEAR, Scene.DEFAULT_ZFAR, viewport.width(), viewport.height(), orthoDist, obj11Coord); + + planeBox.setSize( obj00Coord, obj11Coord ); } }; diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/Alignment.java b/src/graphui/classes/com/jogamp/graph/ui/layout/Alignment.java index b43de332c..544ae3f26 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/Alignment.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/Alignment.java @@ -39,6 +39,8 @@ public final class Alignment { public static final Alignment Center = new Alignment(Alignment.Bit.Center); /** {@link Bit#Fill} alignment constant. */ public static final Alignment Fill = new Alignment(Alignment.Bit.Fill.value); + /** {@link Bit#Fill} and {@link Bit#Center} alignment constant. */ + public static final Alignment FillCenter = new Alignment(Alignment.Bit.Fill.value | Alignment.Bit.Center.value); public enum Bit { /** Left alignment. */ diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java b/src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java index 6f6e610f6..acd58d0ab 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/BoxLayout.java @@ -39,16 +39,17 @@ import com.jogamp.opengl.util.PMVMatrix; * GraphUI Stack {@link Group.Layout}. * <p> * A stack of {@link Shape}s - * - size kept unscaled - * - position depends on {@Link Padding} and {@link Margin} - * - *cell* size can be set + * - Size kept unscaled + * - Position depends on {@Link Padding} and {@link Margin} + * - Cell size can be set * </p> */ public class BoxLayout implements Group.Layout { private final float cellWidth, cellHeight; private final Margin margin; private final Padding padding; - private final float borderThickness; + + private static final boolean TRACE_LAYOUT = false; public BoxLayout(final Padding padding) { this(0f, 0f, new Margin(), padding); @@ -56,12 +57,19 @@ public class BoxLayout implements Group.Layout { public BoxLayout(final float width, final float height, final Margin margin) { this(width, height, margin, new Padding()); } + + /** + * + * @param width + * @param height + * @param margin + * @param padding + */ public BoxLayout(final float width, final float height, final Margin margin, final Padding padding) { this.cellWidth = Math.max(0f, width); this.cellHeight = Math.max(0f, height); this.margin = margin; this.padding = padding; - this.borderThickness = 0f; } public Padding getPadding() { return padding; } @@ -75,6 +83,8 @@ public class BoxLayout implements Group.Layout { final AABBox sbox = new AABBox(); for(int i=0; i < shapes.size(); ++i) { final Shape s = shapes.get(i); + + // measure size pmv.glPushMatrix(); s.setTransform(pmv); s.getBounds().transformMv(pmv, sbox); @@ -83,34 +93,39 @@ public class BoxLayout implements Group.Layout { // adjust size and position (centered) final float paddedWidth = sbox.getWidth() + padding.width(); final float paddedHeight = sbox.getHeight() + padding.height(); - final float marginedWidth = paddedWidth + margin.width(); - final float marginedHeight = paddedHeight + margin.height(); - final float cellWidth2 = hasCellWidth ? cellWidth : marginedWidth; - final float cellHeight2 = hasCellHeight ? cellHeight : marginedHeight; - final float x, y; - if( margin.isCenteredHoriz() || hasCellWidth && sbox.getWidth() + padding.width() + margin.width() > cellWidth2 ) { - x = 0; - } else { - x = margin.left + padding.left; + final float cellWidth2 = hasCellWidth ? cellWidth : paddedWidth; + final float cellHeight2 = hasCellHeight ? cellHeight : paddedHeight; + float x = margin.left; + float y = margin.bottom; + if( !margin.isCenteredHoriz() && paddedWidth <= cellWidth2 ) { + x += padding.left; } - if( margin.isCenteredVert() || hasCellHeight && sbox.getHeight() + padding.height() + margin.height() > cellHeight2 ) { - y = 0; - } else { - y = margin.bottom + padding.bottom; + if( !margin.isCenteredVert() && paddedHeight <= cellHeight2 ) { + y += padding.bottom; } - float dxh = 0, dyh = 0; + final float dxh, dyh; if( margin.isCenteredHoriz() ) { - dxh += 0.5f * ( cellWidth2 - paddedWidth ); // actual horiz-centered + dxh = 0.5f * ( cellWidth2 - paddedWidth ); // actual horiz-centered + } else { + dxh = 0; } if( margin.isCenteredVert() ) { - dyh += 0.5f * ( cellHeight2 - paddedHeight ); // actual vert-centered + dyh = 0.5f * ( cellHeight2 - paddedHeight ); // actual vert-centered + } else { + dyh = 0; } - System.err.println("["+i+"].m: "+x+" / "+y+" + "+dxh+" / "+dyh+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight()); - s.moveTo( x + dxh, y + dyh, 0f ); // center the scaled artifact + if( TRACE_LAYOUT ) { + System.err.println("bl["+i+"].0: @ "+s.getPosition()+", sbox "+sbox); + System.err.println("bl["+i+"].m: "+x+" / "+y+" + "+dxh+" / "+dyh+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight()); + } + s.move( x + dxh, y + dyh, 0f ); // center the scaled artifact s.move( sbox.getLow().mul(-1f) ); // remove the bottom-left delta - box.resize( x + cellWidth2 + padding.right, y + cellHeight2 + padding.top, 0); - box.resize( x - padding.left, y - padding.bottom, 0); - System.err.println("["+i+"].x: "+x+" / "+y+" + "+dxh+" / "+dyh+" -> "+s.getPosition()+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight()); + // resize bounds including padding, excluding margin + box.resize( x + sbox.getWidth() + padding.right, y + sbox.getHeight() + padding.top, 0); + box.resize( x - padding.left, y - padding.bottom, 0); + if( TRACE_LAYOUT ) { + System.err.println("bl["+i+"].x: "+x+" / "+y+" + "+dxh+" / "+dyh+" -> "+s.getPosition()+", p "+paddedWidth+" x "+paddedHeight+", sz "+cellWidth2+" x "+cellHeight2+", box "+box.getWidth()+" x "+box.getHeight()); + } } } diff --git a/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java b/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java index d5ba8e289..acc82208f 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java +++ b/src/graphui/classes/com/jogamp/graph/ui/layout/GridLayout.java @@ -29,14 +29,22 @@ package com.jogamp.graph.ui.layout; import java.util.List; -import com.jogamp.graph.ui.GraphShape; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Shape; +import com.jogamp.opengl.math.FloatUtil; +import com.jogamp.opengl.math.Vec3f; import com.jogamp.opengl.math.geom.AABBox; import com.jogamp.opengl.util.PMVMatrix; /** * GraphUI Grid {@link Group.Layout}. + * <p> + * A grid of {@link Shape}s + * - Optional cell-size with {@link Alignment#Fill} and or {@link Alignment#Center} + * - Without cell-size behaves like a grid bag using individual shape sizes including padding + * - Can be filled in {@link Order#COLUMN} or {@link Order#ROW} major-order. + * - .. + * </p> */ public class GridLayout implements Group.Layout { /** Layout order for {@link Group#getShapes()}} after population. */ @@ -50,18 +58,21 @@ public class GridLayout implements Group.Layout { private final int col_limit; private final int row_limit; private final float cellWidth, cellHeight; - private final Padding padding; + private final Alignment alignment; + private final Gap gap; private int row_count, col_count; + private static final boolean TRACE_LAYOUT = false; /** * Default layout order of {@link Group#getShapes()}} is {@link Order#COLUMN}. * @param column_limit [1..inf) * @param cellWidth * @param cellHeight + * @param alignment TODO */ - public GridLayout(final int column_limit, final float cellWidth, final float cellHeight) { - this(Math.max(1, column_limit), -1, cellWidth, cellHeight, new Padding()); + public GridLayout(final int column_limit, final float cellWidth, final float cellHeight, final Alignment alignment) { + this(alignment, Math.max(1, column_limit), -1, cellWidth, cellHeight, new Gap()); } /** @@ -69,30 +80,33 @@ public class GridLayout implements Group.Layout { * @param column_limit [1..inf) * @param cellWidth * @param cellHeight - * @param padding + * @param alignment TODO + * @param gap */ - public GridLayout(final int column_limit, final float cellWidth, final float cellHeight, final Padding padding) { - this(Math.max(1, column_limit), -1, cellWidth, cellHeight, padding); + public GridLayout(final int column_limit, final float cellWidth, final float cellHeight, final Alignment alignment, final Gap gap) { + this(alignment, Math.max(1, column_limit), -1, cellWidth, cellHeight, gap); } /** * Default layout order of {@link Group#getShapes()}} is {@link Order#ROW}. * @param cellWidth * @param cellHeight - * @param padding + * @param alignment TODO + * @param gap * @param row_limit [1..inf) */ - public GridLayout(final float cellWidth, final float cellHeight, final Padding padding, final int row_limit) { - this(-1, Math.max(1, row_limit), cellWidth, cellHeight, padding); + public GridLayout(final float cellWidth, final float cellHeight, final Alignment alignment, final Gap gap, final int row_limit) { + this(alignment, -1, Math.max(1, row_limit), cellWidth, cellHeight, gap); } - private GridLayout(final int column_limit, final int row_limit, final float cellWidth, final float cellHeight, final Padding padding) { + private GridLayout(final Alignment alignment, final int column_limit, final int row_limit, final float cellWidth, final float cellHeight, final Gap gap) { this.order = 0 < column_limit ? Order.COLUMN : Order.ROW; this.col_limit = column_limit; this.row_limit = row_limit; this.cellWidth = cellWidth; this.cellHeight = cellHeight; - this.padding = padding;; + this.alignment = alignment; + this.gap = gap; row_count = 0; col_count = 0; } @@ -100,9 +114,226 @@ public class GridLayout implements Group.Layout { public Order getOrder() { return order; } public int getColumnCount() { return col_count; } public int getRowCount() { return row_count; } + public Gap getGap() { return gap; } @Override public void layout(final Group g, final AABBox box, final PMVMatrix pmv) { + layout1(g, box, pmv); + } + private void layout1(final Group g, final AABBox box, final PMVMatrix pmv) { + final Vec3f zeroVec3 = new Vec3f(); + final boolean hasCellWidth = !FloatUtil.isZero(cellWidth); + final boolean hasCellHeight = !FloatUtil.isZero(cellHeight); + final boolean isCenteredHoriz = hasCellWidth && alignment.isSet(Alignment.Bit.Center); + final boolean isCenteredVert = hasCellHeight && alignment.isSet(Alignment.Bit.Center); + final boolean isScaled = alignment.isSet(Alignment.Bit.Fill) && ( hasCellWidth || hasCellHeight ); + final List<Shape> shapes = g.getShapes(); + if( Order.COLUMN == order ) { + row_count = (int) Math.ceil( (double)shapes.size() / (double)col_limit ); + col_count = col_limit; + } else { // Order.ROW_MAJOR == order + row_count = row_limit; + col_count = (int) Math.ceil( (double)shapes.size() / (double)row_limit ); + } + if( TRACE_LAYOUT ) { + System.err.println("gl.00: "+order+", "+col_count+" x "+row_count+", a "+alignment+", shapes "+shapes.size()+", "+gap); + } + int col_i = 0, row_i = 0; + float x=0, y=0; + float totalWidth=-Float.MAX_VALUE, totalHeight=-Float.MAX_VALUE; + final AABBox[] sboxes = new AABBox[shapes.size()]; + final Vec3f[] diffBLs = new Vec3f[shapes.size()]; + final float[] y_pos = new float[col_count * row_count]; // y_bottom = totalHeight - y_pos[..] + + // Pass-1: Determine totalHeight, while collect sbox and y_pos + for(int i=0; i < shapes.size(); ++i) { + final Shape s = shapes.get(i); + // measure size + pmv.glPushMatrix(); + s.setTransform(pmv); + { + final AABBox sbox0 = s.getBounds(); + sboxes[i] = sbox0.transformMv(pmv, new AABBox()); + + final Vec3f diffBL = new Vec3f(); + if( !diffBL.set( sbox0.getLow().x(), sbox0.getLow().y(), 0).min( zeroVec3 ).isZero() ) { + // pmv.mulMvMatVec3f(diffBL).scale(-1f, -1f, 0f); + final Vec3f ss = s.getScale(); + diffBL.scale(-1f*ss.x(), -1f*ss.y(), 0f); + } + diffBLs[i] = diffBL; + } + pmv.glPopMatrix(); + final AABBox sbox = sboxes[i]; + + final float sxy; + if( isScaled ) { + // scaling to cell size + final float shapeWidthU = sbox.getWidth(); + final float shapeHeightU = sbox.getHeight(); + final float cellWidthU = hasCellWidth ? cellWidth : shapeWidthU; + final float cellHeightU = hasCellHeight ? cellHeight : shapeHeightU; + final float sx = cellWidthU / shapeWidthU; + final float sy = cellHeightU/ shapeHeightU; + sxy = sx < sy ? sx : sy; + } else { + sxy = 1; + } + final float shapeWidthS = sxy*sbox.getWidth(); + final float shapeHeightS = sxy*sbox.getHeight(); + final float cellWidthS = hasCellWidth ? cellWidth : shapeWidthS; + final float cellHeightS = hasCellHeight ? cellHeight : shapeHeightS; + + // bottom y_pos, top to bottom, to be subtracted from totalHeight + final float y0 = y + cellHeightS; + final float x1 = x + cellWidthS; + totalHeight = Math.max(totalHeight, y0); + totalWidth = Math.max(totalWidth, x1); + y_pos[col_count * row_i + col_i] = y0; + if( TRACE_LAYOUT ) { + System.err.println("gl.00: y("+i+")["+col_i+"]["+row_i+"]: "+y0+", ["+cellWidthS+" x "+cellHeightS+"]"); + } + + // position for next cell + if( i + 1 < shapes.size() ) { + if( Order.COLUMN == order ) { + if( col_i + 1 == col_count ) { + col_i = 0; + row_i++; + x = 0; + y += cellHeightS + gap.height(); + } else { + col_i++; + x += cellWidthS + gap.width(); + } + } else { // Order.ROW_MAJOR == order + if( row_i + 1 == row_count ) { + row_i = 0; + col_i++; + y = 0; + x += cellWidthS + gap.width(); + } else { + row_i++; + y += cellHeightS + gap.height(); + } + } + } + } + if( TRACE_LAYOUT ) { + System.err.println("gl[__].00: Total "+totalWidth+" / "+totalHeight); + } + + // Pass-2: Layout + row_i = 0; col_i = 0; + x = 0; y = 0; + for(int i=0; i < shapes.size(); ++i) { + final Shape s = shapes.get(i); + final AABBox sbox = sboxes[i]; + final Vec3f diffBL = diffBLs[i]; + final float zPos = sbox.getCenter().z(); + + if( TRACE_LAYOUT ) { + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].0: "+s); + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].0: sbox "+sbox+", diffBL "+diffBL); + } + + // IF isScaled: Uniform scale w/ lowest axis scale and center position on lower-scale axis + final float sxy; + float dxh = 0, dyh = 0; + if( isScaled ) { + // scaling to cell size + final float shapeWidthU = sbox.getWidth(); + final float shapeHeightU = sbox.getHeight(); + final float cellWidth2 = hasCellWidth ? cellWidth : shapeWidthU; + final float cellHeight2 = hasCellHeight ? cellHeight : shapeHeightU; + final float sx = cellWidth2 / shapeWidthU; + final float sy = cellHeight2/ shapeHeightU; + sxy = sx < sy ? sx : sy; + dxh += shapeWidthU * ( sx - sxy ) * 0.5f; // adjustment for scale-axis + dyh += shapeHeightU * ( sy - sxy ) * 0.5f; // ditto + if( TRACE_LAYOUT ) { + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].s: "+sx+" x "+sy+" -> "+sxy+": +"+dxh+" / "+dyh+", U: s "+shapeWidthU+" x "+shapeHeightU+", sz "+cellWidth2+" x "+cellHeight2); + } + } else { + sxy = 1; + } + final float shapeWidthS = sxy*sbox.getWidth(); + final float shapeHeightS = sxy*sbox.getHeight(); + final float cellWidthS = hasCellWidth ? cellWidth : shapeWidthS; + final float cellHeightS = hasCellHeight ? cellHeight : shapeHeightS; + + y = totalHeight - y_pos[col_count * row_i + col_i]; + + if( isCenteredHoriz ) { + dxh += 0.5f * ( cellWidthS - shapeWidthS ); // actual horiz-centered + } + if( isCenteredVert ) { + dyh += 0.5f * ( cellHeightS - shapeHeightS ); // actual vert-centered + } + if( TRACE_LAYOUT ) { + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].m: "+x+" / "+y+" + "+dxh+" / "+dyh+", S: s "+shapeWidthS+" x "+shapeHeightS+", sz "+cellWidthS+" x "+cellHeightS); + } + { + // New shape position, relative to previous position + final float aX = x + dxh; + final float aY = y + dyh; + s.moveTo( aX, aY, 0f ); + s.move( diffBL.scale(sxy) ); // remove the bottom-left delta + + // resize bounds including padding, excluding margin + box.resize( x, y, zPos); + box.resize( aX + cellWidthS, aY + cellHeightS, zPos); + } + s.scale( sxy, sxy, 1f); + + if( TRACE_LAYOUT ) { + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].x: "+x+" / "+y+" + "+dxh+" / "+dyh+" -> "+s.getPosition()+", p3 "+shapeWidthS+" x "+shapeHeightS+", sz3 "+cellWidthS+" x "+cellHeightS+", box "+box.getWidth()+" x "+box.getHeight()); + System.err.println("gl("+i+")["+col_i+"]["+row_i+"].x: "+s); + } + + if( i + 1 < shapes.size() ) { + // position for next cell + if( Order.COLUMN == order ) { + if( col_i + 1 == col_count ) { + col_i = 0; + row_i++; + x = 0; + } else { + col_i++; + x += cellWidthS + gap.width(); + } + } else { // Order.ROW_MAJOR == order + if( row_i + 1 == row_count ) { + row_i = 0; + col_i++; + y = 0; + x += cellWidthS + gap.width(); + } else { + row_i++; + } + } + } + } + if( TRACE_LAYOUT ) { + System.err.println("gl.xx: "+box); + } + } + + /** + * A fast path layout for set cellWidth > 0 && cellHeight > 0, + * w/o consideration of individual shape height. + */ + @SuppressWarnings("unused") + private void layout0(final Group g, final AABBox box, final PMVMatrix pmv) { + final Vec3f zeroVec3 = new Vec3f(); + final boolean hasCellWidth = !FloatUtil.isZero(cellWidth); + final boolean hasCellHeight = !FloatUtil.isZero(cellHeight); + if( !hasCellWidth || !hasCellHeight ) { + throw new IllegalArgumentException(toString()); + } + final boolean isCenteredHoriz = hasCellWidth && alignment.isSet(Alignment.Bit.Center); + final boolean isCenteredVert = hasCellHeight && alignment.isSet(Alignment.Bit.Center); + final boolean isScaled = alignment.isSet(Alignment.Bit.Fill) && ( hasCellWidth || hasCellHeight ); final List<Shape> shapes = g.getShapes(); if( Order.COLUMN == order ) { row_count = (int) Math.ceil( (double)shapes.size() / (double)col_limit ); @@ -111,40 +342,102 @@ public class GridLayout implements Group.Layout { row_count = row_limit; col_count = (int) Math.ceil( (double)shapes.size() / (double)row_limit ); } + if( TRACE_LAYOUT ) { + System.err.println("gl.00: "+row_count+" x "+col_count+", "+box); + } int col_i = 0, row_i = 0; final AABBox sbox = new AABBox(); - for(final Shape s : shapes) { + final Vec3f diffBL = new Vec3f(); + for(int i=0; i < shapes.size(); ++i) { + final Shape s = shapes.get(i); + // measure size pmv.glPushMatrix(); s.setTransform(pmv); - s.getBounds().transformMv(pmv, sbox); + { + final AABBox sbox0 = s.getBounds(); + sbox0.transformMv(pmv, sbox); + + if( !diffBL.set( sbox0.getLow().x(), sbox0.getLow().y(), 0).min( zeroVec3 ).isZero() ) { + // pmv.mulMvMatVec3f(diffBL).scale(-1f, -1f, 0f); + final Vec3f ss = s.getScale(); + diffBL.scale(-1f*ss.x(), -1f*ss.y(), 0f); + } + } pmv.glPopMatrix(); + final float zPos = sbox.getCenter().z(); + + if( TRACE_LAYOUT ) { + System.err.println("gl["+i+"].0: "+s); + System.err.println("gl["+i+"].0: sbox "+sbox+", diffBL "+diffBL); + } + + // IF hasCell{Width|Height}: Uniform scale w/ lowest axis scale and center position on lower-scale axis + final float sxy; + float dxh = 0, dyh = 0; + if( isScaled ) { + // scaling to cell size + final float shapeWidthU = sbox.getWidth(); + final float shapeHeightU = sbox.getHeight(); + final float cellWidthU = hasCellWidth ? cellWidth : shapeWidthU; + final float cellHeightU = hasCellHeight ? cellHeight : shapeHeightU; + final float sx = cellWidthU / shapeWidthU; + final float sy = cellHeightU/ shapeHeightU; + sxy = sx < sy ? sx : sy; + dxh += shapeWidthU * ( sx - sxy ) * 0.5f; // adjustment for scale-axis + dyh += shapeHeightU * ( sy - sxy ) * 0.5f; // ditto + if( TRACE_LAYOUT ) { + System.err.println("gl["+i+"].s: "+sx+" x "+sy+" -> "+sxy+": +"+dxh+" / "+dyh+", U: s "+shapeWidthU+" x "+shapeHeightU+", sz "+cellWidthU+" x "+cellHeightU); + } + } else { + sxy = 1; + } + final float shapeWidthS = sxy*sbox.getWidth(); + final float shapeHeightS = sxy*sbox.getHeight(); + final float cellWidthS = hasCellWidth ? cellWidth : shapeWidthS; + final float cellHeightS = hasCellHeight ? cellHeight : shapeHeightS; - // adjust size and position (centered) - final float x = ( ( col_i ) * ( cellWidth + padding.width() ) ) + padding.left; - final float y = ( ( row_count - row_i - 1 ) * ( cellHeight + padding.height() ) ) + padding.bottom; - final float sx = cellWidth / sbox.getWidth(); - final float sy = cellHeight/ sbox.getHeight(); - final float sxy = sx < sy ? sx : sy; - final float dxh = sbox.getWidth() * ( sx - sxy ) * 0.5f; - final float dyh = sbox.getHeight() * ( sy - sxy ) * 0.5f; - s.moveTo( x + dxh, y + dyh, 0f ); // center the scaled artifact - s.move( sbox.getLow().mul(-1f*sxy) ); // remove the bottom-left delta + final float x = ( ( col_i ) * ( cellWidthS + gap.width() ) ); + final float y = ( ( row_count - row_i - 1 ) * ( cellHeightS + gap.height() ) ); + + if( isCenteredHoriz ) { + dxh += 0.5f * ( cellWidthS - shapeWidthS ); // actual horiz-centered + } + if( isCenteredVert ) { + dyh += 0.5f * ( cellHeightS - shapeHeightS ); // actual vert-centered + } + if( TRACE_LAYOUT ) { + System.err.println("gl["+i+"].m: "+x+" / "+y+" + "+dxh+" / "+dyh+", S: s "+shapeWidthS+" x "+shapeHeightS+", sz "+cellWidthS+" x "+cellHeightS+", box "+box.getWidth()+" x "+box.getHeight()); + } + { + // New shape position, relative to previous position + final float aX = x + dxh; + final float aY = y + dyh; + s.moveTo( aX, aY, 0f ); + s.move( diffBL.scale(sxy) ); // remove the bottom-left delta + // s.move( sbox.getLow().mul(-1f) ); // remove the bottom-left delta + + // resize bounds including padding, excluding margin + box.resize( aX, aY, zPos); + box.resize( aX + cellWidthS, aY + cellHeightS, zPos); + } s.scale( sxy, sxy, 1f); - box.resize( x + cellWidth + padding.right, y + cellHeight + padding.top, 0); - box.resize( x - padding.left, y - padding.bottom, 0); - // System.err.println("["+row_i+"]["+col_i+"]: "+x+" / "+y+", sxy "+sxy+", d[xy]h "+dxh+" x "+dyh+", "+sbox); + + if( TRACE_LAYOUT ) { + System.err.println("gl["+i+"].x: "+x+" / "+y+" + "+dxh+" / "+dyh+" -> "+s.getPosition()+", p3 "+shapeWidthS+" x "+shapeHeightS+", sz3 "+cellWidthS+" x "+cellHeightS+", box "+box.getWidth()+" x "+box.getHeight()); + System.err.println("gl["+i+"].x: "+s); + } // position for next cell if( Order.COLUMN == order ) { - if( col_i + 1 == col_limit ) { + if( col_i + 1 == col_count ) { col_i = 0; row_i++; } else { col_i++; } } else { // Order.ROW_MAJOR == order - if( row_i + 1 == row_limit ) { + if( row_i + 1 == row_count ) { row_i = 0; col_i++; } else { @@ -152,11 +445,14 @@ public class GridLayout implements Group.Layout { } } } + if( TRACE_LAYOUT ) { + System.err.println("gl.xx: "+box); + } } @Override public String toString() { - return "Grid["+row_count+"x"+col_count+", "+order+", cell["+cellWidth+" x "+cellHeight+"], "+padding+"]"; + return "Grid["+col_count+"x"+row_count+", "+order+", cell["+cellWidth+" x "+cellHeight+", a "+alignment+"], "+gap+"]"; } } diff --git a/src/test/com/jogamp/opengl/test/junit/graph/FontViewListener01.java b/src/test/com/jogamp/opengl/test/junit/graph/FontViewListener01.java index 538c07967..01f6e456d 100644 --- a/src/test/com/jogamp/opengl/test/junit/graph/FontViewListener01.java +++ b/src/test/com/jogamp/opengl/test/junit/graph/FontViewListener01.java @@ -32,8 +32,9 @@ import com.jogamp.graph.font.FontScale; import com.jogamp.graph.ui.Group; import com.jogamp.graph.ui.Scene; import com.jogamp.graph.ui.Shape; +import com.jogamp.graph.ui.layout.Alignment; +import com.jogamp.graph.ui.layout.Gap; import com.jogamp.graph.ui.layout.GridLayout; -import com.jogamp.graph.ui.layout.Padding; import com.jogamp.graph.ui.shapes.GlyphShape; import com.jogamp.graph.ui.shapes.Rectangle; import com.jogamp.newt.opengl.GLWindow; @@ -122,7 +123,7 @@ public class FontViewListener01 implements GLEventListener { final float gridSize = gridCols > gridRows ? 1f/gridCols : 1f/gridRows; System.err.println("Reshape Grid "+gridCols+" x "+gridRows+", "+cellCount+" cells, gridSize "+gridSize); - grid = new Group(new GridLayout(gridCols, gridSize, gridSize, new Padding(gridSize*0.05f, gridSize*0.05f))); + grid = new Group(new GridLayout(gridCols, gridSize, gridSize, Alignment.Fill, new Gap(gridSize*0.10f))); scene.addShape(grid); for(int i=0; i<cellCount; ++i) { |