def __init__(self, editorSession, *args, **kwargs): super(MoveTool, self).__init__(editorSession, *args, **kwargs) self.overlayNode = scenenode.Node("moveOverlay") self._currentImport = None self._currentImportNode = None self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.copyOptionsWidget = QtGui.QGroupBox(self.tr("Options")) self.copyAirCheckbox = QtGui.QCheckBox(self.tr("Copy Air")) self.copyOptionsWidget.setLayout(Column(self.copyAirCheckbox)) confirmButton = QtGui.QPushButton( "Confirm") # xxxx should be in worldview confirmButton.clicked.connect(self.confirmImport) self.toolWidget.setLayout( Column(self.pointInput, self.rotationInput, self.copyOptionsWidget, confirmButton, None))
def __init__(self, editorSession, *args, **kwargs): super(MoveTool, self).__init__(editorSession, *args, **kwargs) self.overlayNode = scenenode.Node("moveOverlay") self._currentImport = None self._currentImportNode = None self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.copyOptionsWidget = QtGui.QGroupBox(self.tr("Options")) self.copyAirCheckbox = QtGui.QCheckBox(self.tr("Copy Air")) self.copyOptionsWidget.setLayout(Column(self.copyAirCheckbox)) confirmButton = QtGui.QPushButton("Confirm") # xxxx should be in worldview confirmButton.clicked.connect(self.confirmImport) self.toolWidget.setLayout(Column(self.pointInput, self.rotationInput, self.copyOptionsWidget, confirmButton, None))
def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.pendingClones = [] self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node("cloneOverlay") self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.scaleInput = ScaleWidget() self.scaleInput.scaleChanged.connect(self.scaleChanged) confirmButton = QtGui.QPushButton(self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=10000, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.rotateRepeatsCheckbox = QtGui.QCheckBox(self.tr("Rotate Repeats")) self.rotateRepeatsCheckbox.toggled.connect(self.updateTiling) self.rotateOffsetCheckbox = QtGui.QCheckBox(self.tr("Rotate Offset")) self.rotateOffsetCheckbox.toggled.connect(self.updateTiling) self.toolWidget.setLayout(Column(self.pointInput, self.rotationInput, Row(self.rotateRepeatsCheckbox, self.rotateOffsetCheckbox), self.scaleInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), confirmButton, None)) self.mainPendingClone = None # Do this after creating pointInput to disable inputs
def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.offsetPoint = None self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node() self.overlayNode.name = "Clone Overlay" self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) confirmButton = QtGui.QPushButton( self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=100, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.tileX = self.tileY = self.tileZ = False self.tileXCheckbox = QtGui.QCheckBox(self.tr("Tile X")) self.tileXCheckbox.toggled.connect(self.setTileX) self.tileYCheckbox = QtGui.QCheckBox(self.tr("Tile Y")) self.tileYCheckbox.toggled.connect(self.setTileY) self.tileZCheckbox = QtGui.QCheckBox(self.tr("Tile Z")) self.tileZCheckbox.toggled.connect(self.setTileZ) self.toolWidget.setLayout( Column( self.pointInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), Row(self.tileXCheckbox, self.tileYCheckbox, self.tileZCheckbox), confirmButton, None)) self.pendingClone = None # Do this after creating pointInput to disable inputs
def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.offsetPoint = None self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node() self.overlayNode.name = "Clone Overlay" self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) confirmButton = QtGui.QPushButton(self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=100, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.tileX = self.tileY = self.tileZ = False self.tileXCheckbox = QtGui.QCheckBox(self.tr("Tile X")) self.tileXCheckbox.toggled.connect(self.setTileX) self.tileYCheckbox = QtGui.QCheckBox(self.tr("Tile Y")) self.tileYCheckbox.toggled.connect(self.setTileY) self.tileZCheckbox = QtGui.QCheckBox(self.tr("Tile Z")) self.tileZCheckbox.toggled.connect(self.setTileZ) self.toolWidget.setLayout(Column(self.pointInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), Row(self.tileXCheckbox, self.tileYCheckbox, self.tileZCheckbox), confirmButton, None)) self.pendingClone = None # Do this after creating pointInput to disable inputs
class MoveTool(EditorTool): iconName = "move" name = "Move" modifiesWorld = True def __init__(self, editorSession, *args, **kwargs): super(MoveTool, self).__init__(editorSession, *args, **kwargs) self.overlayNode = scenenode.Node("moveOverlay") self._currentImport = None self._currentImportNode = None self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.copyOptionsWidget = QtGui.QGroupBox(self.tr("Options")) self.copyAirCheckbox = QtGui.QCheckBox(self.tr("Copy Air")) self.copyOptionsWidget.setLayout(Column(self.copyAirCheckbox)) confirmButton = QtGui.QPushButton( "Confirm") # xxxx should be in worldview confirmButton.clicked.connect(self.confirmImport) self.toolWidget.setLayout( Column(self.pointInput, self.rotationInput, self.copyOptionsWidget, confirmButton, None)) def rotationChanged(self, rots, live): if self.currentImport: if live: self.currentImportNode.setPreviewRotation(rots) elif rots != self.currentImport.rotation: command = MoveRotateCommand(self.currentImport.rotation, rots, self.currentImport) self.editorSession.pushCommand(command) self.editorSession.updateView() def pointInputChanged(self, value): if value is not None: self.importDidMove(value, self.currentImport.basePosition) # --- Pending imports --- def importDidMove(self, newPoint, oldPoint): if self.currentImport is None: return if newPoint != oldPoint: command = MoveOffsetCommand(oldPoint, newPoint, self.currentImport) self.editorSession.pushCommand(command) self.pointInput.point = newPoint @property def currentImport(self): return self._currentImport @currentImport.setter def currentImport(self, pendingImport): self._currentImport = pendingImport self.pointInput.setEnabled(pendingImport is not None) if pendingImport is not None: pendingImport.rotationChanged.connect(self.setRotationInput) pendingImport.positionChanged.connect(self.setPositionInput) # Set current import to different color? # for node in self.pendingImportNodes.itervalues(): # node.outlineNode.wireColor = (.2, 1., .2, .5) if node.pendingImport is value else (1, 1, 1, .3) if self._currentImportNode is not None: self.overlayNode.removeChild(self._currentImportNode) self._currentImportNode = None if pendingImport is not None: node = PendingImportNode(pendingImport, self.editorSession.textureAtlas) node.importMoved.connect(self.importDidMove) self._currentImportNode = node self.overlayNode.addChild(node) self.rotationInput.rotation = pendingImport.rotation self.pointInput.point = pendingImport.basePosition self.pointInput.origin = pendingImport.selection.origin @property def currentImportNode(self): return self._currentImportNode def setRotationInput(self, rots): self.rotationInput.rotation = rots def setPositionInput(self, pos): self.pointInput.point = pos # --- Mouse events --- def mouseMove(self, event): # Hilite face cursor is over if self.currentImport is not None: self.currentImportNode.mouseMove(event) # Highlight face of box to move along, or else axis pointers to grab and drag? def mouseDrag(self, event): self.mouseMove(event) def mousePress(self, event): if self.currentImport is not None: self.currentImportNode.mousePress(event) def mouseRelease(self, event): if self.currentImport is not None: self.currentImportNode.mouseRelease(event) # --- Editor events --- def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.currentImport is None: self.rotationInput.rotation = (0, 0, 0) if self.editorSession.currentSelection is None: return # This makes a reference to the latest revision in the editor. # If the moved area is changed between "Move" and "Confirm", the changed # blocks will be moved. pos = self.editorSession.currentSelection.origin pendingImport = PendingImport(self.editorSession.currentDimension, pos, self.editorSession.currentSelection, self.tr("<Moved Object>"), isMove=True) moveCommand = MoveSelectionCommand(self, pendingImport) self.editorSession.pushCommand(moveCommand) def toolInactive(self): self.editorSession.selectionTool.hideSelectionWalls = False # hide hovers for box handles? def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") sourceDim, selection = self.currentImport.getSourceForDim(destDim) def _copy(): # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter( sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) def _clear(): log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) # XXX PendingImport knows about this, defer copy/clear to it? if sourceDim is self.currentImport.importDim: # copying from original source, copy before clear _copy() _clear() else: # temp schematic used, source and dest overlap, clear before copy _clear() _copy() self.editorSession.pushCommand(command)
class MoveTool(EditorTool): iconName = "move" name = "Move" def __init__(self, editorSession, *args, **kwargs): super(MoveTool, self).__init__(editorSession, *args, **kwargs) self.overlayNode = scenenode.Node("moveOverlay") self._currentImport = None self._currentImportNode = None self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.copyOptionsWidget = QtGui.QGroupBox(self.tr("Options")) self.copyAirCheckbox = QtGui.QCheckBox(self.tr("Copy Air")) self.copyOptionsWidget.setLayout(Column(self.copyAirCheckbox)) confirmButton = QtGui.QPushButton("Confirm") # xxxx should be in worldview confirmButton.clicked.connect(self.confirmImport) self.toolWidget.setLayout(Column(self.pointInput, self.rotationInput, self.copyOptionsWidget, confirmButton, None)) def rotationChanged(self, rots, live): if self.currentImport: if live: self.currentImportNode.setPreviewRotation(rots) else: command = MoveRotateCommand(self.currentImport.rotation, rots, self.currentImport) self.editorSession.pushCommand(command) self.editorSession.updateView() def pointInputChanged(self, value): if value is not None: self.importDidMove(value, self.currentImport.basePosition) # --- Pending imports --- def importDidMove(self, newPoint, oldPoint): if newPoint != oldPoint: command = MoveOffsetCommand(oldPoint, newPoint, self.currentImport) self.editorSession.pushCommand(command) self.pointInput.point = newPoint @property def currentImport(self): return self._currentImport @currentImport.setter def currentImport(self, pendingImport): self._currentImport = pendingImport self.pointInput.setEnabled(pendingImport is not None) # Set current import to different color? # for node in self.pendingImportNodes.itervalues(): # node.outlineNode.wireColor = (.2, 1., .2, .5) if node.pendingImport is value else (1, 1, 1, .3) if self._currentImportNode is not None: self.overlayNode.removeChild(self._currentImportNode) self._currentImportNode = None if pendingImport is not None: node = PendingImportNode(pendingImport, self.editorSession.textureAtlas) node.importMoved.connect(self.importDidMove) self._currentImportNode = node self.overlayNode.addChild(node) self.rotationInput.rotation = pendingImport.rotation self.pointInput.point = pendingImport.basePosition self.pointInput.origin = pendingImport.selection.origin @property def currentImportNode(self): return self._currentImportNode # --- Mouse events --- def mouseMove(self, event): # Hilite face cursor is over if self.currentImport is not None: self.currentImportNode.mouseMove(event) # Highlight face of box to move along, or else axis pointers to grab and drag? def mouseDrag(self, event): self.mouseMove(event) def mousePress(self, event): if self.currentImport is not None: self.currentImportNode.mousePress(event) def mouseRelease(self, event): if self.currentImport is not None: self.currentImportNode.mouseRelease(event) # --- Editor events --- def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.currentImport is None: self.rotationInput.rotation = (0, 0, 0) if self.editorSession.currentSelection is None: return # This makes a reference to the latest revision in the editor. # If the moved area is changed between "Move" and "Confirm", the changed # blocks will be moved. pos = self.editorSession.currentSelection.origin pendingImport = PendingImport(self.editorSession.currentDimension, pos, self.editorSession.currentSelection, self.tr("<Moved Object>"), isMove=True) moveCommand = MoveSelectionCommand(self, pendingImport) self.editorSession.pushCommand(moveCommand) def toolInactive(self): self.editorSession.selectionTool.hideSelectionWalls = False # hide hovers for box handles? def confirmImport(self): if self.currentImport is None: return command = MoveFinishCommand(self, self.currentImport) destDim = self.editorSession.currentDimension with command.begin(): log.info("Move: starting") sourceDim, selection = self.currentImport.getSourceForDim(destDim) # Copy to destination log.info("Move: copying") task = destDim.copyBlocksIter(sourceDim, selection, self.currentImport.importPos, biomes=True, create=True, copyAir=self.copyAirCheckbox.isChecked()) showProgress(self.tr("Pasting..."), task) log.info("Move: clearing") # Clear source if self.currentImport.isMove: fill = destDim.fillBlocksIter(self.currentImport.selection, "air") showProgress(self.tr("Clearing..."), fill) self.editorSession.pushCommand(command)
class CloneTool(EditorTool): """ Make multiple copies of the selected area. When selected, displays a preview of the copies and allows the position, repeat count, and transforms to be changed. Attributes ---------- mainPendingClone : PendingImport The object currently being cloned. pendingClones : list of PendingImport Repeated imports of the object being cloned """ iconName = "clone" name = "Clone" modifiesWorld = True def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.pendingClones = [] self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node("cloneOverlay") self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) self.rotationInput = RotationWidget() self.rotationInput.rotationChanged.connect(self.rotationChanged) self.scaleInput = ScaleWidget() self.scaleInput.scaleChanged.connect(self.scaleChanged) confirmButton = QtGui.QPushButton(self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=10000, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.rotateRepeatsCheckbox = QtGui.QCheckBox(self.tr("Rotate Repeats")) self.rotateRepeatsCheckbox.toggled.connect(self.updateTiling) self.rotateOffsetCheckbox = QtGui.QCheckBox(self.tr("Rotate Offset")) self.rotateOffsetCheckbox.toggled.connect(self.updateTiling) self.toolWidget.setLayout(Column(self.pointInput, self.rotationInput, Row(self.rotateRepeatsCheckbox, self.rotateOffsetCheckbox), self.scaleInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), confirmButton, None)) self.mainPendingClone = None # Do this after creating pointInput to disable inputs def pointInputChanged(self, value): if self.mainPendingClone.basePosition != value: self.mainPendingClone.basePosition = value self.updateTiling() def rotationChanged(self, rots, live): scale = self.scaleInput.scale if live: for node, (nodePos, nodeRots, nodeScale) in zip(self.pendingCloneNodes, self.getTilingPositions(None, rots, scale)): node.setPreviewRotation(nodeRots) node.setPreviewScale(nodeScale) node.setPreviewBasePosition(nodePos + node.pendingImport.transformOffset) self.editorSession.updateView() else: if self.mainPendingClone and self.mainPendingClone.rotation != rots: command = CloneRotateCommand(self.mainPendingClone.rotation, rots, self) self.editorSession.pushCommand(command) self.updateTiling() def scaleChanged(self, scale, live): rots = self.rotationInput.rotation if live: for node, (nodePos, nodeRots, nodeScale) in zip(self.pendingCloneNodes, self.getTilingPositions(None, rots, scale)): node.setPreviewRotation(nodeRots) node.setPreviewScale(nodeScale) node.setPreviewBasePosition(nodePos + node.pendingImport.transformOffset) self.editorSession.updateView() else: if self.mainPendingClone and self.mainPendingClone.scale != scale: command = CloneScaleCommand(self.mainPendingClone.scale, scale, self) self.editorSession.pushCommand(command) self.updateTiling() def setRepeatCount(self, value): self.repeatCount = value self.updateTiling() def setRotation(self, rots): if self.mainPendingClone is None: return else: self.mainPendingClone.rotation = rots self.updateTiling() def setScale(self, scale): if self.mainPendingClone is None: return else: self.mainPendingClone.scale = scale self.updateTiling() def updateTiling(self): if self.mainPendingClone is None: repeatCount = 0 else: repeatCount = self.repeatCount while len(self.pendingClones) > repeatCount: node = self.pendingCloneNodes.pop() self.overlayNode.removeChild(node) self.pendingClones.pop() while len(self.pendingClones) < repeatCount: clone = PendingImport(self.mainPendingClone.sourceDim, self.mainPendingClone.basePosition, self.mainPendingClone.selection, self.mainPendingClone.text + " %d" % len(self.pendingClones)) node = PendingImportNode(clone, self.editorSession.textureAtlas, hasHandle=len(self.pendingClones) == 0) self.pendingClones.append(clone) self.pendingCloneNodes.append(node) self.overlayNode.addChild(node) # This is stupid. if self.mainCloneNode: self.mainCloneNode.importMoved.disconnect(self.cloneDidMove) self.mainCloneNode.importIsMoving.disconnect(self.cloneIsMoving) if repeatCount > 0: self.mainCloneNode = self.pendingCloneNodes[0] self.mainCloneNode.importMoved.connect(self.cloneDidMove) self.mainCloneNode.importIsMoving.connect(self.cloneIsMoving) else: self.mainCloneNode = None self.updateTilingPositions() def updateTilingPositions(self, offsetPoint=None): if self.originPoint is not None: for clone, (pos, rots, scale) in zip(self.pendingClones, self.getTilingPositions(offsetPoint)): clone.basePosition = pos clone.rotation = rots clone.scale = scale self.editorSession.updateView() def getTilingPositions(self, offsetPoint=None, rotations=None, scale=None): rotateRepeats = self.rotateRepeatsCheckbox.isChecked() rotateOffsets = self.rotateOffsetCheckbox.isChecked() baseRotations = rotations or self.mainPendingClone.rotation rotations = baseRotations scale = scale or self.mainPendingClone.scale matrix = transform.transformationMatrix((0, 0, 0), rotations, scale) matrix = numpy.linalg.inv(matrix)[:3, :3] # TODO: Use scales here if offsetPoint is None: offsetPoint = self.mainPendingClone.basePosition if None not in (offsetPoint, self.originPoint): pos = self.originPoint offset = offsetPoint - self.originPoint for i in range(self.repeatCount): pos = pos + offset yield pos.intfloor(), rotations, scale if rotateRepeats: rotations = [a+b for a,b in zip(rotations, baseRotations)] if rotateOffsets: # Convert to 4-element column and back offset = (offset * matrix).T offset = tuple(float(x) for x in offset) @property def mainPendingClone(self): return self._pendingClone @mainPendingClone.setter def mainPendingClone(self, pendingImport): log.info("Begin clone: %s", pendingImport) self._pendingClone = pendingImport self.pointInput.setEnabled(pendingImport is not None) if pendingImport: self.pointInput.point = pendingImport.basePosition self.updateTiling() def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.mainPendingClone is None: if self.editorSession.currentSelection is None: return # This makes a reference to the latest revision in the editor. # If the cloned area is changed between "Clone" and "Confirm", the changed # blocks will be cloned. pos = self.editorSession.currentSelection.origin self.pointInput.origin = self.originPoint = pos pendingImport = PendingImport(self.editorSession.currentDimension, pos, self.editorSession.currentSelection, self.tr("<Cloned Object>")) moveCommand = CloneSelectionCommand(self, pendingImport) self.editorSession.pushCommand(moveCommand) self.updateTiling() def toolInactive(self): self.editorSession.selectionTool.hideSelectionWalls = False # if self.mainCloneNode: # self.mainCloneNode.hoverFace(None) self.confirmClone() def confirmClone(self): if self.mainPendingClone is None: return command = CloneFinishCommand(self, self.mainPendingClone, self.originPoint) with command.begin(): tasks = [] for clone in self.pendingClones: # TODO don't use intermediate schematic... destDim = self.editorSession.currentDimension dim, selection = clone.getSourceForDim(destDim) task = destDim.copyBlocksIter(dim, selection, clone.importPos, biomes=True, create=True, copyAir=False) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command) @property def clonePosition(self): return None if self.mainPendingClone is None else self.mainPendingClone.basePosition @clonePosition.setter def clonePosition(self, value): """ :type value: Vector """ self.pointInput.point = value self.pointInputChanged(value) # --- Mouse events --- def mouseMove(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mouseDrag(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mousePress(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mousePress(event) def mouseRelease(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseRelease(event) # --- Box handle events --- def cloneDidMove(self, newPoint, oldPoint): log.info("clone offset command: %s %s", oldPoint, newPoint) if newPoint != oldPoint: command = CloneOffsetCommand(self, oldPoint, newPoint) self.editorSession.pushCommand(command) def cloneIsMoving(self, newPoint): self.updateTilingPositions(newPoint)
class CloneTool(EditorTool): iconName = "clone" name = "Clone" def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.offsetPoint = None self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node() self.overlayNode.name = "Clone Overlay" self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) confirmButton = QtGui.QPushButton(self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=100, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.tileX = self.tileY = self.tileZ = False self.tileXCheckbox = QtGui.QCheckBox(self.tr("Tile X")) self.tileXCheckbox.toggled.connect(self.setTileX) self.tileYCheckbox = QtGui.QCheckBox(self.tr("Tile Y")) self.tileYCheckbox.toggled.connect(self.setTileY) self.tileZCheckbox = QtGui.QCheckBox(self.tr("Tile Z")) self.tileZCheckbox.toggled.connect(self.setTileZ) self.toolWidget.setLayout(Column(self.pointInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), Row(self.tileXCheckbox, self.tileYCheckbox, self.tileZCheckbox), confirmButton, None)) self.pendingClone = None # Do this after creating pointInput to disable inputs def pointInputChanged(self, value): if self.offsetPoint != value: self.offsetPoint = value self.pendingClone.pos = value self.updateTiling() def setTileX(self, value): self.tileX = value self.updateTiling() def setTileY(self, value): self.tileY = value self.updateTiling() def setTileZ(self, value): self.tileZ = value self.updateTiling() def setRepeatCount(self, value): self.repeatCount = value self.updateTiling() def updateTiling(self): if self.pendingClone is None: repeatCount = 0 else: repeatCount = self.repeatCount while len(self.pendingCloneNodes) > repeatCount: node = self.pendingCloneNodes.pop() self.overlayNode.removeChild(node) while len(self.pendingCloneNodes) < repeatCount: node = PendingImportNode(self.pendingClone, self.editorSession.textureAtlas) self.pendingCloneNodes.append(node) self.overlayNode.addChild(node) # This is stupid. if self.mainCloneNode: self.mainCloneNode.importMoved.disconnect(self.cloneDidMove) if repeatCount > 0: self.mainCloneNode = self.pendingCloneNodes[0] self.mainCloneNode.importMoved.connect(self.cloneDidMove) else: self.mainCloneNode = None if None not in (self.offsetPoint, self.originPoint): for node, pos in zip(self.pendingCloneNodes, self.getTilingPositions()): node.pos = pos self.editorSession.updateView() def getTilingPositions(self): if None not in (self.offsetPoint, self.originPoint): pos = self.originPoint offset = self.offsetPoint - self.originPoint for i in range(self.repeatCount): pos = pos + offset yield pos @property def pendingClone(self): return self._pendingClone @pendingClone.setter def pendingClone(self, pendingImport): log.info("Begin clone: %s", pendingImport) self._pendingClone = pendingImport self.pointInput.setEnabled(pendingImport is not None) self.updateTiling() def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.pendingClone is not None: self.pendingClone = None if self.editorSession.currentSelection is None: return # This makes a reference to the latest revision in the editor. # If the cloned area is changed between "Clone" and "Confirm", the changed # blocks will be moved. pos = self.editorSession.currentSelection.origin self.originPoint = pos self.offsetPoint = pos pendingImport = PendingImport(self.editorSession.currentDimension, pos, self.editorSession.currentSelection, self.tr("<Cloned Object>")) moveCommand = CloneSelectionCommand(self, pendingImport) self.editorSession.pushCommand(moveCommand) def toolInactive(self): self.editorSession.selectionTool.hideSelectionWalls = False # if self.mainCloneNode: # self.mainCloneNode.hoverFace(None) self.confirmClone() def confirmClone(self): if self.pendingClone is None: return command = CloneFinishCommand(self, self.pendingClone) with command.begin(): # TODO don't use intermediate schematic... export = self.pendingClone.sourceDim.exportSchematicIter(self.pendingClone.selection) schematic = showProgress("Copying...", export) dim = schematic.getDimension() tasks = [] for pos in self.getTilingPositions(): task = self.editorSession.currentDimension.copyBlocksIter(dim, dim.bounds, pos, biomes=True, create=True) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command) self.originPoint = None @property def clonePosition(self): return None if self.pendingClone is None else self.pendingClone.pos @clonePosition.setter def clonePosition(self, value): """ :type value: Vector """ self.pointInput.point = value self.pointInputChanged(value) # --- Mouse events --- def mouseMove(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mouseDrag(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mousePress(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mousePress(event) def mouseRelease(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseRelease(event) # --- Box handle events --- def cloneDidMove(self, newPoint, oldPoint): log.info("clone offset command: %s %s", oldPoint, newPoint) if newPoint != oldPoint: command = CloneOffsetCommand(self, oldPoint, newPoint) self.editorSession.pushCommand(command)
class CloneTool(EditorTool): iconName = "clone" name = "Clone" def __init__(self, editorSession, *args, **kwargs): super(CloneTool, self).__init__(editorSession, *args, **kwargs) self.originPoint = None self.offsetPoint = None self.pendingCloneNodes = [] self.mainCloneNode = None self.overlayNode = scenenode.Node() self.overlayNode.name = "Clone Overlay" self.toolWidget = QtGui.QWidget() self.pointInput = CoordinateWidget() self.pointInput.pointChanged.connect(self.pointInputChanged) confirmButton = QtGui.QPushButton( self.tr("Confirm")) # xxxx should be in worldview confirmButton.clicked.connect(self.confirmClone) self.repeatCount = 1 self.repeatCountInput = QtGui.QSpinBox(minimum=1, maximum=100, value=1) self.repeatCountInput.valueChanged.connect(self.setRepeatCount) self.tileX = self.tileY = self.tileZ = False self.tileXCheckbox = QtGui.QCheckBox(self.tr("Tile X")) self.tileXCheckbox.toggled.connect(self.setTileX) self.tileYCheckbox = QtGui.QCheckBox(self.tr("Tile Y")) self.tileYCheckbox.toggled.connect(self.setTileY) self.tileZCheckbox = QtGui.QCheckBox(self.tr("Tile Z")) self.tileZCheckbox.toggled.connect(self.setTileZ) self.toolWidget.setLayout( Column( self.pointInput, Row(QtGui.QLabel(self.tr("Repeat count: ")), self.repeatCountInput), Row(self.tileXCheckbox, self.tileYCheckbox, self.tileZCheckbox), confirmButton, None)) self.pendingClone = None # Do this after creating pointInput to disable inputs def pointInputChanged(self, value): if self.offsetPoint != value: self.offsetPoint = value self.pendingClone.pos = value self.updateTiling() def setTileX(self, value): self.tileX = value self.updateTiling() def setTileY(self, value): self.tileY = value self.updateTiling() def setTileZ(self, value): self.tileZ = value self.updateTiling() def setRepeatCount(self, value): self.repeatCount = value self.updateTiling() def updateTiling(self): if self.pendingClone is None: repeatCount = 0 else: repeatCount = self.repeatCount while len(self.pendingCloneNodes) > repeatCount: node = self.pendingCloneNodes.pop() self.overlayNode.removeChild(node) while len(self.pendingCloneNodes) < repeatCount: node = PendingImportNode(self.pendingClone, self.editorSession.textureAtlas) self.pendingCloneNodes.append(node) self.overlayNode.addChild(node) # This is stupid. if self.mainCloneNode: self.mainCloneNode.importMoved.disconnect(self.cloneDidMove) if repeatCount > 0: self.mainCloneNode = self.pendingCloneNodes[0] self.mainCloneNode.importMoved.connect(self.cloneDidMove) else: self.mainCloneNode = None if None not in (self.offsetPoint, self.originPoint): for node, pos in zip(self.pendingCloneNodes, self.getTilingPositions()): node.pos = pos self.editorSession.updateView() def getTilingPositions(self): if None not in (self.offsetPoint, self.originPoint): pos = self.originPoint offset = self.offsetPoint - self.originPoint for i in range(self.repeatCount): pos = pos + offset yield pos @property def pendingClone(self): return self._pendingClone @pendingClone.setter def pendingClone(self, pendingImport): log.info("Begin clone: %s", pendingImport) self._pendingClone = pendingImport self.pointInput.setEnabled(pendingImport is not None) self.updateTiling() def toolActive(self): self.editorSession.selectionTool.hideSelectionWalls = True if self.pendingClone is not None: self.pendingClone = None if self.editorSession.currentSelection is None: return # This makes a reference to the latest revision in the editor. # If the cloned area is changed between "Clone" and "Confirm", the changed # blocks will be moved. pos = self.editorSession.currentSelection.origin self.originPoint = pos self.offsetPoint = pos pendingImport = PendingImport(self.editorSession.currentDimension, pos, self.editorSession.currentSelection, self.tr("<Cloned Object>")) moveCommand = CloneSelectionCommand(self, pendingImport) self.editorSession.pushCommand(moveCommand) def toolInactive(self): self.editorSession.selectionTool.hideSelectionWalls = False # if self.mainCloneNode: # self.mainCloneNode.hoverFace(None) self.confirmClone() def confirmClone(self): if self.pendingClone is None: return command = CloneFinishCommand(self, self.pendingClone) with command.begin(): # TODO don't use intermediate schematic... export = self.pendingClone.sourceDim.exportSchematicIter( self.pendingClone.selection) schematic = showProgress("Copying...", export) dim = schematic.getDimension() tasks = [] for pos in self.getTilingPositions(): task = self.editorSession.currentDimension.copyBlocksIter( dim, dim.bounds, pos, biomes=True, create=True) tasks.append(task) showProgress(self.tr("Pasting..."), *tasks) self.editorSession.pushCommand(command) self.originPoint = None @property def clonePosition(self): return None if self.pendingClone is None else self.pendingClone.pos @clonePosition.setter def clonePosition(self, value): """ :type value: Vector """ self.pointInput.point = value self.pointInputChanged(value) # --- Mouse events --- def mouseMove(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mouseDrag(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseMove(event) def mousePress(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mousePress(event) def mouseRelease(self, event): if self.mainCloneNode is not None: self.mainCloneNode.mouseRelease(event) # --- Box handle events --- def cloneDidMove(self, newPoint, oldPoint): log.info("clone offset command: %s %s", oldPoint, newPoint) if newPoint != oldPoint: command = CloneOffsetCommand(self, oldPoint, newPoint) self.editorSession.pushCommand(command)