mirror of
https://github.com/lalbornoz/roar.git
synced 2024-11-22 23:36:36 +00:00
Implements automatic snapshotting & restoring from snapshots.
This commit is contained in:
parent
f428daa9e0
commit
c4e78cb241
@ -20,7 +20,6 @@
|
|||||||
Release roadmap:
|
Release roadmap:
|
||||||
1) {copy,cut,delete,insert from,paste}, edit asset in new canvas, import from {canvas,object}
|
1) {copy,cut,delete,insert from,paste}, edit asset in new canvas, import from {canvas,object}
|
||||||
2) operators: crop, scale, shift, slice
|
2) operators: crop, scale, shift, slice
|
||||||
3) auto{load,save} & {backup,restore}
|
3) tools: unicode block elements
|
||||||
4) tools: unicode block elements
|
|
||||||
|
|
||||||
vim:ff=dos tw=0
|
vim:ff=dos tw=0
|
||||||
|
@ -79,6 +79,9 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||||||
if "dirty" in self.lastPanelState \
|
if "dirty" in self.lastPanelState \
|
||||||
and self.lastPanelState["dirty"]:
|
and self.lastPanelState["dirty"]:
|
||||||
textItems.append("*")
|
textItems.append("*")
|
||||||
|
if "backupStatus" in self.lastPanelState \
|
||||||
|
and self.lastPanelState["backupStatus"] == True:
|
||||||
|
textItems.append("Saving backup...")
|
||||||
self.parentFrame.statusBar.SetStatusText(" | ".join(textItems))
|
self.parentFrame.statusBar.SetStatusText(" | ".join(textItems))
|
||||||
if ("undoInhibit" in self.lastPanelState) \
|
if ("undoInhibit" in self.lastPanelState) \
|
||||||
and (self.lastPanelState["undoInhibit"]):
|
and (self.lastPanelState["undoInhibit"]):
|
||||||
|
@ -18,10 +18,10 @@ except ImportError:
|
|||||||
|
|
||||||
from GuiFrame import GuiCommandDecorator, GuiSubMenuDecorator, NID_MENU_SEP
|
from GuiFrame import GuiCommandDecorator, GuiSubMenuDecorator, NID_MENU_SEP
|
||||||
from RtlPlatform import getLocalConfPathName
|
from RtlPlatform import getLocalConfPathName
|
||||||
import io, os, wx
|
import datetime, io, os, stat, wx
|
||||||
|
|
||||||
class RoarCanvasCommandsFile():
|
class RoarCanvasCommandsFile():
|
||||||
def _import(self, f, newDirty, pathName):
|
def _import(self, f, newDirty, pathName, emptyPathName=False):
|
||||||
rc = False
|
rc = False
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||||
try:
|
try:
|
||||||
@ -29,7 +29,11 @@ class RoarCanvasCommandsFile():
|
|||||||
if rc:
|
if rc:
|
||||||
self.parentCanvas.update(newSize, False, newMap, dirty=newDirty)
|
self.parentCanvas.update(newSize, False, newMap, dirty=newDirty)
|
||||||
self.parentCanvas.dirty = newDirty
|
self.parentCanvas.dirty = newDirty
|
||||||
self.canvasPathName = newPathName
|
if not emptyPathName:
|
||||||
|
self.canvasPathName = newPathName
|
||||||
|
else:
|
||||||
|
self.canvasPathName = None
|
||||||
|
self.parentCanvas._snapshotsReset()
|
||||||
self.update(dirty=self.parentCanvas.dirty, pathName=self.canvasPathName, undoLevel=-1)
|
self.update(dirty=self.parentCanvas.dirty, pathName=self.canvasPathName, undoLevel=-1)
|
||||||
self.parentCanvas.canvas.journal.resetCursor()
|
self.parentCanvas.canvas.journal.resetCursor()
|
||||||
self.parentCanvas.canvas.journal.resetUndo()
|
self.parentCanvas.canvas.journal.resetUndo()
|
||||||
@ -41,7 +45,7 @@ class RoarCanvasCommandsFile():
|
|||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
||||||
return rc, newPathName
|
return rc, newPathName
|
||||||
|
|
||||||
def _importFile(self, f, newDirty, wildcard):
|
def _importFile(self, f, newDirty, wildcard, emptyPathName=False):
|
||||||
with wx.FileDialog(self.parentCanvas, "Open...", os.getcwd(), "", wildcard, wx.FD_OPEN) as dialog:
|
with wx.FileDialog(self.parentCanvas, "Open...", os.getcwd(), "", wildcard, wx.FD_OPEN) as dialog:
|
||||||
if self.lastDir != None:
|
if self.lastDir != None:
|
||||||
dialog.SetDirectory(self.lastDir)
|
dialog.SetDirectory(self.lastDir)
|
||||||
@ -49,7 +53,7 @@ class RoarCanvasCommandsFile():
|
|||||||
return False, None
|
return False, None
|
||||||
elif self._promptSaveChanges():
|
elif self._promptSaveChanges():
|
||||||
pathName = dialog.GetPath(); self.lastDir = os.path.dirname(pathName); self._storeLastDir(self.lastDir);
|
pathName = dialog.GetPath(); self.lastDir = os.path.dirname(pathName); self._storeLastDir(self.lastDir);
|
||||||
return self._import(f, newDirty, pathName)
|
return self._import(f, newDirty, pathName, emptyPathName=emptyPathName)
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
def _loadLastDir(self):
|
def _loadLastDir(self):
|
||||||
@ -65,6 +69,11 @@ class RoarCanvasCommandsFile():
|
|||||||
for lastFile in inFile.readlines():
|
for lastFile in inFile.readlines():
|
||||||
self._pushRecent(lastFile.rstrip("\r\n"), False)
|
self._pushRecent(lastFile.rstrip("\r\n"), False)
|
||||||
|
|
||||||
|
def _popSnapshot(self, pathName):
|
||||||
|
if pathName in self.snapshots.keys():
|
||||||
|
self.canvasRestore.attrDict["menu"].Delete(self.snapshots[pathName]["menuItemId"])
|
||||||
|
del self.snapshots[pathName]
|
||||||
|
|
||||||
def _promptSaveChanges(self):
|
def _promptSaveChanges(self):
|
||||||
if self.parentCanvas.dirty:
|
if self.parentCanvas.dirty:
|
||||||
message = "Do you want to save changes to {}?".format(self.canvasPathName if self.canvasPathName != None else "(Untitled)")
|
message = "Do you want to save changes to {}?".format(self.canvasPathName if self.canvasPathName != None else "(Untitled)")
|
||||||
@ -88,7 +97,7 @@ class RoarCanvasCommandsFile():
|
|||||||
if (numLastFiles + 1) > 8:
|
if (numLastFiles + 1) > 8:
|
||||||
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[0]["menuItemId"])
|
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[0]["menuItemId"])
|
||||||
del self.lastFiles[0]
|
del self.lastFiles[0]
|
||||||
menuItemWindow = self.canvasOpenRecent.attrDict["menu"].Insert(self.canvasOpenRecent.attrDict["menu"].GetMenuItemCount() - 2, menuItemId, "{}".format(pathName), pathName)
|
menuItemWindow = self.canvasOpenRecent.attrDict["menu"].Insert(self.canvasOpenRecent.attrDict["menu"].GetMenuItemCount() - 2, menuItemId, pathName, pathName)
|
||||||
self.parentFrame.menuItemsById[self.canvasOpenRecent.attrDict["id"]].Enable(True)
|
self.parentFrame.menuItemsById[self.canvasOpenRecent.attrDict["id"]].Enable(True)
|
||||||
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasOpenRecent(event, pathName), menuItemWindow)
|
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasOpenRecent(event, pathName), menuItemWindow)
|
||||||
self.lastFiles += [{"menuItemId":menuItemId, "menuItemWindow":menuItemWindow, "pathName":pathName}]
|
self.lastFiles += [{"menuItemId":menuItemId, "menuItemWindow":menuItemWindow, "pathName":pathName}]
|
||||||
@ -98,6 +107,21 @@ class RoarCanvasCommandsFile():
|
|||||||
for lastFile in [l["pathName"] for l in self.lastFiles]:
|
for lastFile in [l["pathName"] for l in self.lastFiles]:
|
||||||
print(lastFile, file=outFile)
|
print(lastFile, file=outFile)
|
||||||
|
|
||||||
|
def _pushSnapshot(self, pathName):
|
||||||
|
menuItemId = wx.NewId()
|
||||||
|
if not (pathName in self.snapshots.keys()):
|
||||||
|
label = datetime.datetime.fromtimestamp(os.stat(pathName)[stat.ST_MTIME]).strftime("%c")
|
||||||
|
menuItemWindow = self.canvasRestore.attrDict["menu"].Insert(self.canvasRestore.attrDict["menu"].GetMenuItemCount() - 2, menuItemId, label)
|
||||||
|
self.parentFrame.menuItemsById[self.canvasRestore.attrDict["id"]].Enable(True)
|
||||||
|
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasRestore(event, pathName), menuItemWindow)
|
||||||
|
self.snapshots[pathName] = {"menuItemId":menuItemId, "menuItemWindow":menuItemWindow}
|
||||||
|
|
||||||
|
def _resetSnapshots(self):
|
||||||
|
for pathName in list(self.snapshots.keys()):
|
||||||
|
self._popSnapshot(pathName)
|
||||||
|
if self.canvasRestore.attrDict["id"] in self.parentFrame.menuItemsById:
|
||||||
|
self.parentFrame.menuItemsById[self.canvasRestore.attrDict["id"]].Enable(False)
|
||||||
|
|
||||||
def _storeLastDir(self, pathName):
|
def _storeLastDir(self, pathName):
|
||||||
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
||||||
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
||||||
@ -194,7 +218,7 @@ class RoarCanvasCommandsFile():
|
|||||||
def canvasImportAnsi_(pathName):
|
def canvasImportAnsi_(pathName):
|
||||||
rc, error = self.parentCanvas.canvas.importStore.importAnsiFile(pathName)
|
rc, error = self.parentCanvas.canvas.importStore.importAnsiFile(pathName)
|
||||||
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
||||||
self._importFile(canvasImportAnsi_, True, "ANSI files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*")
|
self._importFile(canvasImportAnsi_, True, "ANSI files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*", emptyPathName=True)
|
||||||
|
|
||||||
@GuiCommandDecorator("Import from clipboard", "Import from &clipboard", None, None, None)
|
@GuiCommandDecorator("Import from clipboard", "Import from &clipboard", None, None, None)
|
||||||
def canvasImportFromClipboard(self, event):
|
def canvasImportFromClipboard(self, event):
|
||||||
@ -209,15 +233,14 @@ class RoarCanvasCommandsFile():
|
|||||||
else:
|
else:
|
||||||
rc, error = False, "Clipboard does not contain text data and/or cannot be opened"
|
rc, error = False, "Clipboard does not contain text data and/or cannot be opened"
|
||||||
return (rc, error, self.parentCanvas.canvas.importStore.outMap, None, self.parentCanvas.canvas.importStore.inSize)
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, None, self.parentCanvas.canvas.importStore.inSize)
|
||||||
if self._promptSaveChanges():
|
self._import(canvasImportFromClipboard_, True, None, emptyPathName=True)
|
||||||
self._import(canvasImportFromClipboard_, True, None)
|
|
||||||
|
|
||||||
@GuiCommandDecorator("Import SAUCE...", "Import &SAUCE...", None, None, None)
|
@GuiCommandDecorator("Import SAUCE...", "Import &SAUCE...", None, None, None)
|
||||||
def canvasImportSauce(self, event):
|
def canvasImportSauce(self, event):
|
||||||
def canvasImportSauce_(pathName):
|
def canvasImportSauce_(pathName):
|
||||||
rc, error = self.parentCanvas.canvas.importStore.importSauceFile(pathName)
|
rc, error = self.parentCanvas.canvas.importStore.importSauceFile(pathName)
|
||||||
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
||||||
self._importFile(canvasImportSauce_, True, "SAUCE files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*")
|
self._importFile(canvasImportSauce_, True, "SAUCE files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*", emptyPathName=True)
|
||||||
|
|
||||||
@GuiCommandDecorator("New", "&New", ["", wx.ART_NEW], [wx.ACCEL_CTRL, ord("N")], None)
|
@GuiCommandDecorator("New", "&New", ["", wx.ART_NEW], [wx.ACCEL_CTRL, ord("N")], None)
|
||||||
def canvasNew(self, event, newCanvasSize=None):
|
def canvasNew(self, event, newCanvasSize=None):
|
||||||
@ -250,6 +273,22 @@ class RoarCanvasCommandsFile():
|
|||||||
numLastFile = [i for i in range(len(self.lastFiles)) if self.lastFiles[i]["pathName"] == pathName][0]
|
numLastFile = [i for i in range(len(self.lastFiles)) if self.lastFiles[i]["pathName"] == pathName][0]
|
||||||
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[numLastFile]["menuItemId"]); del self.lastFiles[numLastFile];
|
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[numLastFile]["menuItemId"]); del self.lastFiles[numLastFile];
|
||||||
|
|
||||||
|
@GuiSubMenuDecorator("Restore Snapshot", "Res&tore Snapshot", None, None, False)
|
||||||
|
def canvasRestore(self, event, pathName=None):
|
||||||
|
def canvasImportmIRC(pathName_):
|
||||||
|
rc, error = self.parentCanvas.canvas.importStore.importTextFile(pathName)
|
||||||
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, self.canvasPathName, self.parentCanvas.canvas.importStore.inSize)
|
||||||
|
if self._promptSaveChanges():
|
||||||
|
rc, newPathName = self._import(canvasImportmIRC, False, self.canvasPathName)
|
||||||
|
|
||||||
|
@GuiCommandDecorator("Restore from file", "Restore from &file", None, None, False)
|
||||||
|
def canvasRestoreFile(self, event):
|
||||||
|
def canvasImportmIRC(pathName):
|
||||||
|
rc, error = self.parentCanvas.canvas.importStore.importTextFile(pathName)
|
||||||
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
||||||
|
if self._promptSaveChanges():
|
||||||
|
rc, newPathName = self._import(canvasImportmIRC, False, self.canvasPathName)
|
||||||
|
|
||||||
@GuiCommandDecorator("Save", "&Save", ["", wx.ART_FILE_SAVE], [wx.ACCEL_CTRL, ord("S")], None)
|
@GuiCommandDecorator("Save", "&Save", ["", wx.ART_FILE_SAVE], [wx.ACCEL_CTRL, ord("S")], None)
|
||||||
def canvasSave(self, event, newDirty=False):
|
def canvasSave(self, event, newDirty=False):
|
||||||
if self.canvasPathName == None:
|
if self.canvasPathName == None:
|
||||||
@ -284,11 +323,11 @@ class RoarCanvasCommandsFile():
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.imgurApiKey, self.lastFiles, self.lastDir = ImgurApiKey.imgurApiKey if haveImgurApiKey else None, [], None
|
self.imgurApiKey, self.lastFiles, self.lastDir, self.snapshots = ImgurApiKey.imgurApiKey if haveImgurApiKey else None, [], None, {}
|
||||||
self.accels = ()
|
self.accels = ()
|
||||||
self.menus = (
|
self.menus = (
|
||||||
("&File",
|
("&File",
|
||||||
self.canvasNew, self.canvasOpen, self.canvasOpenRecent, self.canvasSave, self.canvasSaveAs, NID_MENU_SEP,
|
self.canvasNew, self.canvasOpen, self.canvasOpenRecent, self.canvasRestore, self.canvasSave, self.canvasSaveAs, NID_MENU_SEP,
|
||||||
("&Export...", self.canvasExportAsAnsi, self.canvasExportToClipboard, self.canvasExportImgur, self.canvasExportPastebin, self.canvasExportAsPng,),
|
("&Export...", self.canvasExportAsAnsi, self.canvasExportToClipboard, self.canvasExportImgur, self.canvasExportPastebin, self.canvasExportAsPng,),
|
||||||
("&Import...", self.canvasImportAnsi, self.canvasImportFromClipboard, self.canvasImportSauce,),
|
("&Import...", self.canvasImportAnsi, self.canvasImportFromClipboard, self.canvasImportSauce,),
|
||||||
NID_MENU_SEP,
|
NID_MENU_SEP,
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from GuiWindow import GuiWindow
|
from GuiWindow import GuiWindow
|
||||||
|
from Rtl import natural_sort
|
||||||
|
from RtlPlatform import getLocalConfPathName
|
||||||
from ToolObject import ToolObject
|
from ToolObject import ToolObject
|
||||||
from ToolText import ToolText
|
from ToolText import ToolText
|
||||||
import copy, json, wx, sys
|
import copy, hashlib, json, os, re, time, wx, sys
|
||||||
|
|
||||||
class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
||||||
def done(self):
|
def done(self):
|
||||||
@ -60,6 +62,50 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
self.commands.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
|
self.commands.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
|
||||||
|
|
||||||
|
def _snapshotsReset(self):
|
||||||
|
self._snapshotFiles, self._snapshotsUpdateLast = [], time.time()
|
||||||
|
self.commands._resetSnapshots()
|
||||||
|
if self.commands.canvasPathName != None:
|
||||||
|
canvasPathName = os.path.abspath(self.commands.canvasPathName)
|
||||||
|
canvasFileName = os.path.basename(canvasPathName)
|
||||||
|
canvasPathNameHash = hashlib.sha1(canvasPathName.encode()).hexdigest()
|
||||||
|
self._snapshotsDirName = os.path.join(getLocalConfPathName(), "{}_{}".format(canvasFileName, canvasPathNameHash))
|
||||||
|
if os.path.exists(self._snapshotsDirName):
|
||||||
|
for snapshotFile in natural_sort([f for f in os.listdir(self._snapshotsDirName) \
|
||||||
|
if (re.match(r'snapshot\d+\.txt$', f)) and os.path.isfile(os.path.join(self._snapshotsDirName, f))]):
|
||||||
|
self.commands._pushSnapshot(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||||
|
else:
|
||||||
|
self._snapshotsDirName = None
|
||||||
|
|
||||||
|
def _snapshotsUpdate(self):
|
||||||
|
if self._snapshotsDirName != None:
|
||||||
|
t = time.time()
|
||||||
|
if (t > self._snapshotsUpdateLast) and ((t - self._snapshotsUpdateLast) >= (5 * 60)):
|
||||||
|
try:
|
||||||
|
if not os.path.exists(self._snapshotsDirName):
|
||||||
|
os.makedirs(self._snapshotsDirName)
|
||||||
|
self._snapshotFiles = natural_sort([f for f in os.listdir(self._snapshotsDirName)
|
||||||
|
if (re.match(r'snapshot\d+\.txt$', f)) and os.path.isfile(os.path.join(self._snapshotsDirName, f))])
|
||||||
|
if self._snapshotFiles != []:
|
||||||
|
snapshotsCount, snapshotIndex = len(self._snapshotFiles), abs(int(re.match(r'snapshot(\d+)\.txt$', self._snapshotFiles[-1])[1])) + 1
|
||||||
|
else:
|
||||||
|
snapshotsCount, snapshotIndex = 0, 1
|
||||||
|
snapshotPathName = os.path.join(self._snapshotsDirName, "snapshot{}.txt".format(snapshotIndex));
|
||||||
|
self.commands.update(snapshotStatus=True)
|
||||||
|
with open(snapshotPathName, "w", encoding="utf-8") as outFile:
|
||||||
|
self.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||||
|
self.canvas.exportStore.exportTextFile(self.canvas.map, self.canvas.size, outFile)
|
||||||
|
self.SetCursor(wx.Cursor(wx.NullCursor))
|
||||||
|
self.commands.update(snapshotStatus=False); self._snapshotsUpdateLast = time.time();
|
||||||
|
self._snapshotFiles += [os.path.basename(snapshotPathName)];
|
||||||
|
self.commands._pushSnapshot(snapshotPathName)
|
||||||
|
if len(self._snapshotFiles) > 72:
|
||||||
|
for snapshotFile in self._snapshotFiles[:len(self._snapshotFiles) - 8]:
|
||||||
|
self.commands._popSnapshot(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||||
|
os.remove(os.path.join(self._snapshotsDirName, snapshotFile)); snapshotsCount -= 1;
|
||||||
|
except:
|
||||||
|
print("Exception during _snapshotsUpdate(): {}".format(sys.exc_info()[1]))
|
||||||
|
|
||||||
def applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect):
|
def applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect):
|
||||||
eventDc, patches, patchesCursor, rc = self.backend.getDeviceContext(self.GetClientSize(), self), None, None, True
|
eventDc, patches, patchesCursor, rc = self.backend.getDeviceContext(self.GetClientSize(), self), None, None, True
|
||||||
if (currentTool.__class__ == ToolObject) and (currentTool.toolState >= currentTool.TS_SELECT):
|
if (currentTool.__class__ == ToolObject) and (currentTool.toolState >= currentTool.TS_SELECT):
|
||||||
@ -81,16 +127,19 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
rc, patches, patchesCursor = currentTool.onSelectEvent(self.canvas, (0, 0), True, wx.MOD_NONE, None, currentTool.targetRect)
|
rc, patches, patchesCursor = currentTool.onSelectEvent(self.canvas, (0, 0), True, wx.MOD_NONE, None, currentTool.targetRect)
|
||||||
patchesCursor = [] if patchesCursor == None else patchesCursor
|
patchesCursor = [] if patchesCursor == None else patchesCursor
|
||||||
patchesCursor += currentTool._drawSelectRect(currentTool.targetRect)
|
patchesCursor += currentTool._drawSelectRect(currentTool.targetRect)
|
||||||
|
self._applyPatches(eventDc, patches, patchesCursor, rc)
|
||||||
else:
|
else:
|
||||||
patches = []
|
patches = []
|
||||||
for numRow in range(len(region)):
|
for numRow in range(len(region)):
|
||||||
for numCol in range(len(region[numRow])):
|
for numCol in range(len(region[numRow])):
|
||||||
patches += [[numCol, numRow, *region[numRow][numCol]]]
|
patches += [[numCol, numRow, *region[numRow][numCol]]]
|
||||||
self._applyPatches(eventDc, patches, patchesCursor, rc)
|
self._applyPatches(eventDc, patches, patchesCursor, rc)
|
||||||
|
if (patches != None) and (len(patches) > 0):
|
||||||
|
self._snapshotsUpdate()
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect, force=False):
|
def applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect, force=False):
|
||||||
dirty, patches, patchesCursor, rc = False, None, None, False
|
patches, patchesCursor, rc = None, None, False
|
||||||
if eventMouse:
|
if eventMouse:
|
||||||
self.lastCellState = None if force else self.lastCellState
|
self.lastCellState = None if force else self.lastCellState
|
||||||
if ((mapPoint[0] < self.canvas.size[0]) and (mapPoint[1] < self.canvas.size[1])) \
|
if ((mapPoint[0] < self.canvas.size[0]) and (mapPoint[1] < self.canvas.size[1])) \
|
||||||
@ -118,6 +167,8 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
self.commands.update(toolName=newToolName, undoInhibit=False)
|
self.commands.update(toolName=newToolName, undoInhibit=False)
|
||||||
else:
|
else:
|
||||||
self.commands.update(undoInhibit=False)
|
self.commands.update(undoInhibit=False)
|
||||||
|
if (patches != None) and (len(patches) > 0):
|
||||||
|
self._snapshotsUpdate()
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def onKeyboardInput(self, event):
|
def onKeyboardInput(self, event):
|
||||||
@ -237,6 +288,8 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
self.Scroll(*viewRect); self.dirty = dirty;
|
self.Scroll(*viewRect); self.dirty = dirty;
|
||||||
self.commands.update(dirty=self.dirty, size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel)
|
self.commands.update(dirty=self.dirty, size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel)
|
||||||
|
if commitUndo:
|
||||||
|
self._snapshotsUpdate()
|
||||||
|
|
||||||
def undo(self, redo=False):
|
def undo(self, redo=False):
|
||||||
deltaPatches = self.canvas.journal.popUndo() if not redo else self.canvas.journal.popRedo()
|
deltaPatches = self.canvas.journal.popUndo() if not redo else self.canvas.journal.popRedo()
|
||||||
@ -276,5 +329,6 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
self.dropTarget = RoarCanvasWindowDropTarget(self)
|
self.dropTarget = RoarCanvasWindowDropTarget(self)
|
||||||
self.SetDropTarget(self.dropTarget)
|
self.SetDropTarget(self.dropTarget)
|
||||||
self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
|
self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
|
||||||
|
self._snapshotsReset()
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
||||||
|
@ -62,10 +62,15 @@ class RoarClient(GuiFrame):
|
|||||||
for menuItem in self.canvasPanel.commands.menus[3][1:]:
|
for menuItem in self.canvasPanel.commands.menus[3][1:]:
|
||||||
menuItemWindow = self.canvasPanel.operatorsMenu.Append(menuItem.attrDict["id"], menuItem.attrDict["label"], menuItem.attrDict["caption"])
|
menuItemWindow = self.canvasPanel.operatorsMenu.Append(menuItem.attrDict["id"], menuItem.attrDict["label"], menuItem.attrDict["caption"])
|
||||||
self.Bind(wx.EVT_MENU, self.onMenu, menuItemWindow)
|
self.Bind(wx.EVT_MENU, self.onMenu, menuItemWindow)
|
||||||
self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].AppendSeparator()
|
|
||||||
self.canvasPanel.commands.canvasClearRecent.attrDict["id"] = wx.NewId()
|
self.canvasPanel.commands.canvasClearRecent.attrDict["id"] = wx.NewId()
|
||||||
|
self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].AppendSeparator()
|
||||||
|
self.canvasPanel.commands.canvasRestore.attrDict["menu"].AppendSeparator()
|
||||||
|
self.canvasPanel.commands.canvasRestoreFile.attrDict["id"] = wx.NewId()
|
||||||
menuItemWindow = self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Append(self.canvasPanel.commands.canvasClearRecent.attrDict["id"], self.canvasPanel.commands.canvasClearRecent.attrDict["label"], self.canvasPanel.commands.canvasClearRecent.attrDict["caption"])
|
menuItemWindow = self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Append(self.canvasPanel.commands.canvasClearRecent.attrDict["id"], self.canvasPanel.commands.canvasClearRecent.attrDict["label"], self.canvasPanel.commands.canvasClearRecent.attrDict["caption"])
|
||||||
|
menuItemWindow = self.canvasPanel.commands.canvasRestore.attrDict["menu"].Append(self.canvasPanel.commands.canvasRestoreFile.attrDict["id"], self.canvasPanel.commands.canvasRestoreFile.attrDict["label"], self.canvasPanel.commands.canvasRestoreFile.attrDict["caption"])
|
||||||
self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Bind(wx.EVT_MENU, self.canvasPanel.commands.canvasClearRecent, menuItemWindow)
|
self.canvasPanel.commands.canvasOpenRecent.attrDict["menu"].Bind(wx.EVT_MENU, self.canvasPanel.commands.canvasClearRecent, menuItemWindow)
|
||||||
|
self.canvasPanel.commands.canvasRestore.attrDict["menu"].Bind(wx.EVT_MENU, self.canvasPanel.commands.canvasRestoreFile, menuItemWindow)
|
||||||
self.Bind(wx.EVT_CLOSE, self.onClose); self.Bind(wx.EVT_SIZE, self.onSize);
|
self.Bind(wx.EVT_CLOSE, self.onClose); self.Bind(wx.EVT_SIZE, self.onSize);
|
||||||
self.toolBarPanes[0].BestSize(0, 0).Right(); self.toolBarPanes[1].BestSize(0, 0).Right(); self.auiManager.Update();
|
self.toolBarPanes[0].BestSize(0, 0).Right(); self.toolBarPanes[1].BestSize(0, 0).Right(); self.auiManager.Update();
|
||||||
|
|
||||||
|
@ -5,13 +5,18 @@
|
|||||||
# This project is licensed under the terms of the MIT licence.
|
# This project is licensed under the terms of the MIT licence.
|
||||||
#
|
#
|
||||||
|
|
||||||
import statistics, time
|
import re, statistics, time
|
||||||
|
|
||||||
timeState = [None, None, 0, []]
|
timeState = [None, None, 0, []]
|
||||||
|
|
||||||
def flatten(l):
|
def flatten(l):
|
||||||
return [li for l_ in l for li in l_]
|
return [li for l_ in l for li in l_]
|
||||||
|
|
||||||
|
def natural_sort(l):
|
||||||
|
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
||||||
|
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
||||||
|
return sorted(l, key=alphanum_key)
|
||||||
|
|
||||||
def timePrint(pfx):
|
def timePrint(pfx):
|
||||||
timeState[0] = time.time() if timeState[0] == None else timeState[0]
|
timeState[0] = time.time() if timeState[0] == None else timeState[0]
|
||||||
t1 = time.time(); td = t1 - timeState[0]
|
t1 = time.time(); td = t1 - timeState[0]
|
||||||
|
1
roar.py
1
roar.py
@ -25,6 +25,7 @@ def main(*argv):
|
|||||||
if (len(argv) >= 2) and (argv[1].endswith(".lst")):
|
if (len(argv) >= 2) and (argv[1].endswith(".lst")):
|
||||||
roarClient.assetsWindow._load_list(argv[1])
|
roarClient.assetsWindow._load_list(argv[1])
|
||||||
roarClient.canvasPanel.commands.canvasPathName = argv[0]
|
roarClient.canvasPanel.commands.canvasPathName = argv[0]
|
||||||
|
roarClient.canvasPanel._snapshotsReset()
|
||||||
rc, error = roarClient.canvasPanel.canvas.importStore.importTextFile(argv[0])
|
rc, error = roarClient.canvasPanel.canvas.importStore.importTextFile(argv[0])
|
||||||
if rc:
|
if rc:
|
||||||
roarClient.canvasPanel.update(roarClient.canvasPanel.canvas.importStore.inSize, False, roarClient.canvasPanel.canvas.importStore.outMap, dirty=False)
|
roarClient.canvasPanel.update(roarClient.canvasPanel.canvas.importStore.inSize, False, roarClient.canvasPanel.canvas.importStore.outMap, dirty=False)
|
||||||
|
Loading…
Reference in New Issue
Block a user