diff --git a/MiRCARTCanvas.py b/MiRCARTCanvas.py index eb341dd..a3c6642 100644 --- a/MiRCARTCanvas.py +++ b/MiRCARTCanvas.py @@ -22,6 +22,7 @@ # SOFTWARE. # +from MiRCARTCanvasBackend import MiRCARTCanvasBackend from MiRCARTCanvasJournal import MiRCARTCanvasJournal from MiRCARTCanvasStore import MiRCARTCanvasStore, haveMiRCARTToPngFile, haveUrllib from MiRCARTColours import MiRCARTColours @@ -30,208 +31,168 @@ import wx class MiRCARTCanvas(wx.Panel): """XXX""" parentFrame = None - canvasPos = canvasSize = canvasWinSize = cellSize = None - canvasBitmap = canvasMap = None + canvasMap = canvasPos = canvasSize = None brushColours = brushPos = brushSize = None - mircBrushes = mircPens = None - canvasJournal = canvasStore = None - canvasCurTool = None + canvasBackend = canvasCurTool = canvasJournal = canvasStore = None - # {{{ _initBrushesAndPens(self): XXX - def _initBrushesAndPens(self): - self.mircBrushes = [None for x in range(len(MiRCARTColours))] - 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) + # {{{ _commitPatch(self, patch): + def _commitPatch(self, patch): + self.canvasMap[patch[0][1]][patch[0][0]] = patch[1:] # }}} - # {{{ _drawPatch(self, patch, eventDc, tmpDc, atPoint): XXX - def _drawPatch(self, patch, eventDc, tmpDc, atPoint): - absPoint = self._relMapPointToAbsPoint(patch[0], atPoint) - if patch[3] == " ": - brushFg = self.mircBrushes[patch[1][1]] - brushBg = self.mircBrushes[patch[1][0]] - pen = self.mircPens[patch[1][1]] - else: - brushFg = self.mircBrushes[patch[1][0]] - brushBg = self.mircBrushes[patch[1][1]] - pen = self.mircPens[patch[1][0]] - for dc in (eventDc, tmpDc): - dc.SetBrush(brushFg); dc.SetBackground(brushBg); dc.SetPen(pen); - dc.DrawRectangle(*absPoint, *self.cellSize) - # }}} - # {{{ _eventPointToMapPoint(self, eventPoint): XXX - def _eventPointToMapPoint(self, eventPoint): - 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) - # }}} - # {{{ _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] + # {{{ _dispatchInput(self, eventDc, patches, tmpDc): XXX + def _dispatchInput(self, eventDc, patches, tmpDc): + self.canvasBackend.drawCursorMaskWithJournal( \ + self.canvasJournal, eventDc, tmpDc) + cursorPatches = []; undoPatches = []; newPatches = []; + for patchDescr in patches: + patchIsCursor = patchDescr[0] + for patch in patchDescr[1]: + if self.canvasBackend.drawPatch(eventDc, patch, tmpDc) == False: + continue + else: + patchDeltaCell = self.canvasMap[patch[0][1]][patch[0][0]] + if patchIsCursor == True: + cursorPatches.append([list(patch[0]), *patchDeltaCell.copy()]) + else: + undoPatches.append([list(patch[0]), *patchDeltaCell.copy()]) + newPatches.append(patch) + self._commitPatch(patch) + if len(cursorPatches): + self.canvasJournal.pushCursor(cursorPatches) + if len(undoPatches): + self.canvasJournal.pushDeltas(undoPatches, newPatches) # }}} - # {{{ onClose(self, event): XXX - def onClose(self, event): - self.Destroy(); self.__del__(); + # {{{ onPanelClose(self, event): XXX + def onPanelClose(self, event): + self.Destroy() # }}} - # {{{ onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): - def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint, isInherit=False): - if eventDc == None: - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - if tmpDc == None: - tmpDc.SelectObject(self.canvasBitmap) - if isTmp == True: - if isInherit: - patch[1:] = self._getMapCell(patch[0]) - self._drawPatch(patch, eventDc, tmpDc, atPoint) + # {{{ onPanelKeyboardInput(self, event): XXX + def onPanelKeyboardInput(self, event): + eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self) + tool = self.canvasCurTool; mapPoint = self.brushPos; + if event.GetModifiers() != wx.MOD_NONE: + event.Skip() else: - if isInherit: - patchOld = patch.copy() - patchOld[1:] = self._getMapCell(patchOld[0]) - self._setMapCell(absMapPoint, *patch[1:]) - self._drawPatch(patch, eventDc, tmpDc, atPoint) - if isInherit: - return patchOld + patches = tool.onKeyboardEvent( \ + event, mapPoint, self.brushColours, self.brushSize, \ + chr(event.GetUnicodeKey())) + if len(patches): + self._dispatchInput(eventDc, patches, tmpDc) + self.parentFrame.onCanvasUpdate() # }}} - # {{{ onMouseEvent(self, event): XXX - def onMouseEvent(self, event): - eventObject = event.GetEventObject() - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.canvasBitmap) - eventPoint = event.GetLogicalPosition(eventDc) - mapPoint = self._eventPointToMapPoint(eventPoint) + # {{{ onPanelMouseInput(self, event): XXX + def onPanelMouseInput(self, event): + eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self) tool = self.canvasCurTool - mapPatches = tool.onMouseEvent( \ - event, mapPoint, self.brushColours, self.brushSize, \ + self.brushPos = mapPoint = \ + self.canvasBackend.xlateEventPoint(event, eventDc) + patches = tool.onMouseEvent( \ + event, mapPoint, self.brushColours, self.brushSize, \ event.Dragging(), event.LeftIsDown(), event.RightIsDown()) - self.canvasJournal.merge(mapPatches, eventDc, tmpDc, mapPoint) - self.parentFrame.onCanvasUpdate() + if len(patches): + self._dispatchInput(eventDc, patches, tmpDc) + self.parentFrame.onCanvasUpdate() self.parentFrame.onCanvasMotion(event, mapPoint) # }}} - # {{{ onMouseWindowEvent(self, event): XXX - def onMouseWindowEvent(self, event): - eventObject = event.GetEventObject() - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.canvasBitmap) - self.canvasJournal.resetCursor(eventDc, tmpDc) + # {{{ onPanelFocus(self, event): XXX + def onPanelFocus(self, event): + if event.GetEventType() == wx.wxEVT_LEAVE_WINDOW: + eventDc, tmpDc = \ + self.canvasBackend.getDeviceContexts(self) + self.canvasBackend.drawCursorMaskWithJournal( \ + self.canvasJournal, eventDc, tmpDc) self.parentFrame.onCanvasMotion(event) # }}} - # {{{ onPaint(self, event): XXX - def onPaint(self, event): - eventDc = wx.BufferedPaintDC(self, self.canvasBitmap) + # {{{ onPanelPaint(self, event): XXX + def onPanelPaint(self, event): + if self.canvasBackend.canvasBitmap != None: + eventDc = wx.BufferedPaintDC(self, self.canvasBackend.canvasBitmap) # }}} # {{{ onStoreUpdate(self, newCanvasSize, newCanvas=None): def onStoreUpdate(self, newCanvasSize, newCanvas=None): - if newCanvasSize != None: - self.resize(newCanvasSize) - self.canvasJournal.reset() - 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, " "] \ - for x in range(self.canvasSize[0])] \ - for y in range(self.canvasSize[1])] - canvasWinSize = [a*b for a,b in zip(self.canvasSize, self.cellSize)] - if self.canvasBitmap != None: - self.canvasBitmap.Destroy() - self.canvasBitmap = wx.Bitmap(canvasWinSize) - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.canvasBitmap) + self.resize(newCanvasSize=newCanvasSize) + self.canvasBackend.reset(self.canvasSize, self.canvasBackend.cellSize) + self.canvasJournal.resetCursor(); self.canvasJournal.resetUndo(); + self.canvasMap = [[[(1, 1), 0, " "] \ + for x in range(self.canvasSize[0])] \ + for y in range(self.canvasSize[1])] + eventDc, tmpDc = self.canvasBackend.getDeviceContexts(self) for numRow in range(self.canvasSize[1]): for numCol in range(self.canvasSize[0]): - self.onJournalUpdate(False, \ - (numCol, numRow), \ - [(numCol, numRow), \ - *self.canvasMap[numRow][numCol]], \ - eventDc, tmpDc, (0, 0)) + if newCanvas != None \ + and numRow < len(newCanvas) \ + and numCol < len(newCanvas[numRow]): + self._commitPatch([ \ + [numCol, numRow], *newCanvas[numRow][numCol]]) + self.canvasBackend.drawPatch(eventDc, \ + ([numCol, numRow], \ + *self.canvasMap[numRow][numCol]), tmpDc) wx.SafeYield() # }}} - # {{{ redo(self): XXX - def redo(self): - result = self.canvasJournal.redo() + # {{{ popRedo(self): + def popRedo(self): + 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() - 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): if newCanvasSize != self.canvasSize: - self.SetSize(*self.canvasPos, \ - newCanvasSize[0] * self.cellSize[0], \ - newCanvasSize[1] * self.cellSize[1]) + winSize = [a*b for a,b in \ + zip(newCanvasSize, self.canvasBackend.cellSize)] + self.SetSize(*self.canvasPos, *winSize) for numRow in range(self.canvasSize[1]): 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]): self.canvasMap.append([]) for numNewCol in range(newCanvasSize[0]): - self.canvasMap[numNewRow].append([1, 1, " "]) + self.canvasMap[numNewRow].append([[1, 1], 0, " "]) self.canvasSize = newCanvasSize - canvasWinSize = ( \ - self.cellSize[0] * self.canvasSize[0], \ - self.cellSize[1] * self.canvasSize[1]) - self.canvasBitmap = wx.Bitmap(canvasWinSize) - # }}} - # {{{ undo(self): XXX - def undo(self): - result = self.canvasJournal.undo() + self.canvasBackend.reset(self.canvasSize, \ + self.canvasBackend.cellSize) 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 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)]) - self.Bind(wx.EVT_CLOSE, self.onClose) - self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseWindowEvent) - self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseWindowEvent) - self.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) - self.Bind(wx.EVT_MOTION, self.onMouseEvent) - self.Bind(wx.EVT_PAINT, self.onPaint) - self.Bind(wx.EVT_RIGHT_DOWN, self.onMouseEvent) + + self.parentFrame = parentFrame + self.canvasMap = None; self.canvasPos = canvasPos; self.canvasSize = canvasSize; + self.brushColours = [4, 1]; self.brushPos = [0, 0]; self.brushSize = [1, 1]; + self.canvasBackend = MiRCARTCanvasBackend(canvasSize, cellSize) + self.canvasCurTool = None + 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 diff --git a/MiRCARTCanvasBackend.py b/MiRCARTCanvasBackend.py new file mode 100644 index 0000000..b9381f9 --- /dev/null +++ b/MiRCARTCanvasBackend.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +# +# MiRCARTCanvasBackend.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# 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 diff --git a/MiRCARTCanvasJournal.py b/MiRCARTCanvasJournal.py index 9ac34d2..17706e7 100644 --- a/MiRCARTCanvasJournal.py +++ b/MiRCARTCanvasJournal.py @@ -24,94 +24,58 @@ class MiRCARTCanvasJournal(): """XXX""" - parentCanvas = None - patchesTmp = patchesUndo = patchesUndoLevel = None + patchesCursor = patchesUndo = patchesUndoLevel = None - # {{{ _popTmp(self, eventDc, tmpDc): XXX - def _popTmp(self, eventDc, tmpDc): - if self.patchesTmp: - for patch in self.patchesTmp: - self.parentCanvas.onJournalUpdate(True, \ - patch[0], patch, eventDc, tmpDc, (0, 0), True) - self.patchesTmp = [] + # {{{ popCursor(self): XXX + def popCursor(self): + if len(self.patchesCursor): + patchesCursor = self.patchesCursor + self.patchesCursor = [] + return patchesCursor + else: + return [] # }}} - # {{{ _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: - patchUndo = \ - 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 - def redo(self): + # {{{ popRedo(self): XXX + def popRedo(self): if self.patchesUndoLevel > 0: self.patchesUndoLevel -= 1 - for patch in self.patchesUndo[self.patchesUndoLevel]: - self.parentCanvas.onJournalUpdate(False, \ - patch[1][0], patch[1], None, None, (0, 0)) - return True + patches = self.patchesUndo[self.patchesUndoLevel] + return patches[1] else: - return False + return [] # }}} - # {{{ reset(self): XXX - def reset(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): + # {{{ popUndo(self): XXX + def popUndo(self): if self.patchesUndo[self.patchesUndoLevel] != None: patches = self.patchesUndo[self.patchesUndoLevel] self.patchesUndoLevel += 1 - for patch in patches: - self.parentCanvas.onJournalUpdate(False, \ - patch[0][0], patch[0], None, None, (0, 0)) - return True + return patches[0] 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 - def __init__(self, parentCanvas): - self.parentCanvas = parentCanvas; self.reset(); + # __init__(self): initialisation method + def __init__(self): + self.resetCursor(); self.resetUndo(); # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTFrame.py b/MiRCARTFrame.py index 7a92ebb..94f339e 100644 --- a/MiRCARTFrame.py +++ b/MiRCARTFrame.py @@ -36,7 +36,6 @@ import os, wx class MiRCARTFrame(MiRCARTGeneralFrame): """XXX""" panelCanvas = canvasPathName = None - canvasPos = canvasSize = cellSize = None # {{{ Commands # 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_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_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("+")]] - 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("-")]] - 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_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", ( \ CID_UNDO, CID_REDO, 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", ( \ 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_UNDO, CID_REDO, 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_COLOUR00, CID_COLOUR01, CID_COLOUR02, CID_COLOUR03, CID_COLOUR04, \ CID_COLOUR05, CID_COLOUR06, CID_COLOUR07, CID_COLOUR08, CID_COLOUR09, \ @@ -115,7 +119,8 @@ class MiRCARTFrame(MiRCARTGeneralFrame): # }}} # {{{ Accelerators (hotkeys) 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 LID_ACCELS = (0x600, TID_LIST, (AID_EDIT)) @@ -177,15 +182,15 @@ class MiRCARTFrame(MiRCARTGeneralFrame): # {{{ canvasExportAsPng(self): XXX def canvasExportAsPng(self): - with wx.FileDialog(self, self.CID_SAVEAS[2], os.getcwd(), "", \ + with wx.FileDialog(self, self.CID_SAVEAS[2], os.getcwd(), "", \ "*.png", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog: if dialog.ShowModal() == wx.ID_CANCEL: return False else: outPathName = dialog.GetPath() self.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) - self.panelCanvas.canvasStore.exportBitmapToPngFile( \ - self.panelCanvas.canvasBitmap, outPathName, \ + self.panelCanvas.canvasStore.exportBitmapToPngFile( \ + self.panelCanvas.canvasBackend.canvasBitmap, outPathName, \ wx.BITMAP_TYPE_PNG) self.SetCursor(wx.Cursor(wx.NullCursor)) return True @@ -194,7 +199,8 @@ class MiRCARTFrame(MiRCARTGeneralFrame): def canvasExportImgur(self): self.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) 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)) if imgurResult[0] == 200: if not wx.TheClipboard.IsOpened(): @@ -295,12 +301,12 @@ class MiRCARTFrame(MiRCARTGeneralFrame): return self.canvasSave() # }}} # {{{ onCanvasMotion(self, event): XXX - def onCanvasMotion(self, event, mapPoint=None): + def onCanvasMotion(self, event, atPoint=None): eventType = event.GetEventType() if eventType == wx.wxEVT_ENTER_WINDOW: - pass + self.SetFocus() elif eventType == wx.wxEVT_MOTION: - self._updateStatusBar(showPos=mapPoint) + self._updateStatusBar(showPos=atPoint) elif eventType == wx.wxEVT_LEAVE_WINDOW: pass # }}} @@ -339,9 +345,9 @@ class MiRCARTFrame(MiRCARTGeneralFrame): elif cid == self.CID_EXIT[0]: self.Close(True) elif cid == self.CID_UNDO[0]: - self.panelCanvas.undo() + self.panelCanvas.popUndo() elif cid == self.CID_REDO[0]: - self.panelCanvas.redo() + self.panelCanvas.popRedo() elif cid == self.CID_CUT[0]: pass elif cid == self.CID_COPY[0]: @@ -350,33 +356,52 @@ class MiRCARTFrame(MiRCARTGeneralFrame): pass elif cid == self.CID_DELETE[0]: pass - elif cid == self.CID_INCRBRUSH[0]: - self.panelCanvas.brushSize = \ + 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 = \ [a+1 for a in self.panelCanvas.brushSize] - elif cid == self.CID_DECRBRUSH[0] \ - and self.panelCanvas.brushSize[0] > 1 \ + elif cid == self.CID_DECR_BRUSH[0] \ + and self.panelCanvas.brushSize[0] > 1 \ and self.panelCanvas.brushSize[1] > 1: - self.panelCanvas.brushSize = \ + self.panelCanvas.brushSize = \ [a-1 for a in self.panelCanvas.brushSize] elif cid == self.CID_SOLID_BRUSH[0]: pass elif cid == self.CID_RECT[0]: self.menuItemsById[cid].Check(True) - self.panelCanvas.canvasCurTool = \ + self.panelCanvas.canvasCurTool = \ MiRCARTToolRect(self.panelCanvas) elif cid == self.CID_CIRCLE[0]: self.menuItemsById[cid].Check(True) - self.panelCanvas.canvasCurTool = \ + self.panelCanvas.canvasCurTool = \ MiRCARTToolCircle(self.panelCanvas) elif cid == self.CID_LINE[0]: self.menuItemsById[cid].Check(True) - self.panelCanvas.canvasCurTool = \ + self.panelCanvas.canvasCurTool = \ MiRCARTToolLine(self.panelCanvas) elif cid == self.CID_TEXT[0]: self.menuItemsById[cid].Check(True) - self.panelCanvas.canvasCurTool = \ + self.panelCanvas.canvasCurTool = \ MiRCARTToolText(self.panelCanvas) - elif cid >= self.CID_COLOUR00[0] \ + elif cid >= self.CID_COLOUR00[0] \ and cid <= self.CID_COLOUR15[0]: numColour = cid - self.CID_COLOUR00[0] if event.GetEventType() == wx.wxEVT_TOOL: @@ -392,15 +417,13 @@ class MiRCARTFrame(MiRCARTGeneralFrame): # }}} # - # __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), canvasSize=(100, 30), cellSize=(7, 14)): initialisation method - def __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), canvasSize=(100, 30), cellSize=(7, 14)): + # __init__(self, parent, appSize=(840, 630), canvasPos=(25, 50), canvasSize=(125, 35), cellSize=(7, 14)): initialisation method + def __init__(self, parent, appSize=(840, 630), canvasPos=(25, 50), canvasSize=(125, 35), cellSize=(7, 14)): self._initPaletteToolBitmaps() panelSkin = super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize) - self.canvasPos = canvasPos; self.cellSize = cellSize; self.canvasSize = canvasSize; self.canvasPathName = None self.panelCanvas = MiRCARTCanvas(panelSkin, parentFrame=self, \ - canvasPos=self.canvasPos, canvasSize=self.canvasSize, \ - cellSize=self.cellSize) + canvasPos=canvasPos, canvasSize=canvasSize, cellSize=cellSize) self.panelCanvas.canvasCurTool = MiRCARTToolRect(self.panelCanvas) self.canvasNew() diff --git a/MiRCARTToPngFile.py b/MiRCARTToPngFile.py index cf6e7de..78ef788 100755 --- a/MiRCARTToPngFile.py +++ b/MiRCARTToPngFile.py @@ -24,7 +24,7 @@ import MiRCARTCanvasStore from PIL import Image, ImageDraw, ImageFont -import string, sys +import sys class MiRCARTToPngFile: """XXX""" diff --git a/MiRCARTTool.py b/MiRCARTTool.py index ae91e6d..be8758c 100644 --- a/MiRCARTTool.py +++ b/MiRCARTTool.py @@ -26,9 +26,13 @@ class MiRCARTTool(): """XXX""" 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 def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): - pass + return () # }}} # diff --git a/MiRCARTToolRect.py b/MiRCARTToolRect.py index d2452c5..a4e9662 100644 --- a/MiRCARTToolRect.py +++ b/MiRCARTToolRect.py @@ -37,9 +37,12 @@ class MiRCARTToolRect(MiRCARTTool): brushColours[0] = brushColours[1] else: brushColours[1] = brushColours[0] + brushSize = brushSize.copy() + if brushSize[0] > 1: + brushSize[0] *= 2 brushPatches = [] for brushRow in range(brushSize[1]): - for brushCol in range(brushSize[0] * 2): + for brushCol in range(brushSize[0]): brushPatches.append([[ \ atPoint[0] + brushCol, \ atPoint[1] + brushRow], \ diff --git a/MiRCARTToolText.py b/MiRCARTToolText.py index 9fd18ab..8f1be6d 100644 --- a/MiRCARTToolText.py +++ b/MiRCARTToolText.py @@ -23,30 +23,45 @@ # from MiRCARTTool import MiRCARTTool +import string class MiRCARTToolText(MiRCARTTool): """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 def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): - brushColours = brushColours.copy() if isLeftDown: - brushColours[1] = brushColours[0] + self.textColours = brushColours.copy() + self.textPos = list(atPoint) elif isRightDown: - brushColours[0] = brushColours[1] + self.textColours = [brushColours[1], brushColours[0]] + self.textPos = list(atPoint) else: - brushColours[1] = brushColours[0] - brushPatches = [] - for brushRow in range(brushSize[1]): - for brushCol in range(brushSize[0] * 2): - brushPatches.append([[ \ - atPoint[0] + brushCol, \ - atPoint[1] + brushRow], \ - brushColours, 0, " "]) - if isLeftDown or isRightDown: - return [[False, brushPatches], [True, brushPatches]] - else: - return [[True, brushPatches]] + if self.textColours == None: + self.textColours = brushColours.copy() + self.textPos = list(atPoint) + return [[True, [[self.textPos, self.textColours, 0, "_"]]]] # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120