|
|
|
@ -320,6 +320,13 @@ public class ImageEditorModel: NSObject {
|
|
|
|
|
private var undoStack = [ImageEditorOperation]()
|
|
|
|
|
private var redoStack = [ImageEditorOperation]()
|
|
|
|
|
|
|
|
|
|
// In some cases, we want to suppress changes to undo state.
|
|
|
|
|
// e.g. drawing a stroke will modify the model many times (once
|
|
|
|
|
// for each touch event/stroke sample), but we only want that
|
|
|
|
|
// to add a single undo operation.
|
|
|
|
|
private var isUndoSuppressed = false
|
|
|
|
|
private var suppressedUndoContents: ImageEditorContents?
|
|
|
|
|
|
|
|
|
|
// We don't want to allow editing of images if:
|
|
|
|
|
//
|
|
|
|
|
// * They are invalid.
|
|
|
|
@ -365,6 +372,28 @@ public class ImageEditorModel: NSObject {
|
|
|
|
|
return !undoStack.isEmpty
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func setIsUndoSuppressed(isUndoSuppressed: Bool) {
|
|
|
|
|
if isUndoSuppressed {
|
|
|
|
|
if self.isUndoSuppressed {
|
|
|
|
|
owsFailDebug("Undo already suppressed.")
|
|
|
|
|
}
|
|
|
|
|
if suppressedUndoContents != nil {
|
|
|
|
|
owsFailDebug("Unexpected suppressed undo contents.")
|
|
|
|
|
}
|
|
|
|
|
suppressedUndoContents = contents.clone()
|
|
|
|
|
} else {
|
|
|
|
|
if self.isUndoSuppressed {
|
|
|
|
|
if suppressedUndoContents == nil {
|
|
|
|
|
owsFailDebug("Missing suppressed undo contents.")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
suppressedUndoContents = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.isUndoSuppressed = isUndoSuppressed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func canRedo() -> Bool {
|
|
|
|
|
return !redoStack.isEmpty
|
|
|
|
@ -402,29 +431,47 @@ public class ImageEditorModel: NSObject {
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func append(item: ImageEditorItem) {
|
|
|
|
|
performAction { (newContents) in
|
|
|
|
|
performAction({ (newContents) in
|
|
|
|
|
newContents.append(item: item)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func replace(item: ImageEditorItem) {
|
|
|
|
|
performAction { (newContents) in
|
|
|
|
|
public func replace(item: ImageEditorItem,
|
|
|
|
|
shouldRemoveUndoSuppression: Bool = false) {
|
|
|
|
|
performAction({ (newContents) in
|
|
|
|
|
newContents.replace(item: item)
|
|
|
|
|
}
|
|
|
|
|
}, shouldRemoveUndoSuppression: shouldRemoveUndoSuppression)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@objc
|
|
|
|
|
public func remove(item: ImageEditorItem) {
|
|
|
|
|
performAction { (newContents) in
|
|
|
|
|
performAction({ (newContents) in
|
|
|
|
|
newContents.remove(item: item)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private func performAction(action: (ImageEditorContents) -> Void) {
|
|
|
|
|
let undoOperation = ImageEditorOperation(contents: contents)
|
|
|
|
|
undoStack.append(undoOperation)
|
|
|
|
|
redoStack.removeAll()
|
|
|
|
|
private func performAction(_ action: (ImageEditorContents) -> Void,
|
|
|
|
|
shouldRemoveUndoSuppression: Bool = false) {
|
|
|
|
|
if shouldRemoveUndoSuppression {
|
|
|
|
|
if !isUndoSuppressed {
|
|
|
|
|
owsFailDebug("Can't remove undo suppression, not suppressed.")
|
|
|
|
|
}
|
|
|
|
|
if let suppressedUndoContents = self.suppressedUndoContents {
|
|
|
|
|
let undoOperation = ImageEditorOperation(contents: suppressedUndoContents)
|
|
|
|
|
undoStack.append(undoOperation)
|
|
|
|
|
redoStack.removeAll()
|
|
|
|
|
} else {
|
|
|
|
|
owsFailDebug("Missing suppressed undo contents.")
|
|
|
|
|
}
|
|
|
|
|
self.isUndoSuppressed = false
|
|
|
|
|
|
|
|
|
|
setIsUndoSuppressed(isUndoSuppressed: false)
|
|
|
|
|
} else if !isUndoSuppressed {
|
|
|
|
|
let undoOperation = ImageEditorOperation(contents: contents)
|
|
|
|
|
undoStack.append(undoOperation)
|
|
|
|
|
redoStack.removeAll()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let newContents = contents.clone()
|
|
|
|
|
action(newContents)
|
|
|
|
|