Files
Mindustry/core/src/mindustry/editor/MapView.java

349 lines
11 KiB
Java

package mindustry.editor;
import arc.Core;
import arc.graphics.Color;
import arc.graphics.g2d.*;
import arc.input.GestureDetector;
import arc.input.GestureDetector.GestureListener;
import arc.input.KeyCode;
import arc.math.Mathf;
import arc.math.geom.*;
import arc.scene.Element;
import arc.scene.event.*;
import arc.scene.ui.TextField;
import arc.scene.ui.layout.Scl;
import arc.util.*;
import mindustry.graphics.Pal;
import mindustry.input.Binding;
import mindustry.ui.GridImage;
import static mindustry.Vars.mobile;
import static mindustry.Vars.ui;
public class MapView extends Element implements GestureListener{
private MapEditor editor;
EditorTool tool = EditorTool.pencil;
private float offsetx, offsety;
private float zoom = 1f;
private boolean grid = false;
private GridImage image = new GridImage(0, 0);
private Vec2 vec = new Vec2();
private Rect rect = new Rect();
private Vec2[][] brushPolygons = new Vec2[MapEditor.brushSizes.length][0];
boolean drawing;
int lastx, lasty;
int startx, starty;
float mousex, mousey;
EditorTool lastTool;
public MapView(MapEditor editor){
this.editor = editor;
for(int i = 0; i < MapEditor.brushSizes.length; i++){
float size = MapEditor.brushSizes[i];
brushPolygons[i] = Geometry.pixelCircle(size, (index, x, y) -> Mathf.dst(x, y, index, index) <= index - 0.5f);
}
Core.input.getInputProcessors().insert(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
this.touchable = Touchable.enabled;
Point2 firstTouch = new Point2();
addListener(new InputListener(){
@Override
public boolean mouseMoved(InputEvent event, float x, float y){
mousex = x;
mousey = y;
requestScroll();
return false;
}
@Override
public void enter(InputEvent event, float x, float y, int pointer, Element fromActor){
requestScroll();
}
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
if(pointer != 0){
return false;
}
if(!mobile && button != KeyCode.mouseLeft && button != KeyCode.mouseMiddle && button != KeyCode.mouseRight){
return true;
}
if(button == KeyCode.mouseRight){
lastTool = tool;
tool = EditorTool.eraser;
}
if(button == KeyCode.mouseMiddle){
lastTool = tool;
tool = EditorTool.zoom;
}
mousex = x;
mousey = y;
Point2 p = project(x, y);
lastx = p.x;
lasty = p.y;
startx = p.x;
starty = p.y;
tool.touched(editor, p.x, p.y);
firstTouch.set(p);
if(tool.edit){
ui.editor.resetSaved();
}
drawing = true;
return true;
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
if(!mobile && button != KeyCode.mouseLeft && button != KeyCode.mouseMiddle && button != KeyCode.mouseRight){
return;
}
drawing = false;
Point2 p = project(x, y);
if(tool == EditorTool.line){
ui.editor.resetSaved();
tool.touchedLine(editor, startx, starty, p.x, p.y);
}
editor.flushOp();
if((button == KeyCode.mouseMiddle || button == KeyCode.mouseRight) && lastTool != null){
tool = lastTool;
lastTool = null;
}
}
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer){
mousex = x;
mousey = y;
Point2 p = project(x, y);
if(drawing && tool.draggable && !(p.x == lastx && p.y == lasty)){
ui.editor.resetSaved();
Bresenham2.line(lastx, lasty, p.x, p.y, (cx, cy) -> tool.touched(editor, cx, cy));
}
if(tool == EditorTool.line && tool.mode == 1){
if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){
lastx = p.x;
lasty = firstTouch.y;
}else{
lastx = firstTouch.x;
lasty = p.y;
}
}else{
lastx = p.x;
lasty = p.y;
}
}
});
}
public EditorTool getTool(){
return tool;
}
public void setTool(EditorTool tool){
this.tool = tool;
}
public boolean isGrid(){
return grid;
}
public void setGrid(boolean grid){
this.grid = grid;
}
@Override
public void act(float delta){
super.act(delta);
if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) && !Core.input.keyDown(KeyCode.controlLeft)){
float ax = Core.input.axis(Binding.move_x);
float ay = Core.input.axis(Binding.move_y);
offsetx -= ax * 15f / zoom;
offsety -= ay * 15f / zoom;
}
if(Core.input.keyTap(KeyCode.shiftLeft)){
lastTool = tool;
tool = EditorTool.pick;
}
if(Core.input.keyRelease(KeyCode.shiftLeft) && lastTool != null){
tool = lastTool;
lastTool = null;
}
if(Core.scene.getScrollFocus() != this) return;
zoom += Core.input.axis(KeyCode.scroll) / 10f * zoom;
clampZoom();
}
private void clampZoom(){
zoom = Mathf.clamp(zoom, 0.2f, 20f);
}
Point2 project(float x, float y){
float ratio = 1f / ((float)editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.width();
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.height();
if(editor.drawBlock.size % 2 == 0 && tool != EditorTool.eraser){
return Tmp.p1.set((int)(x - 0.5f), (int)(y - 0.5f));
}else{
return Tmp.p1.set((int)x, (int)y);
}
}
private Vec2 unproject(int x, int y){
float ratio = 1f / ((float)editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
float px = ((float)x / editor.width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
float py = ((float)(y) / editor.height()) * sclheight
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
return vec.set(px, py);
}
@Override
public void draw(){
float ratio = 1f / ((float)editor.width() / editor.height());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
float centerx = x + width / 2 + offsetx * zoom;
float centery = y + height / 2 + offsety * zoom;
image.setImageSize(editor.width(), editor.height());
if(!ScissorStack.push(rect.set(x, y, width, height))){
return;
}
Draw.color(Pal.remove);
Lines.stroke(2f);
Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2);
editor.renderer().draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
Draw.reset();
if(grid){
Draw.color(Color.gray);
image.setBounds(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
image.draw();
Draw.color();
}
int index = 0;
for(int i = 0; i < MapEditor.brushSizes.length; i++){
if(editor.brushSize == MapEditor.brushSizes[i]){
index = i;
break;
}
}
float scaling = zoom * Math.min(width, height) / editor.width();
Draw.color(Pal.accent);
Lines.stroke(Scl.scl(2f));
if((!editor.drawBlock.isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
if(tool == EditorTool.line && drawing){
Vec2 v1 = unproject(startx, starty).add(x, y);
float sx = v1.x, sy = v1.y;
Vec2 v2 = unproject(lastx, lasty).add(x, y);
Lines.poly(brushPolygons[index], sx, sy, scaling);
Lines.poly(brushPolygons[index], v2.x, v2.y, scaling);
}
if((tool.edit || (tool == EditorTool.line && !drawing)) && (!mobile || drawing)){
Point2 p = project(mousex, mousey);
Vec2 v = unproject(p.x, p.y).add(x, y);
//pencil square outline
if(tool == EditorTool.pencil && tool.mode == 1){
Lines.square(v.x + scaling/2f, v.y + scaling/2f, scaling * (editor.brushSize + 0.5f));
}else{
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
}
}
}else{
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
Point2 p = project(mousex, mousey);
Vec2 v = unproject(p.x, p.y).add(x, y);
float offset = (editor.drawBlock.size % 2 == 0 ? scaling / 2f : 0f);
Lines.square(
v.x + scaling / 2f + offset,
v.y + scaling / 2f + offset,
scaling * editor.drawBlock.size / 2f);
}
}
Draw.color(Pal.accent);
Lines.stroke(Scl.scl(3f));
Lines.rect(x, y, width, height);
Draw.reset();
ScissorStack.pop();
}
private boolean active(){
return Core.scene.getKeyboardFocus() != null
&& Core.scene.getKeyboardFocus().isDescendantOf(ui.editor)
&& ui.editor.isShown() && tool == EditorTool.zoom &&
Core.scene.hit(Core.input.mouse().x, Core.input.mouse().y, true) == this;
}
@Override
public boolean pan(float x, float y, float deltaX, float deltaY){
if(!active()) return false;
offsetx += deltaX / zoom;
offsety += deltaY / zoom;
return false;
}
@Override
public boolean zoom(float initialDistance, float distance){
if(!active()) return false;
float nzoom = distance - initialDistance;
zoom += nzoom / 10000f / Scl.scl(1f) * zoom;
clampZoom();
return false;
}
@Override
public boolean pinch(Vec2 initialPointer1, Vec2 initialPointer2, Vec2 pointer1, Vec2 pointer2){
return false;
}
@Override
public void pinchStop(){
}
}