Implements automatic snapshotting & restoring from snapshots.

This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-28 19:45:45 +02:00
parent f428daa9e0
commit c4e78cb241
7 changed files with 125 additions and 19 deletions

View File

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

View File

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

View File

@ -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,

View File

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

View File

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

View File

@ -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]

View File

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