Initial release w/ circle, line, rectangle, and text tools.

This commit is contained in:
Lucio Andrés Illanes Albornoz 2018-01-09 00:21:43 +01:00
parent 2a7f281d29
commit 38e90f96ca
8 changed files with 413 additions and 290 deletions

View File

@ -22,6 +22,7 @@
# SOFTWARE. # SOFTWARE.
# #
from MiRCARTCanvasBackend import MiRCARTCanvasBackend
from MiRCARTCanvasJournal import MiRCARTCanvasJournal from MiRCARTCanvasJournal import MiRCARTCanvasJournal
from MiRCARTCanvasStore import MiRCARTCanvasStore, haveMiRCARTToPngFile, haveUrllib from MiRCARTCanvasStore import MiRCARTCanvasStore, haveMiRCARTToPngFile, haveUrllib
from MiRCARTColours import MiRCARTColours from MiRCARTColours import MiRCARTColours
@ -30,208 +31,168 @@ import wx
class MiRCARTCanvas(wx.Panel): class MiRCARTCanvas(wx.Panel):
"""XXX""" """XXX"""
parentFrame = None parentFrame = None
canvasPos = canvasSize = canvasWinSize = cellSize = None canvasMap = canvasPos = canvasSize = None
canvasBitmap = canvasMap = None
brushColours = brushPos = brushSize = None brushColours = brushPos = brushSize = None
mircBrushes = mircPens = None canvasBackend = canvasCurTool = canvasJournal = canvasStore = None
canvasJournal = canvasStore = None
canvasCurTool = None
# {{{ _initBrushesAndPens(self): XXX # {{{ _commitPatch(self, patch):
def _initBrushesAndPens(self): def _commitPatch(self, patch):
self.mircBrushes = [None for x in range(len(MiRCARTColours))] self.canvasMap[patch[0][1]][patch[0][0]] = patch[1:]
self.mircPens = [None for x in range(len(MiRCARTColours))]
for mircColour in range(len(MiRCARTColours)):
self.mircBrushes[mircColour] = wx.Brush( \
wx.Colour(MiRCARTColours[mircColour][0:4]), wx.BRUSHSTYLE_SOLID)
self.mircPens[mircColour] = wx.Pen( \
wx.Colour(MiRCARTColours[mircColour][0:4]), 1)
# }}} # }}}
# {{{ _drawPatch(self, patch, eventDc, tmpDc, atPoint): XXX # {{{ _dispatchInput(self, eventDc, patches, tmpDc): XXX
def _drawPatch(self, patch, eventDc, tmpDc, atPoint): def _dispatchInput(self, eventDc, patches, tmpDc):
absPoint = self._relMapPointToAbsPoint(patch[0], atPoint) self.canvasBackend.drawCursorMaskWithJournal( \
if patch[3] == " ": self.canvasJournal, eventDc, tmpDc)
brushFg = self.mircBrushes[patch[1][1]] cursorPatches = []; undoPatches = []; newPatches = [];
brushBg = self.mircBrushes[patch[1][0]] for patchDescr in patches:
pen = self.mircPens[patch[1][1]] patchIsCursor = patchDescr[0]
for patch in patchDescr[1]:
if self.canvasBackend.drawPatch(eventDc, patch, tmpDc) == False:
continue
else: else:
brushFg = self.mircBrushes[patch[1][0]] patchDeltaCell = self.canvasMap[patch[0][1]][patch[0][0]]
brushBg = self.mircBrushes[patch[1][1]] if patchIsCursor == True:
pen = self.mircPens[patch[1][0]] cursorPatches.append([list(patch[0]), *patchDeltaCell.copy()])
for dc in (eventDc, tmpDc): else:
dc.SetBrush(brushFg); dc.SetBackground(brushBg); dc.SetPen(pen); undoPatches.append([list(patch[0]), *patchDeltaCell.copy()])
dc.DrawRectangle(*absPoint, *self.cellSize) newPatches.append(patch)
# }}} self._commitPatch(patch)
# {{{ _eventPointToMapPoint(self, eventPoint): XXX if len(cursorPatches):
def _eventPointToMapPoint(self, eventPoint): self.canvasJournal.pushCursor(cursorPatches)
rectX = eventPoint.x - (eventPoint.x % self.cellSize[0]) if len(undoPatches):
rectY = eventPoint.y - (eventPoint.y % self.cellSize[1]) self.canvasJournal.pushDeltas(undoPatches, newPatches)
mapX = int(rectX / self.cellSize[0] if rectX else 0)
mapY = int(rectY / self.cellSize[1] if rectY else 0)
return (mapX, mapY)
# }}}
# {{{ _getMapCell(self, absMapPoint): XXX
def _getMapCell(self, absMapPoint):
return self.canvasMap[absMapPoint[1]][absMapPoint[0]]
# }}}
# {{{ _relMapPointToAbsPoint(self, relMapPoint, atPoint): XXX
def _relMapPointToAbsPoint(self, relMapPoint, atPoint):
return [(a+b)*c for a,b,c in zip(atPoint, relMapPoint, self.cellSize)]
# }}}
# {{{ _setMapCell(self, absMapPoint, colours, charAttrs, char): XXX
def _setMapCell(self, absMapPoint, colours, charAttrs, char):
self.canvasMap[absMapPoint[1]][absMapPoint[0]] = [colours, charAttrs, char]
# }}} # }}}
# {{{ onClose(self, event): XXX # {{{ onPanelClose(self, event): XXX
def onClose(self, event): def onPanelClose(self, event):
self.Destroy(); self.__del__(); self.Destroy()
# }}} # }}}
# {{{ onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): # {{{ onPanelKeyboardInput(self, event): XXX
def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint, isInherit=False): def onPanelKeyboardInput(self, event):
if eventDc == None: eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self)
eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); tool = self.canvasCurTool; mapPoint = self.brushPos;
if tmpDc == None: if event.GetModifiers() != wx.MOD_NONE:
tmpDc.SelectObject(self.canvasBitmap) event.Skip()
if isTmp == True:
if isInherit:
patch[1:] = self._getMapCell(patch[0])
self._drawPatch(patch, eventDc, tmpDc, atPoint)
else: else:
if isInherit: patches = tool.onKeyboardEvent( \
patchOld = patch.copy() event, mapPoint, self.brushColours, self.brushSize, \
patchOld[1:] = self._getMapCell(patchOld[0]) chr(event.GetUnicodeKey()))
self._setMapCell(absMapPoint, *patch[1:]) if len(patches):
self._drawPatch(patch, eventDc, tmpDc, atPoint) self._dispatchInput(eventDc, patches, tmpDc)
if isInherit: self.parentFrame.onCanvasUpdate()
return patchOld
# }}} # }}}
# {{{ onMouseEvent(self, event): XXX # {{{ onPanelMouseInput(self, event): XXX
def onMouseEvent(self, event): def onPanelMouseInput(self, event):
eventObject = event.GetEventObject() eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self)
eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC();
tmpDc.SelectObject(self.canvasBitmap)
eventPoint = event.GetLogicalPosition(eventDc)
mapPoint = self._eventPointToMapPoint(eventPoint)
tool = self.canvasCurTool tool = self.canvasCurTool
mapPatches = tool.onMouseEvent( \ self.brushPos = mapPoint = \
self.canvasBackend.xlateEventPoint(event, eventDc)
patches = tool.onMouseEvent( \
event, mapPoint, self.brushColours, self.brushSize, \ event, mapPoint, self.brushColours, self.brushSize, \
event.Dragging(), event.LeftIsDown(), event.RightIsDown()) event.Dragging(), event.LeftIsDown(), event.RightIsDown())
self.canvasJournal.merge(mapPatches, eventDc, tmpDc, mapPoint) if len(patches):
self._dispatchInput(eventDc, patches, tmpDc)
self.parentFrame.onCanvasUpdate() self.parentFrame.onCanvasUpdate()
self.parentFrame.onCanvasMotion(event, mapPoint) self.parentFrame.onCanvasMotion(event, mapPoint)
# }}} # }}}
# {{{ onMouseWindowEvent(self, event): XXX # {{{ onPanelFocus(self, event): XXX
def onMouseWindowEvent(self, event): def onPanelFocus(self, event):
eventObject = event.GetEventObject() if event.GetEventType() == wx.wxEVT_LEAVE_WINDOW:
eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); eventDc, tmpDc = \
tmpDc.SelectObject(self.canvasBitmap) self.canvasBackend.getDeviceContexts(self)
self.canvasJournal.resetCursor(eventDc, tmpDc) self.canvasBackend.drawCursorMaskWithJournal( \
self.canvasJournal, eventDc, tmpDc)
self.parentFrame.onCanvasMotion(event) self.parentFrame.onCanvasMotion(event)
# }}} # }}}
# {{{ onPaint(self, event): XXX # {{{ onPanelPaint(self, event): XXX
def onPaint(self, event): def onPanelPaint(self, event):
eventDc = wx.BufferedPaintDC(self, self.canvasBitmap) if self.canvasBackend.canvasBitmap != None:
eventDc = wx.BufferedPaintDC(self, self.canvasBackend.canvasBitmap)
# }}} # }}}
# {{{ onStoreUpdate(self, newCanvasSize, newCanvas=None): # {{{ onStoreUpdate(self, newCanvasSize, newCanvas=None):
def onStoreUpdate(self, newCanvasSize, newCanvas=None): def onStoreUpdate(self, newCanvasSize, newCanvas=None):
if newCanvasSize != None: self.resize(newCanvasSize=newCanvasSize)
self.resize(newCanvasSize) self.canvasBackend.reset(self.canvasSize, self.canvasBackend.cellSize)
self.canvasJournal.reset() self.canvasJournal.resetCursor(); self.canvasJournal.resetUndo();
if newCanvas != None:
self.canvasMap = newCanvas.copy()
for numRow in range(self.canvasSize[1]):
numRowCols = len(self.canvasMap[numRow])
if numRowCols < self.canvasSize[0]:
colsDelta = self.canvasSize[0] - numRowCols
self.canvasMap[numRow][self.canvasSize[0]:] = \
[[(1, 1), 0, " "] for y in range(colsDelta)]
else:
del self.canvasMap[numRow][self.canvasSize[0]:]
else:
self.canvasMap = [[[(1, 1), 0, " "] \ self.canvasMap = [[[(1, 1), 0, " "] \
for x in range(self.canvasSize[0])] \ for x in range(self.canvasSize[0])] \
for y in range(self.canvasSize[1])] for y in range(self.canvasSize[1])]
canvasWinSize = [a*b for a,b in zip(self.canvasSize, self.cellSize)] eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self)
if self.canvasBitmap != None:
self.canvasBitmap.Destroy()
self.canvasBitmap = wx.Bitmap(canvasWinSize)
eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC();
tmpDc.SelectObject(self.canvasBitmap)
for numRow in range(self.canvasSize[1]): for numRow in range(self.canvasSize[1]):
for numCol in range(self.canvasSize[0]): for numCol in range(self.canvasSize[0]):
self.onJournalUpdate(False, \ if newCanvas != None \
(numCol, numRow), \ and numRow < len(newCanvas) \
[(numCol, numRow), \ and numCol < len(newCanvas[numRow]):
*self.canvasMap[numRow][numCol]], \ self._commitPatch([ \
eventDc, tmpDc, (0, 0)) [numCol, numRow], *newCanvas[numRow][numCol]])
self.canvasBackend.drawPatch(eventDc, \
([numCol, numRow], \
*self.canvasMap[numRow][numCol]), tmpDc)
wx.SafeYield() wx.SafeYield()
# }}} # }}}
# {{{ redo(self): XXX # {{{ popRedo(self):
def redo(self): def popRedo(self):
result = self.canvasJournal.redo() eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self)
patches = self.canvasJournal.popRedo()
for patch in patches:
if self.canvasBackend.drawPatch(eventDc, patch, tmpDc) == False:
continue
else:
self._commitPatch(patch)
self.parentFrame.onCanvasUpdate() self.parentFrame.onCanvasUpdate()
return result
# }}} # }}}
# {{{ resize(self, newCanvasSize): XXX # {{{ popUndo(self):
def popUndo(self):
eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self)
patches = self.canvasJournal.popUndo()
for patch in patches:
if self.canvasBackend.drawPatch(eventDc, patch, tmpDc) == False:
continue
else:
self._commitPatch(patch)
self.parentFrame.onCanvasUpdate()
# }}}
# {{{ resize(self, newCanvasSize):
def resize(self, newCanvasSize): def resize(self, newCanvasSize):
if newCanvasSize != self.canvasSize: if newCanvasSize != self.canvasSize:
self.SetSize(*self.canvasPos, \ winSize = [a*b for a,b in \
newCanvasSize[0] * self.cellSize[0], \ zip(newCanvasSize, self.canvasBackend.cellSize)]
newCanvasSize[1] * self.cellSize[1]) self.SetSize(*self.canvasPos, *winSize)
for numRow in range(self.canvasSize[1]): for numRow in range(self.canvasSize[1]):
for numNewCol in range(self.canvasSize[0], newCanvasSize[0]): for numNewCol in range(self.canvasSize[0], newCanvasSize[0]):
self.canvasMap[numRow].append([1, 1, " "]) self.canvasMap[numRow].append([[1, 1], 0, " "])
for numNewRow in range(self.canvasSize[1], newCanvasSize[1]): for numNewRow in range(self.canvasSize[1], newCanvasSize[1]):
self.canvasMap.append([]) self.canvasMap.append([])
for numNewCol in range(newCanvasSize[0]): for numNewCol in range(newCanvasSize[0]):
self.canvasMap[numNewRow].append([1, 1, " "]) self.canvasMap[numNewRow].append([[1, 1], 0, " "])
self.canvasSize = newCanvasSize self.canvasSize = newCanvasSize
canvasWinSize = ( \ self.canvasBackend.reset(self.canvasSize, \
self.cellSize[0] * self.canvasSize[0], \ self.canvasBackend.cellSize)
self.cellSize[1] * self.canvasSize[1])
self.canvasBitmap = wx.Bitmap(canvasWinSize)
# }}}
# {{{ undo(self): XXX
def undo(self):
result = self.canvasJournal.undo()
self.parentFrame.onCanvasUpdate() self.parentFrame.onCanvasUpdate()
return result
# }}}
# {{{ __del__(self): destructor method
def __del__(self):
if self.canvasBitmap != None:
self.canvasBitmap.Destroy(); self.canvasBitmap = None;
for brush in self.mircBrushes or []:
brush.Destroy()
self.mircBrushes = None
for pen in self.mircPens or []:
pen.Destroy()
self.mircPens = None
# }}} # }}}
# #
# _init__(self, parent, parentFrame, canvasPos, canvasSize, cellSize): initialisation method # _init__(self, parent, parentFrame, canvasPos, canvasSize, cellSize): initialisation method
def __init__(self, parent, parentFrame, canvasPos, canvasSize, cellSize): def __init__(self, parent, parentFrame, canvasPos, canvasSize, cellSize):
self.parentFrame = parentFrame
self.canvasPos = canvasPos; self.canvasSize = canvasSize;
self.cellSize = cellSize
self.brushColours = [4, 1]; self._initBrushesAndPens();
self.brushPos = [0, 0]; self.brushSize = [1, 1];
self.canvasJournal = MiRCARTCanvasJournal(parentCanvas=self)
self.canvasStore = MiRCARTCanvasStore(parentCanvas=self)
self.canvasCurTool = None
super().__init__(parent, pos=canvasPos, \ super().__init__(parent, pos=canvasPos, \
size=[w*h for w,h in zip(canvasSize, cellSize)]) size=[w*h for w,h in zip(canvasSize, cellSize)])
self.Bind(wx.EVT_CLOSE, self.onClose)
self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseWindowEvent) self.parentFrame = parentFrame
self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseWindowEvent) self.canvasMap = None; self.canvasPos = canvasPos; self.canvasSize = canvasSize;
self.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) self.brushColours = [4, 1]; self.brushPos = [0, 0]; self.brushSize = [1, 1];
self.Bind(wx.EVT_MOTION, self.onMouseEvent) self.canvasBackend = MiRCARTCanvasBackend(canvasSize, cellSize)
self.Bind(wx.EVT_PAINT, self.onPaint) self.canvasCurTool = None
self.Bind(wx.EVT_RIGHT_DOWN, self.onMouseEvent) self.canvasJournal = MiRCARTCanvasJournal()
self.canvasStore = MiRCARTCanvasStore(parentCanvas=self)
# Bind event handlers
self.Bind(wx.EVT_CLOSE, self.onPanelClose)
self.Bind(wx.EVT_ENTER_WINDOW, self.onPanelFocus)
self.Bind(wx.EVT_LEAVE_WINDOW, self.onPanelFocus)
self.parentFrame.Bind(wx.EVT_CHAR, self.onPanelKeyboardInput)
for eventType in( \
wx.EVT_LEFT_DOWN, wx.EVT_MOTION, wx.EVT_RIGHT_DOWN):
self.Bind(eventType, self.onPanelMouseInput)
self.Bind(wx.EVT_PAINT, self.onPanelPaint)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

153
MiRCARTCanvasBackend.py Normal file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env python3
#
# MiRCARTCanvasBackend.py -- XXX
# Copyright (c) 2018 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
from MiRCARTColours import MiRCARTColours
import wx
class MiRCARTCanvasBackend():
"""XXX"""
_font = _brushes = _pens = None
canvasBitmap = cellSize = None
# {{{ _drawBrushPatch(self, eventDc, patch, tmpDc): XXX
def _drawBrushPatch(self, eventDc, patch, tmpDc):
absPoint = self._xlatePoint(patch[0])
brushFg = self._brushes[patch[1][1]]
brushBg = self._brushes[patch[1][0]]
pen = self._pens[patch[1][1]]
for dc in (eventDc, tmpDc):
dc.SetBrush(brushFg); dc.SetBackground(brushBg); dc.SetPen(pen);
dc.DrawRectangle(*absPoint, *self.cellSize)
# }}}
# {{{ _drawCharPatch(self, eventDc, patch, tmpDc): XXX
def _drawCharPatch(self, eventDc, patch, tmpDc):
absPoint = self._xlatePoint(patch[0])
brushFg = self._brushes[patch[1][0]]
brushBg = self._brushes[patch[1][1]]
pen = self._pens[patch[1][1]]
for dc in (eventDc, tmpDc):
fontBitmap = wx.Bitmap(*self.cellSize)
fontDc = wx.MemoryDC(); fontDc.SelectObject(fontBitmap);
fontDc.SetTextForeground(wx.Colour(MiRCARTColours[patch[1][0]][0:4]))
fontDc.SetTextBackground(wx.Colour(MiRCARTColours[patch[1][1]][0:4]))
fontDc.SetBrush(brushBg); fontDc.SetBackground(brushBg); fontDc.SetPen(pen);
fontDc.SetFont(self._font)
fontDc.DrawRectangle(0, 0, *self.cellSize)
fontDc.DrawText(patch[3], 0, 0)
dc.Blit(*absPoint, *self.cellSize, fontDc, 0, 0)
# }}}
# {{{ _finiBrushesAndPens(self): XXX
def _finiBrushesAndPens(self):
for brush in self._brushes or []:
brush.Destroy()
self._brushes = None
for pen in self._pens or []:
pen.Destroy()
self._pens = None
# }}}
# {{{ _initBrushesAndPens(self): XXX
def _initBrushesAndPens(self):
self._brushes = [None for x in range(len(MiRCARTColours))]
self._pens = [None for x in range(len(MiRCARTColours))]
for mircColour in range(len(MiRCARTColours)):
self._brushes[mircColour] = wx.Brush( \
wx.Colour(MiRCARTColours[mircColour][0:4]), wx.BRUSHSTYLE_SOLID)
self._pens[mircColour] = wx.Pen( \
wx.Colour(MiRCARTColours[mircColour][0:4]), 1)
# }}}
# {{{ _xlatePoint(self, relMapPoint): XXX
def _xlatePoint(self, relMapPoint):
return [a*b for a,b in zip(relMapPoint, self.cellSize)]
# }}}
# {{{ drawPatch(self, eventDc, patch, tmpDc): XXX
def drawPatch(self, eventDc, patch, tmpDc):
if patch[0][0] < self.canvasSize[0] \
and patch[0][1] < self.canvasSize[1]:
if patch[3] == " ":
self._drawBrushPatch(eventDc, patch, tmpDc)
else:
self._drawCharPatch(eventDc, patch, tmpDc)
return True
else:
return False
# }}}
# {{{ drawCursorMaskWithJournal(self, canvasJournal, eventDc, tmpDc): XXX
def drawCursorMaskWithJournal(self, canvasJournal, eventDc, tmpDc):
for patch in canvasJournal.popCursor():
self.drawPatch(eventDc, patch, tmpDc)
# }}}
# {{{ getDeviceContexts(self, parentWindow): XXX
def getDeviceContexts(self, parentWindow):
eventDc = wx.ClientDC(parentWindow); tmpDc = wx.MemoryDC();
tmpDc.SelectObject(self.canvasBitmap)
return (eventDc, tmpDc)
# }}}
# {{{ reset(self, canvasSize, cellSize):
def reset(self, canvasSize, cellSize):
self.resize(canvasSize, cellSize)
# }}}
# {{{ resize(self, canvasSize, cellSize):
def resize(self, canvasSize, cellSize):
winSize = [a*b for a,b in zip(canvasSize, cellSize)]
if self.canvasBitmap == None:
self.canvasBitmap = wx.Bitmap(winSize)
else:
oldDc = wx.MemoryDC()
oldDc.SelectObject(self.canvasBitmap)
newDc = wx.MemoryDC()
newBitmap = wx.Bitmap(winSize)
newDc.SelectObject(newBitmap)
newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0)
self.canvasBitmap = newBitmap
self.canvasSize = canvasSize; self.cellSize = cellSize;
self._font = wx.Font( \
8, \
wx.FONTFAMILY_TELETYPE, \
wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
# }}}
# {{{ xlateEventPoint(self, event, eventDc): XXX
def xlateEventPoint(self, event, eventDc):
eventPoint = event.GetLogicalPosition(eventDc)
rectX = eventPoint.x - (eventPoint.x % self.cellSize[0])
rectY = eventPoint.y - (eventPoint.y % self.cellSize[1])
mapX = int(rectX / self.cellSize[0] if rectX else 0)
mapY = int(rectY / self.cellSize[1] if rectY else 0)
return (mapX, mapY)
# }}}
# {{{ __del__(self): destructor method
def __del__(self):
if self.canvasBitmap != None:
self.canvasBitmap.Destroy(); self.canvasBitmap = None;
self._finiBrushesAndPens()
# }}}
#
# _init__(self, canvasSize, cellSize): initialisation method
def __init__(self, canvasSize, cellSize):
self._initBrushesAndPens()
self.reset(canvasSize, cellSize)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -24,94 +24,58 @@
class MiRCARTCanvasJournal(): class MiRCARTCanvasJournal():
"""XXX""" """XXX"""
parentCanvas = None patchesCursor = patchesUndo = patchesUndoLevel = None
patchesTmp = patchesUndo = patchesUndoLevel = None
# {{{ _popTmp(self, eventDc, tmpDc): XXX # {{{ popCursor(self): XXX
def _popTmp(self, eventDc, tmpDc): def popCursor(self):
if self.patchesTmp: if len(self.patchesCursor):
for patch in self.patchesTmp: patchesCursor = self.patchesCursor
self.parentCanvas.onJournalUpdate(True, \ self.patchesCursor = []
patch[0], patch, eventDc, tmpDc, (0, 0), True) return patchesCursor
self.patchesTmp = []
# }}}
# {{{ _pushTmp(self, atPoint): XXX
def _pushTmp(self, atPoint):
self.patchesTmp.append([atPoint, None, None, None])
# }}}
# {{{ _pushUndo(self, atPoint, patches): XXX
def _pushUndo(self, atPoint, patches):
if self.patchesUndoLevel > 0:
del self.patchesUndo[0:self.patchesUndoLevel]
self.patchesUndoLevel = 0
patchesUndo = []
for patch in patches:
patchesUndo.append([ \
[patch[0], *patch[0][1:]], \
[patch[0], *patch[1][1:]]])
if len(patchesUndo) > 0:
self.patchesUndo.insert(0, patchesUndo)
# }}}
# {{{ merge(self, mapPatches, eventDc, tmpDc, atPoint): XXX
def merge(self, mapPatches, eventDc, tmpDc, atPoint):
patchesUndo = []
for mapPatch in mapPatches:
mapPatchTmp = mapPatch[0]
if mapPatchTmp:
self._popTmp(eventDc, tmpDc)
for patch in mapPatch[1]:
if patch[0][0] >= self.parentCanvas.canvasSize[0] \
or patch[0][1] >= self.parentCanvas.canvasSize[1]:
continue
elif mapPatchTmp:
self._pushTmp(patch[0])
self.parentCanvas.onJournalUpdate(mapPatchTmp, \
patch[0], patch, eventDc, tmpDc, (0, 0))
else: else:
patchUndo = \ return []
self.parentCanvas.onJournalUpdate(mapPatchTmp, \
patch[0], patch, eventDc, tmpDc, (0, 0), True)
patchesUndo.append([patchUndo, patch])
if len(patchesUndo) > 0:
self._pushUndo(atPoint, patchesUndo)
# }}} # }}}
# {{{ redo(self): XXX # {{{ popRedo(self): XXX
def redo(self): def popRedo(self):
if self.patchesUndoLevel > 0: if self.patchesUndoLevel > 0:
self.patchesUndoLevel -= 1 self.patchesUndoLevel -= 1
for patch in self.patchesUndo[self.patchesUndoLevel]: patches = self.patchesUndo[self.patchesUndoLevel]
self.parentCanvas.onJournalUpdate(False, \ return patches[1]
patch[1][0], patch[1], None, None, (0, 0))
return True
else: else:
return False return []
# }}} # }}}
# {{{ reset(self): XXX # {{{ popUndo(self): XXX
def reset(self): def popUndo(self):
self.patchesTmp = []; self.patchesUndo = [None]; self.patchesUndoLevel = 0;
# }}}
# {{{ resetCursor(self, eventDc, tmpDc): XXX
def resetCursor(self, eventDc, tmpDc):
if len(self.patchesTmp):
self._popTmp(eventDc, tmpDc)
self.patchesTmp = []
# }}}
# {{{ undo(self): XXX
def undo(self):
if self.patchesUndo[self.patchesUndoLevel] != None: if self.patchesUndo[self.patchesUndoLevel] != None:
patches = self.patchesUndo[self.patchesUndoLevel] patches = self.patchesUndo[self.patchesUndoLevel]
self.patchesUndoLevel += 1 self.patchesUndoLevel += 1
for patch in patches: return patches[0]
self.parentCanvas.onJournalUpdate(False, \
patch[0][0], patch[0], None, None, (0, 0))
return True
else: else:
return False return []
# }}}
# {{{ pushCursor(self, patches): XXX
def pushCursor(self, patches):
self.patchesCursor += patches
# }}}
# {{{ pushDeltas(self, undoPatches, redoPatches): XXX
def pushDeltas(self, undoPatches, redoPatches):
if self.patchesUndoLevel > 0:
del self.patchesUndo[0:self.patchesUndoLevel]
self.patchesUndoLevel = 0
self.patchesUndo.insert(0, [undoPatches, redoPatches])
# }}}
# {{{ resetCursor(self): XXX
def resetCursor(self):
self.patchesCursor = []
# }}}
# {{{ resetUndo(self): XXX
def resetUndo(self):
self.patchesUndo = [None]; self.patchesUndoLevel = 0;
# }}} # }}}
# #
# __init__(self, parentCanvas): initialisation method # __init__(self): initialisation method
def __init__(self, parentCanvas): def __init__(self):
self.parentCanvas = parentCanvas; self.reset(); self.resetCursor(); self.resetUndo();
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -36,7 +36,6 @@ import os, wx
class MiRCARTFrame(MiRCARTGeneralFrame): class MiRCARTFrame(MiRCARTGeneralFrame):
"""XXX""" """XXX"""
panelCanvas = canvasPathName = None panelCanvas = canvasPathName = None
canvasPos = canvasSize = cellSize = None
# {{{ Commands # {{{ Commands
# Id Type Id Labels Icon bitmap Accelerator [Initial state] # Id Type Id Labels Icon bitmap Accelerator [Initial state]
@ -57,11 +56,15 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
CID_COPY = [0x10b, TID_COMMAND, "Copy", "&Copy", ["", wx.ART_COPY], None, False] CID_COPY = [0x10b, TID_COMMAND, "Copy", "&Copy", ["", wx.ART_COPY], None, False]
CID_PASTE = [0x10c, TID_COMMAND, "Paste", "&Paste", ["", wx.ART_PASTE], None, False] CID_PASTE = [0x10c, TID_COMMAND, "Paste", "&Paste", ["", wx.ART_PASTE], None, False]
CID_DELETE = [0x10d, TID_COMMAND, "Delete", "De&lete", ["", wx.ART_DELETE], None, False] CID_DELETE = [0x10d, TID_COMMAND, "Delete", "De&lete", ["", wx.ART_DELETE], None, False]
CID_INCRBRUSH = [0x10e, TID_COMMAND, "Increase brush size", \ CID_INCR_CANVAS = [0x10e, TID_COMMAND, "Increase canvas size", \
"&Increase canvas size", ["", wx.ART_PLUS], [wx.ACCEL_SHIFT, ord("+")]]
CID_DECR_CANVAS = [0x10f, TID_COMMAND, "Decrease brush size", \
"&Decrease brush size", ["", wx.ART_MINUS], [wx.ACCEL_SHIFT, ord("-")]]
CID_INCR_BRUSH = [0x110, TID_COMMAND, "Increase brush size", \
"&Increase brush size", ["", wx.ART_PLUS], [wx.ACCEL_CTRL, ord("+")]] "&Increase brush size", ["", wx.ART_PLUS], [wx.ACCEL_CTRL, ord("+")]]
CID_DECRBRUSH = [0x10f, TID_COMMAND, "Decrease brush size", \ CID_DECR_BRUSH = [0x111, TID_COMMAND, "Decrease brush size", \
"&Decrease brush size", ["", wx.ART_MINUS], [wx.ACCEL_CTRL, ord("-")]] "&Decrease brush size", ["", wx.ART_MINUS], [wx.ACCEL_CTRL, ord("-")]]
CID_SOLID_BRUSH = [0x110, TID_SELECT, "Solid brush", "&Solid brush", None, None, True] CID_SOLID_BRUSH = [0x112, TID_SELECT, "Solid brush", "&Solid brush", None, None, True]
CID_RECT = [0x150, TID_SELECT, "Rectangle", "&Rectangle", ["toolRect.png"], [wx.ACCEL_CTRL, ord("R")], True] CID_RECT = [0x150, TID_SELECT, "Rectangle", "&Rectangle", ["toolRect.png"], [wx.ACCEL_CTRL, ord("R")], True]
CID_CIRCLE = [0x151, TID_SELECT, "Circle", "&Circle", ["toolCircle.png"], [wx.ACCEL_CTRL, ord("C")], False] CID_CIRCLE = [0x151, TID_SELECT, "Circle", "&Circle", ["toolCircle.png"], [wx.ACCEL_CTRL, ord("C")], False]
@ -97,7 +100,8 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
MID_EDIT = (0x301, TID_MENU, "Edit", "&Edit", ( \ MID_EDIT = (0x301, TID_MENU, "Edit", "&Edit", ( \
CID_UNDO, CID_REDO, NID_MENU_SEP, \ CID_UNDO, CID_REDO, NID_MENU_SEP, \
CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, \ CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, \
CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLID_BRUSH)) CID_INCR_CANVAS, CID_DECR_CANVAS, NID_MENU_SEP, \
CID_INCR_BRUSH, CID_DECR_BRUSH, CID_SOLID_BRUSH))
MID_TOOLS = (0x302, TID_MENU, "Tools", "&Tools", ( \ MID_TOOLS = (0x302, TID_MENU, "Tools", "&Tools", ( \
CID_RECT, CID_CIRCLE, CID_LINE, CID_TEXT)) CID_RECT, CID_CIRCLE, CID_LINE, CID_TEXT))
# }}} # }}}
@ -106,7 +110,7 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_TOOLBAR_SEP, \ CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_TOOLBAR_SEP, \
CID_UNDO, CID_REDO, NID_TOOLBAR_SEP, \ CID_UNDO, CID_REDO, NID_TOOLBAR_SEP, \
CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_TOOLBAR_SEP, \ CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_TOOLBAR_SEP, \
CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLID_BRUSH, NID_TOOLBAR_SEP, \ CID_INCR_BRUSH, CID_DECR_BRUSH, NID_TOOLBAR_SEP, \
CID_RECT, CID_CIRCLE, CID_LINE, CID_TEXT, NID_TOOLBAR_SEP, \ CID_RECT, CID_CIRCLE, CID_LINE, CID_TEXT, NID_TOOLBAR_SEP, \
CID_COLOUR00, CID_COLOUR01, CID_COLOUR02, CID_COLOUR03, CID_COLOUR04, \ CID_COLOUR00, CID_COLOUR01, CID_COLOUR02, CID_COLOUR03, CID_COLOUR04, \
CID_COLOUR05, CID_COLOUR06, CID_COLOUR07, CID_COLOUR08, CID_COLOUR09, \ CID_COLOUR05, CID_COLOUR06, CID_COLOUR07, CID_COLOUR08, CID_COLOUR09, \
@ -115,7 +119,8 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
# }}} # }}}
# {{{ Accelerators (hotkeys) # {{{ Accelerators (hotkeys)
AID_EDIT = (0x500, TID_ACCELS, ( \ AID_EDIT = (0x500, TID_ACCELS, ( \
CID_NEW, CID_OPEN, CID_SAVE, CID_UNDO, CID_REDO, CID_INCRBRUSH, CID_DECRBRUSH)) CID_NEW, CID_OPEN, CID_SAVE, CID_UNDO, CID_REDO, \
CID_INCR_CANVAS, CID_INCR_BRUSH, CID_INCR_BRUSH, CID_DECR_BRUSH))
# }}} # }}}
# {{{ Lists # {{{ Lists
LID_ACCELS = (0x600, TID_LIST, (AID_EDIT)) LID_ACCELS = (0x600, TID_LIST, (AID_EDIT))
@ -185,7 +190,7 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
outPathName = dialog.GetPath() outPathName = dialog.GetPath()
self.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) self.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.panelCanvas.canvasStore.exportBitmapToPngFile( \ self.panelCanvas.canvasStore.exportBitmapToPngFile( \
self.panelCanvas.canvasBitmap, outPathName, \ self.panelCanvas.canvasBackend.canvasBitmap, outPathName, \
wx.BITMAP_TYPE_PNG) wx.BITMAP_TYPE_PNG)
self.SetCursor(wx.Cursor(wx.NullCursor)) self.SetCursor(wx.Cursor(wx.NullCursor))
return True return True
@ -194,7 +199,8 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
def canvasExportImgur(self): def canvasExportImgur(self):
self.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) self.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
imgurResult = self.panelCanvas.canvasStore.exportBitmapToImgur( \ imgurResult = self.panelCanvas.canvasStore.exportBitmapToImgur( \
"c9a6efb3d7932fd", self.panelCanvas.canvasBitmap, "", "", wx.BITMAP_TYPE_PNG) "c9a6efb3d7932fd", self.panelCanvas.canvasBackend.canvasBitmap, \
"", "", wx.BITMAP_TYPE_PNG)
self.SetCursor(wx.Cursor(wx.NullCursor)) self.SetCursor(wx.Cursor(wx.NullCursor))
if imgurResult[0] == 200: if imgurResult[0] == 200:
if not wx.TheClipboard.IsOpened(): if not wx.TheClipboard.IsOpened():
@ -295,12 +301,12 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
return self.canvasSave() return self.canvasSave()
# }}} # }}}
# {{{ onCanvasMotion(self, event): XXX # {{{ onCanvasMotion(self, event): XXX
def onCanvasMotion(self, event, mapPoint=None): def onCanvasMotion(self, event, atPoint=None):
eventType = event.GetEventType() eventType = event.GetEventType()
if eventType == wx.wxEVT_ENTER_WINDOW: if eventType == wx.wxEVT_ENTER_WINDOW:
pass self.SetFocus()
elif eventType == wx.wxEVT_MOTION: elif eventType == wx.wxEVT_MOTION:
self._updateStatusBar(showPos=mapPoint) self._updateStatusBar(showPos=atPoint)
elif eventType == wx.wxEVT_LEAVE_WINDOW: elif eventType == wx.wxEVT_LEAVE_WINDOW:
pass pass
# }}} # }}}
@ -339,9 +345,9 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
elif cid == self.CID_EXIT[0]: elif cid == self.CID_EXIT[0]:
self.Close(True) self.Close(True)
elif cid == self.CID_UNDO[0]: elif cid == self.CID_UNDO[0]:
self.panelCanvas.undo() self.panelCanvas.popUndo()
elif cid == self.CID_REDO[0]: elif cid == self.CID_REDO[0]:
self.panelCanvas.redo() self.panelCanvas.popRedo()
elif cid == self.CID_CUT[0]: elif cid == self.CID_CUT[0]:
pass pass
elif cid == self.CID_COPY[0]: elif cid == self.CID_COPY[0]:
@ -350,10 +356,29 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
pass pass
elif cid == self.CID_DELETE[0]: elif cid == self.CID_DELETE[0]:
pass pass
elif cid == self.CID_INCRBRUSH[0]: elif cid == self.CID_INCR_CANVAS[0] \
or cid == self.CID_DECR_CANVAS[0]:
eventDc, tmpDc = self.panelCanvas.canvasBackend.getDeviceContexts(self)
if cid == self.CID_INCR_CANVAS[0]:
newCanvasSize = [a+1 for a in self.panelCanvas.canvasSize]
else:
newCanvasSize = [a-1 if a > 1 else a for a in self.panelCanvas.canvasSize]
self.panelCanvas.resize(newCanvasSize)
self.panelCanvas.canvasBackend.resize( \
newCanvasSize, \
self.panelCanvas.canvasBackend.cellSize)
for numRow in range(self.panelCanvas.canvasSize[1] - 1):
self.panelCanvas.canvasMap.append([[1, 1], 0, " "])
self.panelCanvas.canvasMap.append([])
for numCol in range(self.panelCanvas.canvasSize[0]):
self.panelCanvas.canvasMap[-1].append([[1, 1], 0, " "])
self.panelCanvas.canvasBackend.drawPatch(eventDc, \
([numCol, self.panelCanvas.canvasSize[1] - 1], *[[1, 1], 0, " "]), tmpDc)
wx.SafeYield()
elif cid == self.CID_INCR_BRUSH[0]:
self.panelCanvas.brushSize = \ self.panelCanvas.brushSize = \
[a+1 for a in self.panelCanvas.brushSize] [a+1 for a in self.panelCanvas.brushSize]
elif cid == self.CID_DECRBRUSH[0] \ elif cid == self.CID_DECR_BRUSH[0] \
and self.panelCanvas.brushSize[0] > 1 \ and self.panelCanvas.brushSize[0] > 1 \
and self.panelCanvas.brushSize[1] > 1: and self.panelCanvas.brushSize[1] > 1:
self.panelCanvas.brushSize = \ self.panelCanvas.brushSize = \
@ -392,15 +417,13 @@ class MiRCARTFrame(MiRCARTGeneralFrame):
# }}} # }}}
# #
# __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), canvasSize=(100, 30), cellSize=(7, 14)): initialisation method # __init__(self, parent, appSize=(840, 630), canvasPos=(25, 50), canvasSize=(125, 35), cellSize=(7, 14)): initialisation method
def __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), canvasSize=(100, 30), cellSize=(7, 14)): def __init__(self, parent, appSize=(840, 630), canvasPos=(25, 50), canvasSize=(125, 35), cellSize=(7, 14)):
self._initPaletteToolBitmaps() self._initPaletteToolBitmaps()
panelSkin = super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize) panelSkin = super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize)
self.canvasPos = canvasPos; self.cellSize = cellSize; self.canvasSize = canvasSize;
self.canvasPathName = None self.canvasPathName = None
self.panelCanvas = MiRCARTCanvas(panelSkin, parentFrame=self, \ self.panelCanvas = MiRCARTCanvas(panelSkin, parentFrame=self, \
canvasPos=self.canvasPos, canvasSize=self.canvasSize, \ canvasPos=canvasPos, canvasSize=canvasSize, cellSize=cellSize)
cellSize=self.cellSize)
self.panelCanvas.canvasCurTool = MiRCARTToolRect(self.panelCanvas) self.panelCanvas.canvasCurTool = MiRCARTToolRect(self.panelCanvas)
self.canvasNew() self.canvasNew()

View File

@ -24,7 +24,7 @@
import MiRCARTCanvasStore import MiRCARTCanvasStore
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
import string, sys import sys
class MiRCARTToPngFile: class MiRCARTToPngFile:
"""XXX""" """XXX"""

View File

@ -26,9 +26,13 @@ class MiRCARTTool():
"""XXX""" """XXX"""
parentCanvas = None parentCanvas = None
# {{{ onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar):
def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar):
return ()
# }}}
# {{{ onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX # {{{ onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown):
pass return ()
# }}} # }}}
# #

View File

@ -37,9 +37,12 @@ class MiRCARTToolRect(MiRCARTTool):
brushColours[0] = brushColours[1] brushColours[0] = brushColours[1]
else: else:
brushColours[1] = brushColours[0] brushColours[1] = brushColours[0]
brushSize = brushSize.copy()
if brushSize[0] > 1:
brushSize[0] *= 2
brushPatches = [] brushPatches = []
for brushRow in range(brushSize[1]): for brushRow in range(brushSize[1]):
for brushCol in range(brushSize[0] * 2): for brushCol in range(brushSize[0]):
brushPatches.append([[ \ brushPatches.append([[ \
atPoint[0] + brushCol, \ atPoint[0] + brushCol, \
atPoint[1] + brushRow], \ atPoint[1] + brushRow], \

View File

@ -23,30 +23,45 @@
# #
from MiRCARTTool import MiRCARTTool from MiRCARTTool import MiRCARTTool
import string
class MiRCARTToolText(MiRCARTTool): class MiRCARTToolText(MiRCARTTool):
"""XXX""" """XXX"""
textColours = textPos = None
#
# onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar): XXX
def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar):
if not keyChar in string.printable:
return []
else:
if self.textColours == None:
self.textColours = brushColours.copy()
if self.textPos == None:
self.textPos = list(atPoint)
patches = [[False, [[self.textPos, self.textColours, 0, keyChar]]]]
if self.textPos[0] < (self.parentCanvas.canvasSize[0] - 1):
self.textPos[0] += 1
elif self.textPos[1] < (self.parentCanvas.canvasSize[1] - 1):
self.textPos[0] = 0
self.textPos[1] += 1
else:
self.textPos = [0, 0]
return patches
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown):
brushColours = brushColours.copy()
if isLeftDown: if isLeftDown:
brushColours[1] = brushColours[0] self.textColours = brushColours.copy()
self.textPos = list(atPoint)
elif isRightDown: elif isRightDown:
brushColours[0] = brushColours[1] self.textColours = [brushColours[1], brushColours[0]]
self.textPos = list(atPoint)
else: else:
brushColours[1] = brushColours[0] if self.textColours == None:
brushPatches = [] self.textColours = brushColours.copy()
for brushRow in range(brushSize[1]): self.textPos = list(atPoint)
for brushCol in range(brushSize[0] * 2): return [[True, [[self.textPos, self.textColours, 0, "_"]]]]
brushPatches.append([[ \
atPoint[0] + brushCol, \
atPoint[1] + brushRow], \
brushColours, 0, " "])
if isLeftDown or isRightDown:
return [[False, brushPatches], [True, brushPatches]]
else:
return [[True, brushPatches]]
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120