/*******************************************************************************
* Copyright 2014 Rafael Garcia Moreno.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.bladecoder.engineeditor.scneditor;
import java.io.IOException;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.math.Polygon;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.UIUtils;
import com.bladecoder.engine.model.AnchorActor;
import com.bladecoder.engine.model.BaseActor;
import com.bladecoder.engine.model.InteractiveActor;
import com.bladecoder.engine.model.Scene;
import com.bladecoder.engine.model.SpriteActor;
import com.bladecoder.engine.util.PolygonUtils;
import com.bladecoder.engineeditor.Ctx;
import com.bladecoder.engineeditor.common.EditorLogger;
import com.bladecoder.engineeditor.common.Message;
import com.bladecoder.engineeditor.model.Project;
import com.bladecoder.engineeditor.undo.UndoDeleteActor;
import com.bladecoder.engineeditor.undo.UndoPosition;
import com.bladecoder.engineeditor.undo.UndoWalkZonePosition;
public class ScnWidgetInputListener extends ClickListener {
private final ScnWidget scnWidget;
private static enum DraggingModes {
NONE, DRAGGING_ACTOR, DRAGGING_BBOX_POINT, DRAGGING_WALKZONE, DRAGGING_WALKZONE_POINT, DRAGGING_MARKER_0, DRAGGING_MARKER_100, DRAGGING_ORIGIN
};
private DraggingModes draggingMode = DraggingModes.NONE;
private BaseActor selActor = null;
private Vector2 org = new Vector2();
private Vector2 undoOrg = new Vector2();
private int vertIndex;
public ScnWidgetInputListener(ScnWidget w) {
this.scnWidget = w;
}
@Override
public void clicked(InputEvent event, float x, float y) {
Scene scn = scnWidget.getScene();
if (scn == null)
return;
Vector2 p = new Vector2(Gdx.input.getX(), Gdx.input.getY());
scnWidget.screenToWorldCoords(p);
// DOUBLE CLICK TO CREATE OR DELETE POINTS
if (getTapCount() == 2) {
// Check WALKZONE
if (scn.getPolygonalNavGraph() != null && scnWidget.getShowWalkZone()) {
Polygon poly = scn.getPolygonalNavGraph().getWalkZone();
if (UIUtils.ctrl()) {
// Delete the point if selected
boolean deleted = PolygonUtils.deletePoint(poly, p.x, p.y, CanvasDrawer.CORNER_DIST);
if (deleted) {
Ctx.project.setModified();
return;
}
} else {
boolean created = PolygonUtils.addClampPointIfTolerance(poly, p.x, p.y, CanvasDrawer.CORNER_DIST);
if (created) {
Ctx.project.setModified();
return;
}
}
}
if (scnWidget.getSelectedActor() != null) {
Polygon poly = scnWidget.getSelectedActor().getBBox();
if ((!(scnWidget.getSelectedActor() instanceof SpriteActor)
|| !((SpriteActor) scnWidget.getSelectedActor()).isBboxFromRenderer()) &&
!(scnWidget.getSelectedActor() instanceof AnchorActor)
) {
if (UIUtils.ctrl()) {
// Delete the point if selected
boolean deleted = PolygonUtils.deletePoint(poly, p.x, p.y, CanvasDrawer.CORNER_DIST);
if (deleted) {
Ctx.project.setModified();
return;
}
} else {
boolean created = PolygonUtils.addClampPointIfTolerance(poly, p.x, p.y,
CanvasDrawer.CORNER_DIST);
if (created) {
Ctx.project.setModified();
return;
}
}
}
}
}
}
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
super.touchDown(event, x, y, pointer, button);
// EditorLogger.debug("Touch Down - X: " + x + " Y: " + y);
Scene scn = scnWidget.getScene();
if (scn == null)
return false;
Vector2 p = new Vector2(Gdx.input.getX(), Gdx.input.getY());
scnWidget.screenToWorldCoords(p);
org.set(p);
if (button == Buttons.LEFT) {
selActor = scnWidget.getSelectedActor();
if (scn.getPolygonalNavGraph() != null && scnWidget.getShowWalkZone()) { // Check
// WALKZONE
// CHECK WALKZONE VERTEXS
Polygon wzPoly = scn.getPolygonalNavGraph().getWalkZone();
float verts[] = wzPoly.getTransformedVertices();
for (int i = 0; i < verts.length; i += 2) {
if (p.dst(verts[i], verts[i + 1]) < CanvasDrawer.CORNER_DIST) {
draggingMode = DraggingModes.DRAGGING_WALKZONE_POINT;
vertIndex = i;
return true;
}
}
// CHECK FOR WALKZONE DRAGGING
if (wzPoly.contains(p.x, p.y)) {
draggingMode = DraggingModes.DRAGGING_WALKZONE;
undoOrg.set(wzPoly.getX(), wzPoly.getY());
return true;
}
}
// SELACTOR ORIGIN DRAGGING
if (selActor != null && selActor instanceof InteractiveActor) {
Vector2 refPoint = ((InteractiveActor) selActor).getRefPoint();
float orgX = selActor.getX() + refPoint.x;
float orgY = selActor.getY() + refPoint.y;
float dst = Vector2.dst(p.x, p.y, orgX, orgY);
if (dst < Scene.ANCHOR_RADIUS) {
draggingMode = DraggingModes.DRAGGING_ORIGIN;
return true;
}
}
// SELACTOR VERTEXs DRAGGING
if (selActor != null
&& (!(selActor instanceof SpriteActor) || !((SpriteActor) selActor).isBboxFromRenderer()) &&
!(scnWidget.getSelectedActor() instanceof AnchorActor)) {
Polygon bbox = selActor.getBBox();
float verts[] = bbox.getTransformedVertices();
for (int i = 0; i < verts.length; i += 2) {
if (p.dst(verts[i], verts[i + 1]) < CanvasDrawer.CORNER_DIST) {
draggingMode = DraggingModes.DRAGGING_BBOX_POINT;
vertIndex = i;
return true;
}
}
}
BaseActor a = scn.getActorAt(p.x, p.y); // CHECK FOR ACTORS
if (a != null && a != selActor) {
selActor = a;
BaseActor da = Ctx.project.getActor(selActor.getId());
Ctx.project.setSelectedActor(da);
return true;
}
if (a != null) {
draggingMode = DraggingModes.DRAGGING_ACTOR;
undoOrg.set(selActor.getX(), selActor.getY());
return true;
}
// CHECK FOR DRAGGING DEPTH MARKERS
Vector2 depthVector = scnWidget.getScene().getDepthVector();
if (depthVector != null) {
p.set(0, depthVector.x);
scnWidget.worldToScreenCoords(p);
if (Vector2.dst(p.x - 40, p.y, x, y) < 50) {
draggingMode = DraggingModes.DRAGGING_MARKER_0;
return true;
}
p.set(0, depthVector.y);
scnWidget.worldToScreenCoords(p);
if (Vector2.dst(p.x - 40, p.y, x, y) < 50) {
draggingMode = DraggingModes.DRAGGING_MARKER_100;
return true;
}
}
}
return true;
}
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
// EditorLogger.debug("Touch Dragged - X: " + Gdx.input.getX() + " Y: "
// + Gdx.input.getY());
super.touchDragged(event, x, y, pointer);
if (Gdx.input.isButtonPressed(Buttons.LEFT)) {
Scene scn = scnWidget.getScene();
if (scn == null)
return;
Vector2 d = new Vector2(Gdx.input.getX(), Gdx.input.getY());
scnWidget.screenToWorldCoords(d);
d.sub(org);
org.add(d);
if (draggingMode == DraggingModes.DRAGGING_ACTOR) {
selActor.setPosition(selActor.getX()+ d.x, selActor.getY() + d.y);
Ctx.project.setModified(this, Project.POSITION_PROPERTY, null, selActor);
} else if (draggingMode == DraggingModes.DRAGGING_ORIGIN) {
Vector2 refPoint = ((InteractiveActor)selActor).getRefPoint();
refPoint.add(d.x, d.y);
Ctx.project.setModified();
} else if (draggingMode == DraggingModes.DRAGGING_BBOX_POINT) {
Polygon poly = selActor.getBBox();
float verts[] = poly.getVertices();
verts[vertIndex] += d.x;
verts[vertIndex + 1] += d.y;
poly.dirty();
Ctx.project.setModified();
} else if (draggingMode == DraggingModes.DRAGGING_WALKZONE_POINT) {
Polygon poly = scn.getPolygonalNavGraph().getWalkZone();
float verts[] = poly.getVertices();
verts[vertIndex] += d.x;
verts[vertIndex + 1] += d.y;
poly.dirty();
Ctx.project.setModified();
} else if (draggingMode == DraggingModes.DRAGGING_WALKZONE) {
Polygon poly = scn.getPolygonalNavGraph().getWalkZone();
poly.translate(d.x, d.y);
} else if (draggingMode == DraggingModes.DRAGGING_MARKER_0) {
Vector2 depthVector = scnWidget.getScene().getDepthVector();
depthVector.x += d.y;
Ctx.project.setModified();
updateFakeDepth();
} else if (draggingMode == DraggingModes.DRAGGING_MARKER_100) {
Vector2 depthVector = scnWidget.getScene().getDepthVector();
depthVector.y += d.y;
Ctx.project.setModified();
updateFakeDepth();
}
} else if (Gdx.input.isButtonPressed(Buttons.RIGHT) || Gdx.input.isButtonPressed(Buttons.MIDDLE)) {
Vector2 p = new Vector2(Gdx.input.getX(), Gdx.input.getY());
scnWidget.screenToWorldCoords(p);
p.sub(org);
scnWidget.translate(p);
}
}
private void updateFakeDepth() {
Scene scn = scnWidget.getScene();
for (BaseActor a : scn.getActors().values()) {
if (a instanceof SpriteActor) {
a.setPosition(a.getX(), a.getY());
}
}
}
@Override
public boolean scrolled(InputEvent event, float x, float y, int amount) {
super.scrolled(event, x, y, amount);
// EditorLogger.debug("SCROLLED - X: " + x + " Y: " + y);
scnWidget.zoom(amount);
return true;
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// EditorLogger.debug("Touch Up - X: " + x + " Y: " + y);
if (draggingMode == DraggingModes.DRAGGING_ACTOR) {
Ctx.project.getUndoStack().add(new UndoPosition(selActor, new Vector2(undoOrg)));
} else if (draggingMode == DraggingModes.DRAGGING_WALKZONE) {
Ctx.project.getUndoStack().add(new UndoWalkZonePosition(scnWidget.getScene().getPolygonalNavGraph().getWalkZone(), new Vector2(undoOrg)));
}
draggingMode = DraggingModes.NONE;
return;
}
@Override
public boolean keyUp (InputEvent event, int keycode) {
switch (keycode) {
case Keys.UP:
case Keys.DOWN:
case Keys.LEFT:
case Keys.RIGHT:
Ctx.project.getUndoStack().add(new UndoPosition(selActor, new Vector2(undoOrg)));
}
return false;
}
@Override
public boolean keyDown(InputEvent event, int keycode) {
super.keyDown(event, keycode);
Polygon p = null;
if (scnWidget.getStage() == null || scnWidget.getStage().getKeyboardFocus() != scnWidget) return false;
switch (keycode) {
case Keys.ENTER:
break;
case Keys.BACKSPACE:
break;
case Keys.Z:
if (UIUtils.ctrl()) {
Ctx.project.getUndoStack().undo();
}
break;
case Keys.FORWARD_DEL:
BaseActor a = Ctx.project.getSelectedActor();
if( a == null)
return false;
Ctx.project.getUndoStack().add(new UndoDeleteActor(Ctx.project.getSelectedScene(), a));
Ctx.project.getSelectedScene().removeActor(a);
Ctx.project.setModified(this, Project.NOTIFY_ELEMENT_DELETED, null, a);
break;
case Keys.S:
if (UIUtils.ctrl()) {
try {
Ctx.project.saveProject();
} catch (IOException e1) {
String msg = "Something went wrong while saving the actor.\n\n"
+ e1.getClass().getSimpleName()
+ " - "
+ e1.getMessage();
Message.showMsgDialog(scnWidget.getStage(), "Error", msg);
EditorLogger.printStackTrace(e1);
}
}
break;
case Keys.UP:
case Keys.DOWN:
case Keys.LEFT:
case Keys.RIGHT:
selActor = scnWidget.getSelectedActor();
p = selActor.getBBox();
undoOrg.set(p.getX(), p.getY());
Ctx.project.setModified(this, Project.POSITION_PROPERTY, null, selActor);
break;
}
return false;
}
@Override
public void enter(InputEvent event, float x, float y, int pointer, com.badlogic.gdx.scenes.scene2d.Actor fromActor) {
super.enter(event, x, y, pointer, fromActor);
// EditorLogger.debug("ENTER - X: " + x + " Y: " + y);
scnWidget.getStage().setScrollFocus(scnWidget);
}
}