/* * ****************************************************************************** * * Copyright 2015 See AUTHORS file. * * * * 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.overlap2d.plugins.ninepatch; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.Circle; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack; /** * Created by azakhary on 8/18/2015. */ public class EditingZone extends Actor { private ShapeRenderer shapeRenderer; private TextureRegion texture; private static final Color BG = new Color(43f / 255f, 43f / 255f, 43f / 255f, 1f); private static final Color GUIDE_COLOR = new Color(255f/255f, 94f/255f, 0f/255f, 0.5f); private static final Color OVER_GUIDE_COLOR = new Color(255f/255f, 173f/255f, 125f/255f, 1f); private float currZoom = 1f; private Vector2 shift = new Vector2(0, 0); private int mouseOverSplit = -1; private float[] splitPositions = new float[4]; private int[] splits = new int[4]; public interface PatchChangeListener { public void changed(int[] splits); } private PatchChangeListener listener; public EditingZone() { shapeRenderer = new ShapeRenderer(); addListener(new InputListener() { private Vector2 lastPoint; private int selectedSplit = -1; public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { selectedSplit = splitCollision(x, y); if(selectedSplit >= 0) { } else { lastPoint = new Vector2(x, y); } return true; } public void touchDragged(InputEvent event, float x, float y, int pointer) { if (selectedSplit >= 0) { if(selectedSplit == 0) { //left splits[0] = (int) ((x-shift.x-getWidth()/2f)/currZoom+texture.getRegionWidth()/2f); if(splits[0] > texture.getRegionWidth()-splits[1]) { int tmp = splits[1]; splits[1] = texture.getRegionWidth()-splits[0]; splits[0] = texture.getRegionWidth() - tmp; selectedSplit = 1; mouseOverSplit = selectedSplit; } splitUpdate(); return; } if(selectedSplit == 1) { splits[1] = -(int) ((x-shift.x-getWidth()/2f)/currZoom-texture.getRegionWidth()/2f); if(texture.getRegionWidth()-splits[1] < splits[0]) { int tmp = splits[0]; splits[0] = texture.getRegionWidth() - splits[1]; splits[1] = texture.getRegionWidth() - tmp; selectedSplit = 0; mouseOverSplit = selectedSplit; } splitUpdate(); return; } if(selectedSplit == 2) { // top splits[2] = -(int) ((y-shift.y-getHeight()/2f)/currZoom-texture.getRegionHeight()/2f); if(texture.getRegionHeight()-splits[2] < splits[3]) { int tmp = splits[2]; splits[2] = texture.getRegionHeight()-splits[3]; splits[3] = texture.getRegionHeight()-tmp; selectedSplit = 3; mouseOverSplit = selectedSplit; } splitUpdate(); return; } if(selectedSplit == 3) { splits[3] = (int) ((y-shift.y-getHeight()/2f)/currZoom+texture.getRegionHeight()/2f); if(splits[3] > texture.getRegionHeight()-splits[2]) { int tmp = splits[3]; splits[3] = texture.getRegionHeight()-splits[2]; splits[2] = texture.getRegionHeight()-tmp; selectedSplit = 2; mouseOverSplit = selectedSplit; } splitUpdate(); return; } } else { Vector2 diff = new Vector2(x - lastPoint.x, y - lastPoint.y); shiftBy(diff); lastPoint = new Vector2(x, y); } } public void touchUp(InputEvent event, float x, float y, int pointer, int button) { selectedSplit = -1; if(listener != null) { listener.changed(splits.clone()); } } public boolean mouseMoved(InputEvent event, float x, float y) { mouseOverSplit = splitCollision(x, y); return false; } }); } public void setListener(PatchChangeListener listener) { this.listener = listener; } public void splitUpdate() { if(splits[0] < 0) splits[0] = 0; if(splits[1] < 0) splits[1] = 0; if(splits[2] < 0) splits[2] = 0; if(splits[3] < 0) splits[3] = 0; } public int[] getSplits() { return splits.clone(); } public void setTexture(TextureRegion texture) { this.texture = texture; splits[0] = ((TextureAtlas.AtlasRegion)texture).splits[0]; splits[1] = ((TextureAtlas.AtlasRegion)texture).splits[1]; splits[2] = ((TextureAtlas.AtlasRegion)texture).splits[2]; splits[3] = ((TextureAtlas.AtlasRegion)texture).splits[3]; } @Override public void draw (Batch batch, float parentAlpha) { Rectangle scissors = new Rectangle(); Rectangle clipBounds = new Rectangle(getX(),getY(),getWidth(),getHeight()); ScissorStack.calculateScissors(getStage().getCamera(), batch.getTransformMatrix(), clipBounds, scissors); ScissorStack.pushScissors(scissors); drawBg(batch, parentAlpha); batch.draw(texture, getX() + getWidth() / 2 - texture.getRegionWidth() / 2 + shift.x, getY() + getHeight() / 2 - texture.getRegionHeight() / 2 + shift.y, texture.getRegionWidth() / 2f, texture.getRegionHeight() / 2f, texture.getRegionWidth(), texture.getRegionHeight(), currZoom, currZoom, 0); drawSplits(batch, parentAlpha); batch.flush(); ScissorStack.popScissors(); } public void drawBg(Batch batch, float parentAlpha) { batch.end(); Gdx.gl.glLineWidth(1.0f); Gdx.gl.glEnable(GL20.GL_BLEND); Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); shapeRenderer.setProjectionMatrix(getStage().getCamera().combined); Matrix4 matrix = batch.getTransformMatrix(); shapeRenderer.setTransformMatrix(matrix); shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); BG.a = parentAlpha; shapeRenderer.setColor(BG); shapeRenderer.rect(getX(), getY(), getWidth(), getHeight()); shapeRenderer.end(); Gdx.gl.glDisable(GL20.GL_BLEND); batch.begin(); batch.setColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a * parentAlpha); } public void drawSplits(Batch batch, float parentAlpha) { batch.end(); Gdx.gl.glLineWidth(1.0f); Gdx.gl.glEnable(GL20.GL_BLEND); Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA); shapeRenderer.setProjectionMatrix(getStage().getCamera().combined); Matrix4 matrix = batch.getTransformMatrix(); shapeRenderer.setTransformMatrix(matrix); shapeRenderer.begin(ShapeRenderer.ShapeType.Line); // left, right, top , bottom Color guideColor = new Color(GUIDE_COLOR); guideColor.a*=parentAlpha; Color overColor = new Color(OVER_GUIDE_COLOR); overColor.a*=parentAlpha; splitPositions[0] = shift.x + getWidth() / 2f + (-texture.getRegionWidth() / 2f + splits[0]) * currZoom; splitPositions[1] = shift.x + getWidth() / 2f + (texture.getRegionWidth() / 2f - splits[1]) * currZoom; splitPositions[2] = shift.y + getHeight()/2f + (texture.getRegionHeight()/2 - splits[2])*currZoom; splitPositions[3] = shift.y + getHeight() / 2f + (-texture.getRegionHeight() / 2 + splits[3]) * currZoom; if(mouseOverSplit == 0) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); shapeRenderer.line(getX() + splitPositions[0], getY(), getX() + splitPositions[0], getY() + getHeight()); if(mouseOverSplit == 1) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); shapeRenderer.line(getX() + splitPositions[1], getY(), getX() + splitPositions[1], getY() + getHeight()); if(mouseOverSplit == 2) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); shapeRenderer.line(getX(), getY() + splitPositions[2], getX() + getWidth(), getY() + splitPositions[2]); if(mouseOverSplit == 3) shapeRenderer.setColor(overColor); else shapeRenderer.setColor(guideColor); shapeRenderer.line(getX(), getY() + splitPositions[3], getX() + getWidth(), getY() + splitPositions[3]); shapeRenderer.end(); Gdx.gl.glDisable(GL20.GL_BLEND); batch.begin(); batch.setColor(Color.WHITE.r, Color.WHITE.g, Color.WHITE.b, Color.WHITE.a * parentAlpha); } public void zoomBy(int amount) { float defaultSize = 1.0f - amount*0.12f; currZoom*=defaultSize; } public void shiftBy(Vector2 diff) { shift.add(diff); } public int splitCollision(float x, float y) { Circle touchCircle = new Circle(); touchCircle.radius = 5f; touchCircle.setPosition(x, y); if(touchCircle.contains(splitPositions[0], touchCircle.y)) { return 0; } if(touchCircle.contains(splitPositions[1], touchCircle.y)) { return 1; } if(touchCircle.contains(touchCircle.x, splitPositions[2])) { return 2; } if(touchCircle.contains(touchCircle.x, splitPositions[3])) { return 3; } return -1; } }