diff options
author | Sven Gothel <[email protected]> | 2023-09-23 04:02:23 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-09-23 04:02:23 +0200 |
commit | 3ecb8e9d1bfd1149f32b05c13c5ec1be6c0cab54 (patch) | |
tree | 3d87c109d06875d38a2ae07130c37863c9b104f3 | |
parent | 6c97c5fa201d221a37773db54994d27e34ba86c3 (diff) |
GraphUI Layout: Add UILayoutBoxGridOffset01, showing behavior w/ shapes not starting at 0/0 but at an offset
OK for centered or non-zoomed .. as used w/ FontView01 to show the underline space.
Sure, Fill (zoom) w/o center on offset shapes is tricky and a matter of definition and taste, but in general useless.
-rw-r--r-- | make/scripts/tests.sh | 6 | ||||
-rw-r--r-- | src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBoxGridOffset01.java | 373 |
2 files changed, 376 insertions, 3 deletions
diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index ce5401339..309a0604e 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -1008,10 +1008,10 @@ function testawtswt() { #testawt com.jogamp.opengl.demos.es2.GearsES2 $* #testnoawt com.jogamp.opengl.demos.graph.ui.UIGraphDemoU01a $* #testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutGrid01 $* -#testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutGrid02 $* -#testnoawt com.jogamp.opengl.demos.av.MovieCube $* -testnoawt com.jogamp.opengl.demos.av.MovieSimple $* #testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutBox01 $* +testnoawt com.jogamp.opengl.demos.graph.ui.UILayoutBoxGridOffset01 $* +#testnoawt com.jogamp.opengl.demos.av.MovieCube $* +#testnoawt com.jogamp.opengl.demos.av.MovieSimple $* #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/UILayoutBoxGridOffset01.java b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBoxGridOffset01.java new file mode 100644 index 000000000..dc865045a --- /dev/null +++ b/src/demos/com/jogamp/opengl/demos/graph/ui/UILayoutBoxGridOffset01.java @@ -0,0 +1,373 @@ +/** + * 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.layout.Alignment; +import com.jogamp.graph.ui.layout.BoxLayout; +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.Label; +import com.jogamp.graph.ui.shapes.Rectangle; +import com.jogamp.math.FloatUtil; +import com.jogamp.math.Vec3f; +import com.jogamp.math.Vec4f; +import com.jogamp.math.geom.AABBox; +import com.jogamp.math.geom.plane.AffineTransform; +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.Tooltips; +import com.jogamp.opengl.demos.util.CommandlineOptions; +import com.jogamp.opengl.util.Animator; + +/** + * Res independent {@link Shape}s with offset (not starting at origin) + * in a {@link Group} using {@link BoxLayout} and {@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 UILayoutBoxGridOffset01 { + static CommandlineOptions options = new CommandlineOptions(1920, 1080, Region.VBAA_RENDERING_BIT); + + static boolean reLayout = true; + static final int reLayoutSleep = 500; + + private static final Vec4f groupBorderColor = new Vec4f(0, 0, 1f, 0.6f); + private static final float borderThickness = 0.01f; + + 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; + } else if (args[idx[0]].equals("-no_relayout")) { + reLayout = false; + } + } + } + System.err.println(options); + + final GLProfile reqGLP = GLProfile.get(options.glProfileName); + System.err.println("GLProfile: "+reqGLP); + + final Animator animator = new Animator(0 /* w/o AWT */); + + 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(UILayoutBoxGridOffset01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + window.addWindowListener(new WindowAdapter() { + @Override + public void windowResized(final WindowEvent e) { + window.setTitle(UILayoutBoxGridOffset01.class.getSimpleName()+": "+window.getSurfaceWidth()+" x "+window.getSurfaceHeight()); + } + @Override + public void windowDestroyNotify(final WindowEvent e) { + animator.stop(); + } + }); + + + final int zBits = 16; + final Scene scene = new Scene(options.graphAASamples); + scene.setPMVMatrixSetup(new Scene.DefaultPMVMatrixSetup(-1f)); + System.err.println("Z16-Precision: default "+Scene.DEFAULT_Z16_EPSILON); + System.err.println("Z16-Precision: zDist -1f, zNear 0.1f "+FloatUtil.getZBufferEpsilon(zBits, -1f, 0.1f)); + System.err.println("Z16-Precision: current "+scene.getZEpsilon(zBits)); + 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(); + + // + // 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(); + final float zEps = scene.getZEpsilon(zBits); // Z Epsilon, i.e. minimum recognized delta (resolution) + System.err.println("SceneBox "+sceneBox+", zEps "+zEps); + + final float cellGapX = sceneBox.getWidth() / 6f; + final float cellGapY = sceneBox.getHeight() * 0.40f; + // final float sxy = 1/10f * sceneBox.getWidth(); + final float sxy = 1/12f * sceneBox.getWidth(); + // final float sxy = 1/4f * sceneBox.getHeight(); + final Vec3f nextPos = new Vec3f(); + + { + final float minX = 0.00f, minY = 0.00f, width = 0.5f, height = 0.5f, lineWidth = 0.05f; + if( true ) { + final Group g = setupGroup(new Group(new BoxLayout(1f, 1f, Alignment.None)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 11, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + } + { + final float minX = 0.125f, minY = 0.125f, width = 0.5f, height = 0.5f, lineWidth = 0.05f; + if( true ) { + final Group g = setupGroup(new Group(new BoxLayout(1f, 1f, Alignment.None)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 12, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new BoxLayout(1f, 1f, Alignment.Fill)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 13, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new BoxLayout(1f, 1f, Alignment.Center)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 14, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new BoxLayout(1f, 1f, Alignment.FillCenter)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 15, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + } + + + // + // + // next line + nextPos.set(0, nextPos.y() + cellGapY / 2f, 0 ); + + { + final float minX = 0.000f, minY = 0.000f, width = 0.5f, height = 0.5f, lineWidth = 0.05f; + if( true ) { + final Group g = setupGroup(new Group(new GridLayout(2, 1f, 1f, Alignment.None)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 21, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + } + { + final float minX = 0.125f, minY = 0.125f, width = 0.5f, height = 0.5f, lineWidth = 0.05f; + if( true ) { + final Group g = setupGroup(new Group(new GridLayout(2, 1f, 1f, Alignment.None)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 22, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new GridLayout(2, 1f, 1f, Alignment.Fill)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 23, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new GridLayout(2, 1f, 1f, Alignment.Center)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 24, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + if( true ) { + final Group g = setupGroup(new Group(new GridLayout(2, 1f, 1f, Alignment.FillCenter)), + reqGLP, scene, zEps, + sxy, nextPos, cellGapX, + font, 25, + (final Group gp) -> { + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + gp.addShape( new Rectangle(options.renderModes, minX, minY, width, height, lineWidth, 0).setDragAndResizeable(false) ); + }, minX, minY ); + nextPos.setX( nextPos.x() + cellGapX ); + } + } + + // next line + nextPos.set(0, nextPos.y() + cellGapY, 0 ); + + // ... + + { + final AABBox sceneDim = scene.getBounds(); + final String text = " Press group description to magnify! "; + final AABBox textDim = font.getGlyphBounds(text, new AffineTransform(), new AffineTransform()); + final float l_sxy = 1/4f * sceneDim.getWidth() / textDim.getWidth(); + + final Shape label = new Label(options.renderModes, font, text).setColor(0, 0, 0, 1).setInteractive(false) + .scale(l_sxy, l_sxy, 1).moveTo(sceneDim.getLow()) + .move(sceneDim.getWidth() - textDim.getWidth()*l_sxy, sceneDim.getHeight() - textDim.getHeight()*l_sxy, 0); + scene.addShape(label); + } + + try { Thread.sleep(1000); } catch (final InterruptedException e1) { } + scene.screenshot(true, scene.nextScreenshotFile(null, UILayoutBoxGridOffset01.class.getSimpleName(), options.renderModes, caps, null)); + if( !options.stayOpen ) { + window.destroy(); + } + } + + static interface GroupMod { + void mod(Group group); + } + static Group setupGroup(final Group g, final GLProfile reqGLP, final Scene scene, final float zEps, + final float sxy, final Vec3f nextPos, final float cellGap, + final Font font, final int id, + final GroupMod modImpl, final float offX, final float offY) { + final String suffix = String.format("%2d", id); + g.setName(id); + final AABBox sceneBox = scene.getBounds(); + modImpl.mod(g); + g.setBorder(borderThickness).setBorderColor(groupBorderColor); + g.scale(sxy, sxy, 1); + g.setInteractive(true); + g.validate(reqGLP); + g.moveTo(sceneBox.getLow()).move(nextPos); + System.err.println("Group-"+suffix+" "+g); + System.err.println("Group-"+suffix+" Layout "+g.getLayout()); + g.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + scene.addShape(g); + { + final float X_width = font.getGlyph(font.getGlyphID(' ')).getAdvance(); + /** + * ID 23: G 23, size[total 2.1 x 1.7, cell 1.0 x 0.5] + * Padding[t 0.05, r 0.05, b 0.05, l 0.05] + * Gap[r 0.1, c 0.1], Align [CenterHoriz, CenterVert, Fill] + */ + final String fixed_text = "Gap[r 0.1, c 0.1], Align [CenterHoriz, CenterVert, Fi"; + final float l_sxy = g.getScaledWidth() / font.getGlyphBounds(fixed_text, new AffineTransform(), new AffineTransform()).getWidth(); + + final String text; + final Group.Layout l = g.getLayout(); + if( l instanceof GridLayout ) { + final GridLayout gl = (GridLayout)l; + text = String.format("Grid %2d, off %.3f/%.3f, size[total %.1f x %.1f, cell %.1f x %.1f]%n%s%n%s, Align %s", + id, offX, offY, g.getBounds().getWidth(), g.getBounds().getHeight(), gl.getCellSize().x(), gl.getCellSize().y(), + ( null == gl.getPadding() || gl.getPadding().zeroSumSize() ) ? "Padding none" : gl.getPadding().toString(), + gl.getGap().zeroSumSize() ? "Gap none" : gl.getGap().toString(), + gl.getAlignment() ); + } else if( l instanceof BoxLayout ){ + final BoxLayout bl = (BoxLayout)l; + text = String.format("Box %2d, off %.3f/%.3f, size[total %.1f x %.1f, cell %.1f x %.1f]%n%s%n%s, Align %s", + id, offX, offY, g.getBounds().getWidth(), g.getBounds().getHeight(), bl.getCellSize().x(), bl.getCellSize().y(), + ( null == bl.getPadding() || bl.getPadding().zeroSumSize() ) ? "Padding none" : bl.getPadding().toString(), + bl.getMargin().zeroSumSize() ? "Margin none" : bl.getMargin().toString(), + bl.getAlignment() ); + } else { + text = String.format("Layout %2d, off %.3f/%.3f, size[total %.1f x %.1f", id, offX, offY, g.getBounds().getWidth(), g.getBounds().getHeight()); + } + final Shape label = new Label(options.renderModes, font, text).setColor(0, 0, 0, 1).validate(reqGLP); + label.scale(l_sxy, l_sxy, 1).moveTo(sceneBox.getLow()).move(nextPos).move(l_sxy*X_width, g.getScaledHeight(), 0) + .addMouseListener(new Tooltips.ZoomLabelOnClickListener(scene, options.renderModes, 1/6f)).setDragAndResizeable(false); + scene.addShape(label); + } + if( reLayout ) { + try { Thread.sleep(reLayoutSleep); } catch (final InterruptedException e1) { } + g.markShapeDirty(); + g.validate(reqGLP); + System.err.println("Group-"+suffix+".2 "+g); + System.err.println("Group-"+suffix+" Layout.2 "+g.getLayout()); + g.forAll( (shape) -> { System.err.println("Shape... "+shape); return false; }); + } + return g; + } + +} |