From 8e1a95aba06089af215a6670fd4add45769d8852 Mon Sep 17 00:00:00 2001 From: SenPie Date: Fri, 26 May 2023 16:27:55 +0400 Subject: [PATCH 1/4] Enhancement: Routine viewport auto camera translate Translate camera, when curve or node is near the edge of viewport. --- .../scene/apps/routines/RoutineEditorApp.java | 47 +++++++++++++++++++ .../talos/editor/nodes/DynamicNodeStage.java | 6 +++ .../talos/editor/nodes/NodeBoard.java | 17 ++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java index c1d5ec138..b7c729059 100644 --- a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java +++ b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java @@ -1,6 +1,9 @@ package com.talosvfx.talos.editor.addons.scene.apps.routines; +import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.Stack; import com.badlogic.gdx.scenes.scene2d.ui.Table; @@ -39,18 +42,62 @@ public RoutineEditorApp() { Notifications.registerObserver(this); routineStage = new RoutineStage(this, SharedResources.skin); routineStageWrapper = new GenericStageWrappedViewportWidget(routineStage.getRootActor()) { + private static final float AUTO_SCROLL_RANGE = 45.0f; + private static final float AUTO_SCROLL_SPEED = 200.0f; @Override protected boolean canMoveAround() { return true; } + private Vector2 tmp = new Vector2(); + @Override public void act(float delta) { super.act(delta); + tmp.set(Gdx.input.getX(), Gdx.input.getY()); + screenToLocalCoordinates(tmp); + + float dt = Gdx.graphics.getDeltaTime(); + OrthographicCamera camera = (OrthographicCamera) routineStageWrapper.getViewportViewSettings().getCurrentCamera(); + + if (routineStage.shouldAutoMove()) { + tmp.set(Gdx.input.getX(), Gdx.input.getY()); + routineStageWrapper.screenToLocalCoordinates(tmp); + + if (isInTopZone(tmp)) { + camera.translate(0, camera.zoom * AUTO_SCROLL_SPEED * dt, 0); + } else if (isInBottomZone(tmp)) { + camera.translate(0, camera.zoom * -AUTO_SCROLL_SPEED * dt, 0); + } + + if (isInLeftZone(tmp)) { + camera.translate(camera.zoom * AUTO_SCROLL_SPEED * dt, 0, 0); + } else if (isInRightZone(tmp)) { + camera.translate(camera.zoom * -AUTO_SCROLL_SPEED * dt, 0, 0); + } + } + routineStage.act(); } + + + private boolean isInRightZone(Vector2 mouse) { + return mouse.x > 0 && mouse.x < AUTO_SCROLL_RANGE; + } + + private boolean isInLeftZone(Vector2 mouse) { + return mouse.x > routineStageWrapper.getWidth() - AUTO_SCROLL_RANGE && mouse.x < routineStageWrapper.getWidth(); + } + + private boolean isInBottomZone(Vector2 mouse) { + return mouse.y > 0 && mouse.y < AUTO_SCROLL_RANGE; + } + + private boolean isInTopZone(Vector2 mouse) { + return mouse.y > routineStageWrapper.getHeight() - AUTO_SCROLL_RANGE && mouse.y < routineStageWrapper.getHeight(); + } }; routineStageWrapper.getDropdownForWorld().setVisible(false); diff --git a/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java b/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java index 5d6b54454..d1a395a58 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java @@ -39,6 +39,8 @@ public abstract class DynamicNodeStage extends W public GameAsset gameAsset; public T data; + public boolean shouldAutoMove; + public DynamicNodeStage (Skin skin) { super(); this.skin = skin; @@ -276,4 +278,8 @@ public DynamicNodeStage getContext () { } public abstract void onNodeSelectionChange (); + + public boolean shouldAutoMove() { + return shouldAutoMove; + } } diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java index c83c88f68..5c014d257 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java @@ -27,7 +27,6 @@ import com.talosvfx.talos.editor.notifications.events.dynamicnodestage.NodeConnectionRemovedEvent; import com.talosvfx.talos.editor.notifications.events.dynamicnodestage.NodeDataModifiedEvent; import com.talosvfx.talos.editor.notifications.events.dynamicnodestage.NodeRemovedEvent; -import com.talosvfx.talos.editor.project2.SharedResources; import com.talosvfx.talos.editor.render.Render; import com.talosvfx.talos.runtime.vfx.Slot; import com.talosvfx.talos.runtime.vfx.modules.AbstractModule; @@ -171,6 +170,19 @@ public void draw (Batch batch, float parentAlpha) { super.draw(batch, parentAlpha); } + + private boolean isHoldingNode; + @Override + public void act(float delta) { + super.act(delta); + + if (activeCurve != null || isHoldingNode) { + nodeStage.shouldAutoMove = true; + } else { + nodeStage.shouldAutoMove = false; + } + } + private void drawCurves () { // draw active curve if (activeCurve != null) { @@ -816,6 +828,8 @@ public void pasteFromClipboard () { } public void nodeClicked (NodeWidget node) { + isHoldingNode = true; + wasNodeDragged = null; if (selectedNodes.contains(node)) { wasNodeSelectedOnDown = node; @@ -844,6 +858,7 @@ public void wrapperMovedBy (NodeWidget node, float x, float y) { } public void nodeClickedUp (NodeWidget node, boolean hasMoved) { + isHoldingNode = false; if (wasNodeDragged != null && hasMoved) { updateSaveState(); From 24ba5c9239649d38e42de971e16a2fcd343e2dfc Mon Sep 17 00:00:00 2001 From: SenPie Date: Thu, 8 Jun 2023 14:00:03 +0400 Subject: [PATCH 2/4] Bugfix: RoutineApp camera auto translate. Could translate the camera even if node was not under mouse focus. Also, added tiny delay before moving. --- .../scene/apps/routines/RoutineEditorApp.java | 18 +++++++++++++++--- .../talosvfx/talos/editor/nodes/NodeBoard.java | 4 +--- .../talos/editor/nodes/NodeWidget.java | 2 ++ 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java index b7c729059..5b9e562e3 100644 --- a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java +++ b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java @@ -52,6 +52,9 @@ protected boolean canMoveAround() { private Vector2 tmp = new Vector2(); + private static final float DELAY_BEFORE_MOVE = 0.3f; + private float delayBeforeMove = DELAY_BEFORE_MOVE; + @Override public void act(float delta) { super.act(delta); @@ -62,10 +65,19 @@ public void act(float delta) { float dt = Gdx.graphics.getDeltaTime(); OrthographicCamera camera = (OrthographicCamera) routineStageWrapper.getViewportViewSettings().getCurrentCamera(); - if (routineStage.shouldAutoMove()) { - tmp.set(Gdx.input.getX(), Gdx.input.getY()); - routineStageWrapper.screenToLocalCoordinates(tmp); + tmp.set(Gdx.input.getX(), Gdx.input.getY()); + routineStageWrapper.screenToLocalCoordinates(tmp); + + boolean shouldMove = routineStage.shouldAutoMove() + && (isInTopZone(tmp) || isInBottomZone(tmp) || isInLeftZone(tmp) || isInRightZone(tmp)); + + if (shouldMove) { + delayBeforeMove -= delta; + } else { + delayBeforeMove = DELAY_BEFORE_MOVE; + } + if (delayBeforeMove < 0) { if (isInTopZone(tmp)) { camera.translate(0, camera.zoom * AUTO_SCROLL_SPEED * dt, 0); } else if (isInBottomZone(tmp)) { diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java index 5c014d257..9a4e9f540 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java @@ -170,8 +170,7 @@ public void draw (Batch batch, float parentAlpha) { super.draw(batch, parentAlpha); } - - private boolean isHoldingNode; + boolean isHoldingNode; @Override public void act(float delta) { super.act(delta); @@ -858,7 +857,6 @@ public void wrapperMovedBy (NodeWidget node, float x, float y) { } public void nodeClickedUp (NodeWidget node, boolean hasMoved) { - isHoldingNode = false; if (wasNodeDragged != null && hasMoved) { updateSaveState(); diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java index e00f73848..5fcfb6048 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java @@ -211,6 +211,8 @@ public void touchUp(InputEvent event, float x, float y, int pointer, int button) if(NodeWidget.this.hit(x, y, true) != null) { nodeBoard.nodeClickedUp(NodeWidget.this, hasMoved); } + + nodeBoard.isHoldingNode = false; } event.cancel(); hasMoved = false; From a6dcfc6169336e589f14b19e52669a71b24adea9 Mon Sep 17 00:00:00 2001 From: SenPie Date: Wed, 21 Jun 2023 14:53:06 +0400 Subject: [PATCH 3/4] Bugfix: Lag when moving nodes. When moving node widget for routine, camera would move, but node would stay in place until the mouse is move manually to trigger touch dragged event. --- .../scene/apps/routines/RoutineEditorApp.java | 59 ------- .../scene/apps/routines/RoutineStage.java | 1 + .../talos/editor/nodes/DynamicNodeStage.java | 10 -- .../talos/editor/nodes/EmptyWindow.java | 167 +++++++++--------- .../talos/editor/nodes/NodeBoard.java | 137 ++++++++++++-- .../talos/editor/nodes/NodeWidget.java | 48 ++--- 6 files changed, 241 insertions(+), 181 deletions(-) diff --git a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java index 5b9e562e3..08d484758 100644 --- a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java +++ b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineEditorApp.java @@ -1,9 +1,6 @@ package com.talosvfx.talos.editor.addons.scene.apps.routines; -import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.OrthographicCamera; -import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.ui.Stack; import com.badlogic.gdx.scenes.scene2d.ui.Table; @@ -42,74 +39,18 @@ public RoutineEditorApp() { Notifications.registerObserver(this); routineStage = new RoutineStage(this, SharedResources.skin); routineStageWrapper = new GenericStageWrappedViewportWidget(routineStage.getRootActor()) { - private static final float AUTO_SCROLL_RANGE = 45.0f; - private static final float AUTO_SCROLL_SPEED = 200.0f; @Override protected boolean canMoveAround() { return true; } - private Vector2 tmp = new Vector2(); - - private static final float DELAY_BEFORE_MOVE = 0.3f; - private float delayBeforeMove = DELAY_BEFORE_MOVE; @Override public void act(float delta) { super.act(delta); - - tmp.set(Gdx.input.getX(), Gdx.input.getY()); - screenToLocalCoordinates(tmp); - - float dt = Gdx.graphics.getDeltaTime(); - OrthographicCamera camera = (OrthographicCamera) routineStageWrapper.getViewportViewSettings().getCurrentCamera(); - - tmp.set(Gdx.input.getX(), Gdx.input.getY()); - routineStageWrapper.screenToLocalCoordinates(tmp); - - boolean shouldMove = routineStage.shouldAutoMove() - && (isInTopZone(tmp) || isInBottomZone(tmp) || isInLeftZone(tmp) || isInRightZone(tmp)); - - if (shouldMove) { - delayBeforeMove -= delta; - } else { - delayBeforeMove = DELAY_BEFORE_MOVE; - } - - if (delayBeforeMove < 0) { - if (isInTopZone(tmp)) { - camera.translate(0, camera.zoom * AUTO_SCROLL_SPEED * dt, 0); - } else if (isInBottomZone(tmp)) { - camera.translate(0, camera.zoom * -AUTO_SCROLL_SPEED * dt, 0); - } - - if (isInLeftZone(tmp)) { - camera.translate(camera.zoom * AUTO_SCROLL_SPEED * dt, 0, 0); - } else if (isInRightZone(tmp)) { - camera.translate(camera.zoom * -AUTO_SCROLL_SPEED * dt, 0, 0); - } - } - routineStage.act(); } - - - private boolean isInRightZone(Vector2 mouse) { - return mouse.x > 0 && mouse.x < AUTO_SCROLL_RANGE; - } - - private boolean isInLeftZone(Vector2 mouse) { - return mouse.x > routineStageWrapper.getWidth() - AUTO_SCROLL_RANGE && mouse.x < routineStageWrapper.getWidth(); - } - - private boolean isInBottomZone(Vector2 mouse) { - return mouse.y > 0 && mouse.y < AUTO_SCROLL_RANGE; - } - - private boolean isInTopZone(Vector2 mouse) { - return mouse.y > routineStageWrapper.getHeight() - AUTO_SCROLL_RANGE && mouse.y < routineStageWrapper.getHeight(); - } }; routineStageWrapper.getDropdownForWorld().setVisible(false); diff --git a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineStage.java b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineStage.java index 1723d1699..a60ba1430 100644 --- a/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineStage.java +++ b/editor/src/com/talosvfx/talos/editor/addons/scene/apps/routines/RoutineStage.java @@ -65,6 +65,7 @@ public RoutineStage (RoutineEditorApp routineEditorApp, Skin skin) { protected void initActors () { super.initActors(); nodeBoard.setTouchable(Touchable.enabled); + nodeBoard.getAutoMoveUtil().setViewportWidget(routineEditorApp.routineStageWrapper); } public void loadFrom (GameAsset asset) { diff --git a/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java b/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java index d1a395a58..25a0a8966 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/DynamicNodeStage.java @@ -22,8 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static com.talosvfx.talos.editor.utils.InputUtils.ctrlPressed; - public abstract class DynamicNodeStage extends WorkplaceStage implements EventContextProvider> { private static final Logger logger = LoggerFactory.getLogger(DynamicNodeStage.class); @@ -39,8 +37,6 @@ public abstract class DynamicNodeStage extends W public GameAsset gameAsset; public T data; - public boolean shouldAutoMove; - public DynamicNodeStage (Skin skin) { super(); this.skin = skin; @@ -235,9 +231,6 @@ public void touchUp (InputEvent event, float x, float y, int pointer, int button protected abstract void onBaseStageSelected (); protected void initActors() { -// GridRendererWrapper gridRenderer = new GridRendererWrapper(stage); -// stage.addActor(gridRenderer); - nodeBoard = new NodeBoard(skin, this); getRootActor().addActor(nodeBoard); @@ -279,7 +272,4 @@ public DynamicNodeStage getContext () { public abstract void onNodeSelectionChange (); - public boolean shouldAutoMove() { - return shouldAutoMove; - } } diff --git a/editor/src/com/talosvfx/talos/editor/nodes/EmptyWindow.java b/editor/src/com/talosvfx/talos/editor/nodes/EmptyWindow.java index 4a1150f46..5d2a921ed 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/EmptyWindow.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/EmptyWindow.java @@ -42,10 +42,6 @@ public boolean touchDown(InputEvent event, float x, float y, int pointer, int bu } }); this.addListener(new InputListener() { - float startX; - float startY; - float lastX; - float lastY; private void updateEdge(float x, float y) { float border = (float)EmptyWindow.this.resizeBorder / 2.0F; @@ -103,10 +99,10 @@ public boolean touchDown(InputEvent event, float x, float y, int pointer, int bu if (button == 0) { this.updateEdge(x, y); EmptyWindow.this.dragging = EmptyWindow.this.edge != 0; - this.startX = x; - this.startY = y; - this.lastX = x - EmptyWindow.this.getWidth(); - this.lastY = y - EmptyWindow.this.getHeight(); + touchDraggedStartX = x; + touchDraggedStartY = y; + touchDraggedLastX = x - EmptyWindow.this.getWidth(); + touchDraggedLastY = y - EmptyWindow.this.getHeight(); } return EmptyWindow.this.edge != 0 || EmptyWindow.this.isModal; @@ -118,79 +114,7 @@ public void touchUp(InputEvent event, float x, float y, int pointer, int button) public void touchDragged(InputEvent event, float x, float y, int pointer) { if (EmptyWindow.this.dragging) { - float width = EmptyWindow.this.getWidth(); - float height = EmptyWindow.this.getHeight(); - float windowX = EmptyWindow.this.getX(); - float windowY = EmptyWindow.this.getY(); - float minWidth = EmptyWindow.this.getMinWidth(); - float maxWidth = EmptyWindow.this.getMaxWidth(); - float minHeight = EmptyWindow.this.getMinHeight(); - float maxHeight = EmptyWindow.this.getMaxHeight(); - Stage stage = EmptyWindow.this.getStage(); - boolean clampPosition = stage != null && EmptyWindow.this.getParent() == stage.getRoot(); - float amountY; - if ((EmptyWindow.this.edge & 32) != 0) { - amountY = x - this.startX; - float amountYx = y - this.startY; - windowX += amountY; - windowY += amountYx; - } - - if ((EmptyWindow.this.edge & 8) != 0) { - amountY = x - this.startX; - if (width - amountY < minWidth) { - amountY = -(minWidth - width); - } - - if (clampPosition && windowX + amountY < 0.0F) { - amountY = -windowX; - } - - width -= amountY; - windowX += amountY; - } - - if ((EmptyWindow.this.edge & 4) != 0) { - amountY = y - this.startY; - if (height - amountY < minHeight) { - amountY = -(minHeight - height); - } - - if (clampPosition && windowY + amountY < 0.0F) { - amountY = -windowY; - } - - height -= amountY; - windowY += amountY; - } - - if ((EmptyWindow.this.edge & 16) != 0) { - amountY = x - this.lastX - width; - if (width + amountY < minWidth) { - amountY = minWidth - width; - } - - if (clampPosition && windowX + width + amountY > stage.getWidth()) { - amountY = stage.getWidth() - windowX - width; - } - - width += amountY; - } - - if ((EmptyWindow.this.edge & 2) != 0) { - amountY = y - this.lastY - height; - if (height + amountY < minHeight) { - amountY = minHeight - height; - } - - if (clampPosition && windowY + height + amountY > stage.getHeight()) { - amountY = stage.getHeight() - windowY - height; - } - - height += amountY; - } - - EmptyWindow.this.setBounds((float)Math.round(windowX), (float)Math.round(windowY), (float)Math.round(width), (float)Math.round(height)); + EmptyWindow.this.touchDragged(x, y); } } @@ -293,4 +217,85 @@ public float getPrefWidth() { public abstract float getTitlePrefWidth(); public abstract float getDragPadTop(); + + private float touchDraggedStartX; + private float touchDraggedStartY; + private float touchDraggedLastX; + private float touchDraggedLastY; + + public void touchDragged(float localX, float localY) { + float width = EmptyWindow.this.getWidth(); + float height = EmptyWindow.this.getHeight(); + float windowX = EmptyWindow.this.getX(); + float windowY = EmptyWindow.this.getY(); + float minWidth = EmptyWindow.this.getMinWidth(); + float maxWidth = EmptyWindow.this.getMaxWidth(); + float minHeight = EmptyWindow.this.getMinHeight(); + float maxHeight = EmptyWindow.this.getMaxHeight(); + Stage stage = EmptyWindow.this.getStage(); + boolean clampPosition = stage != null && EmptyWindow.this.getParent() == stage.getRoot(); + float amountY; + if ((EmptyWindow.this.edge & 32) != 0) { + amountY = localX - this.touchDraggedStartX; + float amountYx = localY - this.touchDraggedStartY; + windowX += amountY; + windowY += amountYx; + } + + if ((EmptyWindow.this.edge & 8) != 0) { + amountY = localX - this.touchDraggedStartX; + if (width - amountY < minWidth) { + amountY = -(minWidth - width); + } + + if (clampPosition && windowX + amountY < 0.0F) { + amountY = -windowX; + } + + width -= amountY; + windowX += amountY; + } + + if ((EmptyWindow.this.edge & 4) != 0) { + amountY = localY - this.touchDraggedStartY; + if (height - amountY < minHeight) { + amountY = -(minHeight - height); + } + + if (clampPosition && windowY + amountY < 0.0F) { + amountY = -windowY; + } + + height -= amountY; + windowY += amountY; + } + + if ((EmptyWindow.this.edge & 16) != 0) { + amountY = localX - this.touchDraggedLastX - width; + if (width + amountY < minWidth) { + amountY = minWidth - width; + } + + if (clampPosition && windowX + width + amountY > stage.getWidth()) { + amountY = stage.getWidth() - windowX - width; + } + + width += amountY; + } + + if ((EmptyWindow.this.edge & 2) != 0) { + amountY = localY - this.touchDraggedLastY - height; + if (height + amountY < minHeight) { + amountY = minHeight - height; + } + + if (clampPosition && windowY + height + amountY > stage.getHeight()) { + amountY = stage.getHeight() - windowY - height; + } + + height += amountY; + } + + EmptyWindow.this.setBounds((float)Math.round(windowX), (float)Math.round(windowY), (float)Math.round(width), (float)Math.round(height)); + } } diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java index 9a4e9f540..f2dd5ff42 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java @@ -11,14 +11,11 @@ import com.badlogic.gdx.math.*; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Group; -import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup; -import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.*; import com.badlogic.gdx.utils.reflect.ClassReflection; import com.badlogic.gdx.utils.reflect.ReflectionException; -import com.talosvfx.talos.TalosMain; import com.talosvfx.talos.editor.Curve; import com.talosvfx.talos.editor.addons.shader.nodes.ColorOutput; import com.talosvfx.talos.editor.data.DynamicNodeStageData; @@ -28,6 +25,7 @@ import com.talosvfx.talos.editor.notifications.events.dynamicnodestage.NodeDataModifiedEvent; import com.talosvfx.talos.editor.notifications.events.dynamicnodestage.NodeRemovedEvent; import com.talosvfx.talos.editor.render.Render; +import com.talosvfx.talos.editor.widgets.ui.ViewportWidget; import com.talosvfx.talos.runtime.vfx.Slot; import com.talosvfx.talos.runtime.vfx.modules.AbstractModule; import lombok.Getter; @@ -73,6 +71,9 @@ public class NodeBoard extends WidgetGroup imple private NodeConnection hoveredConnection = null; private ObjectMap nodeMap = new ObjectMap<>(); + @Getter + private final AutoMoveUtil autoMoveUtil; + public void reset () { nodeCounter = new ObjectIntMap<>(); selectedNodes.clear(); @@ -153,6 +154,9 @@ public NodeBoard (Skin skin, DynamicNodeStage nodeStage) { addActor(groupContainer); addActor(mainContainer); + + autoMoveUtil = new AutoMoveUtil(); + addActor(autoMoveUtil); } @@ -170,16 +174,13 @@ public void draw (Batch batch, float parentAlpha) { super.draw(batch, parentAlpha); } - boolean isHoldingNode; + NodeWidget holdingNode; + @Override public void act(float delta) { super.act(delta); - if (activeCurve != null || isHoldingNode) { - nodeStage.shouldAutoMove = true; - } else { - nodeStage.shouldAutoMove = false; - } + } private void drawCurves () { @@ -827,7 +828,7 @@ public void pasteFromClipboard () { } public void nodeClicked (NodeWidget node) { - isHoldingNode = true; + holdingNode = node; wasNodeDragged = null; if (selectedNodes.contains(node)) { @@ -1049,4 +1050,120 @@ public NodeWidget findNode(int uniqueId) { return nodeMap.get(uniqueId); } + + public class AutoMoveUtil extends Actor { + private static final float AUTO_SCROLL_RANGE = 100.0f; + private static final float AUTO_SCROLL_SPEED = 200.0f; + private static final float DELAY_BEFORE_MOVE = 0.3f; + private float delayBeforeMove = DELAY_BEFORE_MOVE; + + private boolean shouldAutoMove; + + private Vector2 tmp = new Vector2(); + private Vector2 tmp2 = new Vector2(); + private Vector2 tmp3 = new Vector2(); + + private ViewportWidget wrapper; + + private AutoMoveUtil () { + // only for node board use + } + + @Override + public void act(float delta) { + super.act(delta); + + if (wrapper == null) { + return; + } + + tmp.set(Gdx.input.getX(), Gdx.input.getY()); + wrapper.screenToLocalCoordinates(tmp); + + boolean shouldMove = shouldAutoMove + && (isInTopZone(tmp) || isInBottomZone(tmp) || isInLeftZone(tmp) || isInRightZone(tmp)); + + if (shouldMove) { + delayBeforeMove -= delta; + } else { + delayBeforeMove = DELAY_BEFORE_MOVE; + } + + if (activeCurve != null || holdingNode != null) { + shouldAutoMove = true; + } else { + shouldAutoMove = false; + } + + if (shouldAutoMove()) { + Vector2 displacement = autoMoveUtil.displacement(); + Camera camera = getStage().getCamera(); + camera.translate(displacement.x, displacement.y, 0); + + if (holdingNode != null) { + tmp3.set(Gdx.input.getX(), Gdx.input.getY()); + holdingNode.screenToLocalCoordinates(tmp3); + holdingNode.touchDragged(tmp3.x, tmp3.y); + } + } + } + + public boolean shouldAutoMove () { + return delayBeforeMove < 0; + } + + public Vector2 displacement () { + if (wrapper == null) { + return tmp2.setZero(); + } + + float dt = Gdx.graphics.getDeltaTime(); + + tmp.set(Gdx.input.getX(), Gdx.input.getY()); + wrapper.screenToLocalCoordinates(tmp); + + final float displacement = AUTO_SCROLL_SPEED * dt; + tmp2.setZero(); + if (autoMoveUtil.isInTopZone(tmp)) { + tmp2.set(0, displacement); + } else if (autoMoveUtil.isInBottomZone(tmp)) { + tmp2.set(0, -displacement); + } + + if (autoMoveUtil.isInLeftZone(tmp)) { + tmp2.set(-displacement, 0); + } else if (autoMoveUtil.isInRightZone(tmp)) { + tmp2.set(displacement, 0); + } + + // make displacement relative + Camera camera = NodeBoard.this.getStage().getCamera(); + if (camera instanceof OrthographicCamera) { + OrthographicCamera orthoCamera = (OrthographicCamera) camera; + tmp2.scl(orthoCamera.zoom); + } + + return tmp2; + } + + private boolean isInRightZone(Vector2 mouse) { + return mouse.x > wrapper.getWidth() - AUTO_SCROLL_RANGE && mouse.x < wrapper.getWidth(); + } + + private boolean isInLeftZone(Vector2 mouse) { + return mouse.x > 0 && mouse.x < AUTO_SCROLL_RANGE; + } + + private boolean isInBottomZone(Vector2 mouse) { + return mouse.y > 0 && mouse.y < AUTO_SCROLL_RANGE; + } + + private boolean isInTopZone(Vector2 mouse) { + return mouse.y > wrapper.getHeight() - AUTO_SCROLL_RANGE && mouse.y < wrapper.getHeight(); + } + + public void setViewportWidget(ViewportWidget stageWrapper) { + wrapper = stageWrapper; + } + } } diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java index 5fcfb6048..05b043dec 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeWidget.java @@ -35,7 +35,6 @@ public abstract class NodeWidget extends EmptyWindow implements Json.Serializabl private String hoveredSlot = null; private boolean hoveredSlotIsInput = false; private Vector2 tmp = new Vector2(); - private Vector2 tmp2 = new Vector2(); private NodeWidget lastAttachedNode; protected Array inputSlots = new Array(); @@ -171,16 +170,11 @@ public void init(Skin skin, NodeBoard nodeBoard) { addListener(new InputListener() { - Vector2 tmp = new Vector2(); - Vector2 prev = new Vector2(); - - Vector2 start = new Vector2(); - boolean hasMoved = false; public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) { - prev.set(x, y); - start.set(getX(), getY()); - NodeWidget.this.localToStageCoordinates(prev); + touchDraggedPrev.set(x, y); + touchDraggedStart.set(getX(), getY()); + NodeWidget.this.localToStageCoordinates(touchDraggedPrev); if(nodeBoard != null) { nodeBoard.nodeClicked(NodeWidget.this); } @@ -189,18 +183,7 @@ public boolean touchDown (InputEvent event, float x, float y, int pointer, int b @Override public void touchDragged(InputEvent event, float x, float y, int pointer) { - tmp.set(x, y); - NodeWidget.this.localToStageCoordinates(tmp); - super.touchDragged(event, x, y, pointer); - if(nodeBoard != null) { - nodeBoard.wrapperMovedBy(NodeWidget.this, tmp.x - prev.x, tmp.y - prev.y); - } - if (!(start.epsilonEquals(getX(), getY()))) { - hasMoved = true; - } - - prev.set(tmp); } @Override @@ -212,7 +195,7 @@ public void touchUp(InputEvent event, float x, float y, int pointer, int button) nodeBoard.nodeClickedUp(NodeWidget.this, hasMoved); } - nodeBoard.isHoldingNode = false; + nodeBoard.holdingNode = null; } event.cancel(); hasMoved = false; @@ -688,4 +671,27 @@ public Class getType () { // public Array getListOfProperties (); + private Vector2 touchDraggedPrev = new Vector2(); + private Vector2 touchDraggedStart = new Vector2(); + private boolean hasMoved = false; + + @Override + public void touchDragged(float localX, float localY) { + tmp.set(localX, localY); + NodeWidget.this.localToStageCoordinates(tmp); + + if (nodeBoard != null) { + nodeBoard.wrapperMovedBy(NodeWidget.this, tmp.x - touchDraggedPrev.x, tmp.y - touchDraggedPrev.y); + } + + if (!(touchDraggedStart.epsilonEquals(getX(), getY()))) { + hasMoved = true; + } + + touchDraggedPrev.set(tmp); + + // move others, then itself, it just works:/ + super.touchDragged(localX, localY); + } + } From 9994585d393b291f9240d3b09ad7278e2c1853d2 Mon Sep 17 00:00:00 2001 From: SenPie Date: Wed, 21 Jun 2023 15:26:15 +0400 Subject: [PATCH 4/4] smaller range --- editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java index f2dd5ff42..e5086e9e6 100644 --- a/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java +++ b/editor/src/com/talosvfx/talos/editor/nodes/NodeBoard.java @@ -1052,7 +1052,7 @@ public NodeWidget findNode(int uniqueId) { public class AutoMoveUtil extends Actor { - private static final float AUTO_SCROLL_RANGE = 100.0f; + private static final float AUTO_SCROLL_RANGE = 45.0f; private static final float AUTO_SCROLL_SPEED = 200.0f; private static final float DELAY_BEFORE_MOVE = 0.3f; private float delayBeforeMove = DELAY_BEFORE_MOVE;