undoable Life component grid actions
This commit is contained in:
parent
4a310ffb28
commit
ad6dd9f532
|
@ -1,4 +1,5 @@
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
|
from PyQt5.QtWidgets import QUndoCommand
|
||||||
from PIL import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter
|
from PIL import Image, ImageDraw, ImageEnhance, ImageChops, ImageFilter
|
||||||
import os
|
import os
|
||||||
import math
|
import math
|
||||||
|
@ -58,22 +59,8 @@ class Component(Component):
|
||||||
self.mergeUndo = True
|
self.mergeUndo = True
|
||||||
|
|
||||||
def shiftGrid(self, d):
|
def shiftGrid(self, d):
|
||||||
def newGrid(Xchange, Ychange):
|
action = ShiftGrid(self, d)
|
||||||
return {
|
self.parent.undoStack.push(action)
|
||||||
(x + Xchange, y + Ychange)
|
|
||||||
for x, y in self.startingGrid
|
|
||||||
}
|
|
||||||
|
|
||||||
if d == 0:
|
|
||||||
newGrid = newGrid(0, -1)
|
|
||||||
elif d == 1:
|
|
||||||
newGrid = newGrid(0, 1)
|
|
||||||
elif d == 2:
|
|
||||||
newGrid = newGrid(-1, 0)
|
|
||||||
elif d == 3:
|
|
||||||
newGrid = newGrid(1, 0)
|
|
||||||
self.startingGrid = newGrid
|
|
||||||
self._sendUpdateSignal()
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.updateGridSize()
|
self.updateGridSize()
|
||||||
|
@ -98,17 +85,14 @@ class Component(Component):
|
||||||
enabled = (len(self.startingGrid) > 0)
|
enabled = (len(self.startingGrid) > 0)
|
||||||
for widget in self.shiftButtons:
|
for widget in self.shiftButtons:
|
||||||
widget.setEnabled(enabled)
|
widget.setEnabled(enabled)
|
||||||
super().update()
|
|
||||||
|
|
||||||
def previewClickEvent(self, pos, size, button):
|
def previewClickEvent(self, pos, size, button):
|
||||||
pos = (
|
pos = (
|
||||||
math.ceil((pos[0] / size[0]) * self.gridWidth) - 1,
|
math.ceil((pos[0] / size[0]) * self.gridWidth) - 1,
|
||||||
math.ceil((pos[1] / size[1]) * self.gridHeight) - 1
|
math.ceil((pos[1] / size[1]) * self.gridHeight) - 1
|
||||||
)
|
)
|
||||||
if button == 1:
|
action = ClickGrid(self, pos, button)
|
||||||
self.startingGrid.add(pos)
|
self.parent.undoStack.push(action)
|
||||||
elif button == 2:
|
|
||||||
self.startingGrid.discard(pos)
|
|
||||||
|
|
||||||
def updateGridSize(self):
|
def updateGridSize(self):
|
||||||
w, h = self.core.resolutions[-1].split('x')
|
w, h = self.core.resolutions[-1].split('x')
|
||||||
|
@ -223,7 +207,7 @@ class Component(Component):
|
||||||
'up', 'down', 'left', 'right',
|
'up', 'down', 'left', 'right',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
for cell in nearbyCoords(x, y):
|
for cell in self.nearbyCoords(x, y):
|
||||||
if cell not in grid:
|
if cell not in grid:
|
||||||
continue
|
continue
|
||||||
if cell[0] == x:
|
if cell[0] == x:
|
||||||
|
@ -363,7 +347,7 @@ class Component(Component):
|
||||||
|
|
||||||
def neighbours(x, y):
|
def neighbours(x, y):
|
||||||
return {
|
return {
|
||||||
cell for cell in nearbyCoords(x, y)
|
cell for cell in self.nearbyCoords(x, y)
|
||||||
if cell in lastGrid
|
if cell in lastGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +358,7 @@ class Component(Component):
|
||||||
newGrid.add((x, y))
|
newGrid.add((x, y))
|
||||||
potentialNewCells = {
|
potentialNewCells = {
|
||||||
coordTup for origin in lastGrid
|
coordTup for origin in lastGrid
|
||||||
for coordTup in list(nearbyCoords(*origin))
|
for coordTup in list(self.nearbyCoords(*origin))
|
||||||
}
|
}
|
||||||
for x, y in potentialNewCells:
|
for x, y in potentialNewCells:
|
||||||
if (x, y) in newGrid:
|
if (x, y) in newGrid:
|
||||||
|
@ -397,13 +381,95 @@ class Component(Component):
|
||||||
widget.setEnabled(True)
|
widget.setEnabled(True)
|
||||||
super().loadPreset(pr, *args)
|
super().loadPreset(pr, *args)
|
||||||
|
|
||||||
|
def nearbyCoords(self, x, y):
|
||||||
|
yield x + 1, y + 1
|
||||||
|
yield x + 1, y - 1
|
||||||
|
yield x - 1, y + 1
|
||||||
|
yield x - 1, y - 1
|
||||||
|
yield x, y + 1
|
||||||
|
yield x, y - 1
|
||||||
|
yield x + 1, y
|
||||||
|
yield x - 1, y
|
||||||
|
|
||||||
def nearbyCoords(x, y):
|
|
||||||
yield x + 1, y + 1
|
class ClickGrid(QUndoCommand):
|
||||||
yield x + 1, y - 1
|
def __init__(self, comp, pos, id_):
|
||||||
yield x - 1, y + 1
|
super().__init__(
|
||||||
yield x - 1, y - 1
|
"click %s component #%s" % (comp.name, comp.compPos))
|
||||||
yield x, y + 1
|
self.comp = comp
|
||||||
yield x, y - 1
|
self.pos = [pos]
|
||||||
yield x + 1, y
|
self.id_ = id_
|
||||||
yield x - 1, y
|
|
||||||
|
def id(self):
|
||||||
|
return self.id_
|
||||||
|
|
||||||
|
def mergeWith(self, other):
|
||||||
|
self.pos.extend(other.pos)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def add(self):
|
||||||
|
for pos in self.pos[:]:
|
||||||
|
self.comp.startingGrid.add(pos)
|
||||||
|
self.comp.update(auto=True)
|
||||||
|
|
||||||
|
def remove(self):
|
||||||
|
for pos in self.pos[:]:
|
||||||
|
self.comp.startingGrid.discard(pos)
|
||||||
|
self.comp.update(auto=True)
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self.id_ == 1: # Left-click
|
||||||
|
self.add()
|
||||||
|
elif self.id_ == 2: # Right-click
|
||||||
|
self.remove()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self.id_ == 1: # Left-click
|
||||||
|
self.remove()
|
||||||
|
elif self.id_ == 2: # Right-click
|
||||||
|
self.add()
|
||||||
|
|
||||||
|
class ShiftGrid(QUndoCommand):
|
||||||
|
def __init__(self, comp, direction):
|
||||||
|
super().__init__(
|
||||||
|
"change %s component #%s" % (comp.name, comp.compPos))
|
||||||
|
self.comp = comp
|
||||||
|
self.direction = direction
|
||||||
|
self.distance = 1
|
||||||
|
|
||||||
|
def id(self):
|
||||||
|
return self.direction
|
||||||
|
|
||||||
|
def mergeWith(self, other):
|
||||||
|
self.distance += other.distance
|
||||||
|
return True
|
||||||
|
|
||||||
|
def newGrid(self, Xchange, Ychange):
|
||||||
|
return {
|
||||||
|
(x + Xchange, y + Ychange)
|
||||||
|
for x, y in self.comp.startingGrid
|
||||||
|
}
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self.direction == 0:
|
||||||
|
newGrid = self.newGrid(0, -self.distance)
|
||||||
|
elif self.direction == 1:
|
||||||
|
newGrid = self.newGrid(0, self.distance)
|
||||||
|
elif self.direction == 2:
|
||||||
|
newGrid = self.newGrid(-self.distance, 0)
|
||||||
|
elif self.direction == 3:
|
||||||
|
newGrid = self.newGrid(self.distance, 0)
|
||||||
|
self.comp.startingGrid = newGrid
|
||||||
|
self.comp._sendUpdateSignal()
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self.direction == 0:
|
||||||
|
newGrid = self.newGrid(0, self.distance)
|
||||||
|
elif self.direction == 1:
|
||||||
|
newGrid = self.newGrid(0, -self.distance)
|
||||||
|
elif self.direction == 2:
|
||||||
|
newGrid = self.newGrid(self.distance, 0)
|
||||||
|
elif self.direction == 3:
|
||||||
|
newGrid = self.newGrid(-self.distance, 0)
|
||||||
|
self.comp.startingGrid = newGrid
|
||||||
|
self.comp._sendUpdateSignal()
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
log = logging.getLogger('AVP.Gui.PreviewWindow')
|
||||||
|
|
||||||
|
|
||||||
class PreviewWindow(QtWidgets.QLabel):
|
class PreviewWindow(QtWidgets.QLabel):
|
||||||
'''
|
'''
|
||||||
Paints the preview QLabel in MainWindow and maintains the aspect ratio
|
Paints the preview QLabel in MainWindow and maintains the aspect ratio
|
||||||
when the window is resized.
|
when the window is resized.
|
||||||
'''
|
'''
|
||||||
log = logging.getLogger('AVP.Gui.PreviewWindow')
|
|
||||||
|
|
||||||
def __init__(self, parent, img):
|
def __init__(self, parent, img):
|
||||||
super(PreviewWindow, self).__init__()
|
super(PreviewWindow, self).__init__()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
@ -41,17 +41,15 @@ class PreviewWindow(QtWidgets.QLabel):
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
component = self.parent.core.selectedComponents[i]
|
component = self.parent.core.selectedComponents[i]
|
||||||
if not hasattr(component, 'previewClickEvent'):
|
if not hasattr(component, 'previewClickEvent'):
|
||||||
self.log.info('Ignored click event')
|
|
||||||
return
|
return
|
||||||
pos = (event.x(), event.y())
|
pos = (event.x(), event.y())
|
||||||
size = (self.width(), self.height())
|
size = (self.width(), self.height())
|
||||||
butt = event.button()
|
butt = event.button()
|
||||||
self.log.info('Click event for #%s: %s button %s' % (
|
log.info('Click event for #%s: %s button %s' % (
|
||||||
i, pos, butt))
|
i, pos, butt))
|
||||||
component.previewClickEvent(
|
component.previewClickEvent(
|
||||||
pos, size, butt
|
pos, size, butt
|
||||||
)
|
)
|
||||||
self.parent.core.updateComponent(i)
|
|
||||||
|
|
||||||
@QtCore.pyqtSlot(str)
|
@QtCore.pyqtSlot(str)
|
||||||
def threadError(self, msg):
|
def threadError(self, msg):
|
||||||
|
|
Reference in New Issue