undoable Life component grid actions

This commit is contained in:
tassaron 2017-08-27 19:59:51 -04:00
parent 4a310ffb28
commit ad6dd9f532
2 changed files with 102 additions and 38 deletions

View File

@ -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()

View File

@ -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):