package com.vitco.core.modes.tools; import com.threed.jpct.SimpleVector; import com.vitco.core.container.DrawContainer; import com.vitco.core.data.container.Voxel; import com.vitco.settings.VitcoSettings; import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.LinkedList; /** * Defines the basic select tool. */ public class SelectTool extends AbstractVoxelTool { // constructor public SelectTool(DrawContainer container, int side) { super(container, side); // disable the background camera // NOTE: this can cause the highlighted parameter to be null in // the press and shiftPress functions useBackgroundCamera(false); } // -------------------- @Override protected void key() { container.setCursor(Cursor.getDefaultCursor()); useBackgroundCamera(isShiftDown()); } // -------------------- private void doSelect(Point c1, Point c2, boolean select) { Point start = new Point( Math.min(c1.x, c2.x), Math.min(c1.y, c2.y) ); Point stop = new Point( Math.max(c1.x, c2.x), Math.max(c1.y, c2.y) ); java.util.List<Integer> searchResult = new LinkedList<Integer>(); if (!start.equals(stop)) { Voxel[] voxels; switch (side) { case -1: voxels = data.getVisibleLayerVoxel(); break; case 2: voxels = data.getVoxelsYZ(container.getPlane()); break; case 1: voxels = data.getVoxelsXZ(container.getPlane()); break; case 0: voxels = data.getVoxelsXY(container.getPlane()); break; default: voxels = new Voxel[0]; break; } // use all voxles for (Voxel voxel : voxels) { SimpleVector vec = container.convert3D2D(new SimpleVector( voxel.x * VitcoSettings.VOXEL_SIZE, voxel.y * VitcoSettings.VOXEL_SIZE, voxel.z * VitcoSettings.VOXEL_SIZE)); if (vec != null) { if (vec.x >= start.x && vec.x <= stop.x && vec.y >= start.y && vec.y <= stop.y) { searchResult.add(voxel.id); } } } } // execute the select Integer[] toSet = new Integer[searchResult.size()]; searchResult.toArray(toSet); if (toSet.length > 0) { // reset selection shift data.setVoxelSelectionShift(0,0,0); // select voxels data.massSetVoxelSelected(toSet, select); } } // -------------------------- // simple drawing // -------------------------- // the points of a drag private Point start = null; private Point stop = null; // shifting selection, // if neq null user is currently dragging the selection private int[] currentSelectionShift = null; // the reference click voxel (in 3D) private SimpleVector dragStartReferencePos = null; // the "real" drag position (applying shifting) private SimpleVector dragStart = null; private SimpleVector dragStop = null; // true if mouse3 was pressed when drag started private boolean mouse3down = false; @Override public void move(MouseEvent e) { data.highlightVoxel(null); short[] hitVoxel = container.getShiftedCollisionVoxel(e.getPoint()); if (hitVoxel != null) { container.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); } else { container.setCursor(Cursor.getDefaultCursor()); } } @Override public void press(MouseEvent e) { start = e.getPoint(); mouse3down = isMouse3Down(); // check if we hit something selected short[] hitVoxel = container.getShiftedCollisionVoxel(e.getPoint()); if (hitVoxel != null) { // start dragging selection dragStartReferencePos = new SimpleVector(hitVoxel[0], hitVoxel[1], hitVoxel[2]); dragStart = container.convert2D3D(e.getX(), e.getY(), dragStartReferencePos); dragStop = null; currentSelectionShift = data.getVoxelSelectionShift(); } else { currentSelectionShift = null; } } @Override protected void release(MouseEvent e) { stop = e.getPoint(); // use the selected rectangle if this was not a drag that moved // the selection (1) or if this was a single position // click, i.e. no drag (2) if (currentSelectionShift == null || dragStop == null) { // do the selection doSelect(start, stop, !mouse3down); } // hide the rectangle data.setSelectionRect(null); } @Override public void drag(MouseEvent e) { stop = e.getPoint(); // check if we're dragging selection (1) or are outlining a selection (2) if (currentSelectionShift != null) { // get reference position dragStop = container.convert2D3D(e.getX(), e.getY(), dragStartReferencePos); // update position of what we dragged to data.setVoxelSelectionShift( Math.round(currentSelectionShift[0] - (dragStop.x - dragStart.x)/VitcoSettings.VOXEL_SIZE), Math.round(currentSelectionShift[1] - (dragStop.y - dragStart.y)/VitcoSettings.VOXEL_SIZE), Math.round(currentSelectionShift[2] - (dragStop.z - dragStart.z)/VitcoSettings.VOXEL_SIZE)); } else { // update selection outline rectangle int x1 = Math.min(start.x, stop.x); int y1 = Math.min(start.y, stop.y); int x2 = Math.max(start.x, stop.x); int y2 = Math.max(start.y, stop.y); data.setSelectionRect(new Rectangle(x1, y1, x2 - x1, y2 - y1)); } } @Override protected void click(MouseEvent e) {} // executed if no drag occurred @Override protected void singleClick(MouseEvent e) { // execute single selection click int[] pos = getVoxelSimple(e.getPoint()); if (pos != null) { Voxel voxel = data.searchVoxel(pos, false); if (voxel != null) { //todo: fix that this can cause the wrong cursor to appear data.setVoxelSelected(voxel.id, !mouse3down); } } } // -------------------------- // shift drawing // -------------------------- // last active voxel position private int[] initialVoxelPos = null; private int[] lastVoxelPos = null; // previewRect color private final int[] selectDashColor = new int[]{Color.BLACK.getRGB(), Color.WHITE.getRGB()}; // -------------------------- @Override protected void shiftMove(MouseEvent e) { data.highlightVoxel(getVoxel(e.getPoint(), false)); } @Override protected void shiftPress(MouseEvent e) { int[] highlighted = data.getHighlightedVoxel(); // store state mouse3down = isMouse3Down(); // memo selection outline initialVoxelPos = highlighted; lastVoxelPos = highlighted; if (highlighted != null) { // set initial preview rect data.setOutlineBox("preview", new int[][]{initialVoxelPos, lastVoxelPos, selectDashColor}.clone()); } // no voxel selection data.highlightVoxel(null); } @Override protected void shiftRelease(MouseEvent e) { // use the voxels to select the new color if (lastVoxelPos != null && initialVoxelPos != null) { ArrayList<Integer> list = new ArrayList<Integer>(); for (int x = Math.min(initialVoxelPos[0], lastVoxelPos[0]), maxx = Math.max(initialVoxelPos[0], lastVoxelPos[0]); x <= maxx; x++ ) { for (int y = Math.min(initialVoxelPos[1], lastVoxelPos[1]), maxy = Math.max(initialVoxelPos[1], lastVoxelPos[1]); y <= maxy; y++ ) { for (int z = Math.min(initialVoxelPos[2], lastVoxelPos[2]), maxz = Math.max(initialVoxelPos[2], lastVoxelPos[2]); z <= maxz; z++ ) { // depending on mouse3 state we only search current layer Voxel voxel = data.searchVoxel(new int[]{x,y,z}, false); if (voxel != null && voxel.getTexture() == null) { // collect the voxels list.add(voxel.id); } } } } // set the selection // execute the select Integer[] toSet = new Integer[list.size()]; list.toArray(toSet); if (toSet.length > 0) { // reset selection shift data.setVoxelSelectionShift(0,0,0); // select voxels data.massSetVoxelSelected(toSet, !mouse3down); } } // hide preview data.setOutlineBox("preview", null); } @Override protected void shiftDrag(MouseEvent e) { lastVoxelPos = getVoxel(e.getPoint(), false); // display preview if (lastVoxelPos != null && initialVoxelPos != null) { data.setOutlineBox("preview", new int[][]{initialVoxelPos, lastVoxelPos, selectDashColor}); } else { data.setOutlineBox("preview", null); } } @Override protected void shiftClick(MouseEvent e) {} @Override protected void singleShiftClick(MouseEvent e) {} }