Multi-command paste and move operations - Start, Move, Finish are recorded in history
...and add some type info
This commit is contained in:
parent
98ff85b544
commit
b4e1c43f9a
@ -43,11 +43,12 @@ class SimpleRevisionCommand(QtGui.QUndoCommand):
|
||||
self.setText(text)
|
||||
|
||||
def undo(self):
|
||||
self.editorSession.gotoRevision(self.previousRevision)
|
||||
if self.previousRevision is not None:
|
||||
self.editorSession.gotoRevision(self.previousRevision)
|
||||
|
||||
def redo(self):
|
||||
self.editorSession.gotoRevision(self.currentRevision)
|
||||
pass
|
||||
if self.currentRevision is not None:
|
||||
self.editorSession.gotoRevision(self.currentRevision)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def begin(self):
|
||||
|
@ -47,7 +47,9 @@ class EditorSession(QtCore.QObject):
|
||||
self.undoBlock = None
|
||||
self.currentTool = None
|
||||
self.dirty = False
|
||||
|
||||
self.copiedSchematic = None
|
||||
""":type : WorldEditor"""
|
||||
self.versionInfo = versionInfo
|
||||
|
||||
# --- Open world editor ---
|
||||
@ -241,10 +243,11 @@ class EditorSession(QtCore.QObject):
|
||||
return
|
||||
|
||||
moveTool = self.tools["Move"]
|
||||
if moveTool is self.currentTool:
|
||||
moveTool.completeMove()
|
||||
moveTool.movingSchematic = self.copiedSchematic
|
||||
moveTool.movePosition = self.editorTab.currentView().viewCenter()
|
||||
|
||||
ray = self.editorTab.currentView().rayAtCenter()
|
||||
point = ray.point + ray.vector * (self.copiedSchematic.getDimension().bounds.size.length() * 2)
|
||||
point = Vector(*[int(i) for i in point])
|
||||
moveTool.pasteSchematic(self.copiedSchematic, point)
|
||||
self.chooseTool("Move")
|
||||
|
||||
def pasteBlocks(self):
|
||||
@ -271,7 +274,7 @@ class EditorSession(QtCore.QObject):
|
||||
self.undoStack.removeUndoBlock(callback)
|
||||
|
||||
def beginUndo(self):
|
||||
self.undoStack.clearUndoBlock(True)
|
||||
self.undoStack.clearUndoBlock()
|
||||
self.dirty = True
|
||||
self.worldEditor.beginUndo()
|
||||
|
||||
@ -544,7 +547,7 @@ class EditorTab(QtGui.QWidget):
|
||||
def currentView(self):
|
||||
"""
|
||||
|
||||
:rtype: WorldView
|
||||
:rtype: mcedit2.worldview.worldview.WorldView
|
||||
"""
|
||||
return self.viewStack.currentWidget().worldView
|
||||
|
||||
|
@ -21,6 +21,65 @@ from mceditlib.geometry import BoundingBox, Vector
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class MoveSelectionCommand(SimpleRevisionCommand):
|
||||
def __init__(self, moveTool, movingSchematic, movePosition=None, text=None, *args, **kwargs):
|
||||
if text is None:
|
||||
text = moveTool.tr("Move Selected Blocks")
|
||||
if movePosition is None:
|
||||
movePosition = moveTool.editorSession.currentSelection.origin
|
||||
super(MoveSelectionCommand, self).__init__(moveTool.editorSession, text, *args, **kwargs)
|
||||
self.moveTool = moveTool
|
||||
self.movingSchematic = movingSchematic
|
||||
self.movePosition = movePosition
|
||||
|
||||
def undo(self):
|
||||
super(MoveSelectionCommand, self).undo()
|
||||
self.moveTool.movingSchematic = None
|
||||
self.moveTool.movePosition = None
|
||||
self.moveTool.editorSession.chooseTool("Select")
|
||||
|
||||
def redo(self):
|
||||
self.moveTool.movingSchematic = self.movingSchematic
|
||||
self.moveTool.movePosition = self.movePosition
|
||||
self.moveTool.editorSession.chooseTool("Move")
|
||||
super(MoveSelectionCommand, self).redo()
|
||||
|
||||
|
||||
class MoveOffsetCommand(QtGui.QUndoCommand):
|
||||
|
||||
def __init__(self, moveTool, oldPoint, newPoint):
|
||||
super(MoveOffsetCommand, self).__init__()
|
||||
self.setText(moveTool.tr("Move Selection"))
|
||||
self.newPoint = newPoint
|
||||
self.oldPoint = oldPoint
|
||||
self.moveTool = moveTool
|
||||
|
||||
def undo(self):
|
||||
self.moveTool.movePosition = self.oldPoint
|
||||
|
||||
def redo(self):
|
||||
self.moveTool.movePosition = self.newPoint
|
||||
|
||||
class MoveFinishCommand(SimpleRevisionCommand):
|
||||
def __init__(self, moveTool, movingSchematic, *args, **kwargs):
|
||||
super(MoveFinishCommand, self).__init__(moveTool.editorSession, moveTool.tr("Finish Move"), *args, **kwargs)
|
||||
self.movingSchematic = movingSchematic
|
||||
self.moveTool = moveTool
|
||||
|
||||
def undo(self):
|
||||
super(MoveFinishCommand, self).undo()
|
||||
self.moveTool.movingSchematic = self.movingSchematic
|
||||
self.moveTool.movePosition = self.movePosition
|
||||
self.editorSession.currentSelection = self.previousSelection
|
||||
self.editorSession.chooseTool("Move")
|
||||
|
||||
def redo(self):
|
||||
super(MoveFinishCommand, self).redo()
|
||||
self.previousSelection = self.editorSession.currentSelection
|
||||
self.movePosition = self.moveTool.movePosition
|
||||
self.editorSession.currentSelection = BoundingBox(self.movePosition, self.previousSelection.size)
|
||||
self.moveTool.movingSchematic = None
|
||||
|
||||
|
||||
class CoordinateWidget(QtGui.QWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -86,7 +145,6 @@ class MoveTool(EditorTool):
|
||||
|
||||
self.movingWorldScene = None
|
||||
self.loader = None
|
||||
self.currentCommand = None
|
||||
self.dragStartFace = None
|
||||
self.dragStartPoint = None
|
||||
|
||||
@ -116,6 +174,13 @@ class MoveTool(EditorTool):
|
||||
self.pointInput.point = value
|
||||
self.pointInputChanged(value)
|
||||
|
||||
def doMoveOffsetCommand(self, oldPoint, newPoint):
|
||||
if newPoint != oldPoint:
|
||||
command = MoveOffsetCommand(self, oldPoint, newPoint)
|
||||
self.editorSession.removeUndoBlock(self.moveUndoBlock)
|
||||
self.editorSession.pushCommand(command)
|
||||
self.editorSession.setUndoBlock(self.moveUndoBlock)
|
||||
|
||||
def pointInputChanged(self, value):
|
||||
self._movePosition = value
|
||||
if value is not None:
|
||||
@ -185,7 +250,7 @@ class MoveTool(EditorTool):
|
||||
|
||||
def mouseMove(self, event):
|
||||
# Hilite face cursor is over
|
||||
if self.movingSchematic is None:
|
||||
if self.movingSchematic is None or self.movePosition is None:
|
||||
return
|
||||
|
||||
point, face = boxFaceUnderCursor(self.schematicBox, event.ray)
|
||||
@ -229,26 +294,31 @@ class MoveTool(EditorTool):
|
||||
# Don't paste cut selection in yet. Wait for tool switch or "Confirm" button press. Begin new revision
|
||||
# for paste operation, paste stored world, store revision after paste (should be previously stored revision
|
||||
# +2), commit MoveCommand to undo history.
|
||||
pass
|
||||
if self.movingSchematic is not None:
|
||||
self.doMoveOffsetCommand(self.dragStartMovePosition, self.movePosition)
|
||||
|
||||
def toolActive(self):
|
||||
self.editorSession.selectionTool.hideSelectionWalls = True
|
||||
if self.currentCommand is None and self.movingSchematic is None:
|
||||
if self.movingSchematic is None:
|
||||
# Need to cut out selection
|
||||
# xxxx for huge selections, don't cut, just do everything at the end?
|
||||
if self.editorSession.currentSelection is None:
|
||||
return
|
||||
export = self.editorSession.currentDimension.exportSchematicIter(self.editorSession.currentSelection)
|
||||
self.movingSchematic = showProgress("Lifting...", export)
|
||||
self.movePosition = self.editorSession.currentSelection.origin
|
||||
|
||||
self.currentCommand = SimpleRevisionCommand(self.editorSession, self.tr("Move"))
|
||||
self.currentCommand.previousRevision = self.editorSession.currentRevision
|
||||
self.editorSession.beginUndo()
|
||||
fill = self.editorSession.currentDimension.fillBlocksIter(self.editorSession.currentSelection, "air")
|
||||
showProgress("Lifting...", fill)
|
||||
self.editorSession.commitUndo()
|
||||
self.editorSession.setUndoBlock(self.completeMove)
|
||||
moveCommand = MoveSelectionCommand(self, self.movingSchematic)
|
||||
|
||||
with moveCommand.begin():
|
||||
fill = self.editorSession.currentDimension.fillBlocksIter(self.editorSession.currentSelection, "air")
|
||||
showProgress("Lifting...", fill)
|
||||
|
||||
self.editorSession.pushCommand(moveCommand)
|
||||
self.editorSession.setUndoBlock(self.moveUndoBlock)
|
||||
|
||||
def moveUndoBlock(self):
|
||||
self.completeMove()
|
||||
self.movingSchematic = None
|
||||
|
||||
def toolInactive(self):
|
||||
self.editorSession.selectionTool.hideSelectionWalls = False
|
||||
@ -263,17 +333,16 @@ class MoveTool(EditorTool):
|
||||
if self.movingSchematic is None:
|
||||
return
|
||||
|
||||
if self.currentCommand is None:
|
||||
self.currentCommand = SimpleRevisionCommand(self.editorSession, self.tr("Paste"))
|
||||
self.currentCommand.previousRevision = self.editorSession.currentRevision
|
||||
self.editorSession.removeUndoBlock(self.moveUndoBlock)
|
||||
command = MoveFinishCommand(self, self.movingSchematic)
|
||||
|
||||
self.editorSession.removeUndoBlock(self.completeMove)
|
||||
self.editorSession.beginUndo()
|
||||
task = self.editorSession.currentDimension.importSchematicIter(self.movingSchematic, self.movePosition)
|
||||
showProgress(self.tr("Pasting..."), task)
|
||||
self.editorSession.commitUndo()
|
||||
with command.begin():
|
||||
task = self.editorSession.currentDimension.importSchematicIter(self.movingSchematic, self.movePosition)
|
||||
showProgress(self.tr("Pasting..."), task)
|
||||
|
||||
self.currentCommand.currentRevision = self.editorSession.worldEditor.currentRevision
|
||||
self.editorSession.pushCommand(self.currentCommand)
|
||||
self.currentCommand = None
|
||||
self.movingSchematic = None
|
||||
self.editorSession.pushCommand(command)
|
||||
|
||||
def pasteSchematic(self, copiedSchematic, position):
|
||||
command = MoveSelectionCommand(self, copiedSchematic, position, self.tr("Paste"))
|
||||
self.editorSession.pushCommand(command)
|
||||
self.editorSession.setUndoBlock(self.moveUndoBlock)
|
||||
|
@ -11,13 +11,18 @@ class MCEUndoStack(QtGui.QUndoStack):
|
||||
undoBlock = None
|
||||
|
||||
def undo(self):
|
||||
self.clearUndoBlock(False)
|
||||
self.clearUndoBlock()
|
||||
super(MCEUndoStack, self).undo()
|
||||
|
||||
def redo(self):
|
||||
self.clearUndoBlock(False) # Shouldn't ever find a block
|
||||
self.clearUndoBlock() # Shouldn't ever find a block
|
||||
super(MCEUndoStack, self).redo()
|
||||
|
||||
def push(self, *args, **kwargs):
|
||||
self.clearUndoBlock()
|
||||
super(MCEUndoStack, self).push(*args, **kwargs)
|
||||
|
||||
|
||||
def setUndoBlock(self, callback):
|
||||
"""
|
||||
Set a function to be called before the next time undo, redo, or beginUndo is called. Some tools may need to
|
||||
@ -42,17 +47,15 @@ class MCEUndoStack(QtGui.QUndoStack):
|
||||
self.undoBlock, callback)
|
||||
self.undoBlock = None
|
||||
|
||||
def clearUndoBlock(self, complete):
|
||||
def clearUndoBlock(self):
|
||||
"""
|
||||
If an undo block is set, calls its callback and removes it.
|
||||
|
||||
:param complete: Whether to complete or abort the command which set the undo block
|
||||
:type complete: bool
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
if self.undoBlock:
|
||||
callback = self.undoBlock
|
||||
self.undoBlock = None
|
||||
callback(complete)
|
||||
callback()
|
||||
|
||||
|
@ -402,12 +402,15 @@ class WorldView(QGLWidget):
|
||||
Parameters:
|
||||
x and y are coordinates local to this QWidget
|
||||
|
||||
Returns a Ray
|
||||
:rtype: Ray
|
||||
"""
|
||||
|
||||
p0, p1 = self.pointsAtPositions((x, y, 0.0), (x, y, 0.1))
|
||||
return Ray(p0, (p1 - p0).normalize())
|
||||
|
||||
def rayAtCenter(self):
|
||||
return self.rayAtPosition(self.width()/2, self.height()/2)
|
||||
|
||||
def pointsAtPositions(self, *screenPoints):
|
||||
w = float(self.width())
|
||||
h = float(self.height())
|
||||
|
@ -284,27 +284,33 @@ class BoundingBox(SelectionBox):
|
||||
|
||||
@property
|
||||
def origin(self):
|
||||
"The smallest position in the box"
|
||||
"""
|
||||
The smallest position in the box
|
||||
:rtype: Vector
|
||||
"""
|
||||
return self._origin
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"The size of the box"
|
||||
"""
|
||||
The size of the box
|
||||
:rtype: Vector
|
||||
"""
|
||||
return self._size
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
"The dimension along the X axis"
|
||||
"""The dimension along the X axis"""
|
||||
return self._size.x
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
"The dimension along the Y axis"
|
||||
"""The dimension along the Y axis"""
|
||||
return self._size.y
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
"The dimension along the Z axis"
|
||||
"""The dimension along the Z axis"""
|
||||
return self._size.z
|
||||
|
||||
@property
|
||||
|
@ -226,6 +226,7 @@ class WorldEditor(object):
|
||||
:return:
|
||||
:rtype:
|
||||
"""
|
||||
assert index is not None, "None is not a revision index!"
|
||||
self.syncToDisk()
|
||||
|
||||
changes = self.adapter.selectRevision(index)
|
||||
@ -508,6 +509,11 @@ class WorldEditorDimension(object):
|
||||
|
||||
@property
|
||||
def bounds(self):
|
||||
"""
|
||||
|
||||
:return:
|
||||
:rtype: BoundingBox
|
||||
"""
|
||||
if self._bounds is None:
|
||||
if hasattr(self.adapter, "getDimensionBounds"):
|
||||
self._bounds = self.adapter.getDimensionBounds(self.dimName)
|
||||
|
Reference in New Issue
Block a user