Initial canvas panel scrollbar implementation.

assets/text/TODO: updated.
libgui/GuiCanvasPanel.py:__init__(): provide self.winSize & call SetScrollRate().
libgui/GuiCanvasPanel.py:{_drawPatch,dispatch{DeltaPatches,Patch},onPanel{Input,LeaveWindow},resize,update}(): receive and/or pass viewRect.
libgui/GuiCanvasPanel.py:onPanelPaint(): updated.
libgui/GuiCanvasPanel.py:resize(): call SetVirtualSize().
libgui/GuiCanvasWxBackend.py:_{draw{Brush,Char}Patch,_get{Brush,Char}PatchColours,xlatePoint}(): updated.
libgui/GuiCanvasWxBackend.py:{draw{CursorMaskWithJournal,Patch},getDeviceContext,xlateEventPoint}(): receive and/or pass viewRect.
libgui/GuiCanvasWxBackend.py:getDeviceContext(): return ClientDC() if viewRect > (0, 0)
libgui/GuiCanvasWxBackend.py:onPanelPaintEvent(): blit subset of canvasBitmap into BufferedPaintDC() if viewRect > (0, 0).
libtools/Tool{,Circle,Fill,Line,Rect,Select{,Clone,Move},Text}.py: receive & pass viewRect to dispatchFn().
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-09 12:30:25 +02:00
parent 8af07b61ba
commit dfdd374bb0
13 changed files with 139 additions and 116 deletions

View File

@ -5,7 +5,7 @@
5) Client-Server or Peer-to-Peer realtime collaboration 5) Client-Server or Peer-to-Peer realtime collaboration
6) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.) 6) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.)
7) Hotkey & graphical interfaces to {composed,parametrised} tools 7) Hotkey & graphical interfaces to {composed,parametrised} tools
8) GUI: a) scrollbar b) {de,in}crease cell size c) revisit About dialogue d) Settings panel e) switch from wxPython to GTK 8) GUI: a) {de,in}crease cell size b) revisit About dialogue c) Settings panel d) switch from wxPython to GTK
9) Layers, layout (e.g. for comics, zines, etc.) & asset management (e.g. kade, lion, etc.) & traits w/ {inserting,merging,linking} 9) Layers, layout (e.g. for comics, zines, etc.) & asset management (e.g. kade, lion, etc.) & traits w/ {inserting,merging,linking}
10) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...) 10) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...)
11) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools: 11) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools:

View File

@ -6,54 +6,56 @@
import wx import wx
class GuiCanvasPanel(wx.Panel): class GuiCanvasPanel(wx.ScrolledWindow):
# {{{ _drawPatch(self, eventDc, isCursor, patch) # {{{ _drawPatch(self, eventDc, isCursor, patch, viewRect)
def _drawPatch(self, eventDc, isCursor, patch): def _drawPatch(self, eventDc, isCursor, patch, viewRect):
if not self.canvas.dirtyCursor: if not self.canvas.dirtyCursor:
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc) self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc, viewRect)
self.canvas.dirtyCursor = True self.canvas.dirtyCursor = True
if self.backend.drawPatch(eventDc, patch) \ if self.backend.drawPatch(eventDc, patch, viewRect) and isCursor:
and isCursor:
patchDeltaCell = self.canvas.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell]; patchDeltaCell = self.canvas.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
self.canvas.journal.pushCursor(patchDelta) self.canvas.journal.pushCursor(patchDelta)
# }}} # }}}
# {{{ dispatchDeltaPatches(self, deltaPatches) # {{{ dispatchDeltaPatches(self, deltaPatches)
def dispatchDeltaPatches(self, deltaPatches): def dispatchDeltaPatches(self, deltaPatches):
eventDc = self.backend.getDeviceContext(self) eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
for patch in deltaPatches: for patch in deltaPatches:
if patch == None: if patch == None:
continue continue
elif patch[0] == "resize": elif patch[0] == "resize":
del eventDc; self.resize(patch[1:], False); eventDc = self.backend.getDeviceContext(self); del eventDc; self.resize(patch[1:], False); eventDc = self.backend.getDeviceContext(self, self.GetViewStart());
else: else:
self.canvas._commitPatch(patch); self.backend.drawPatch(eventDc, patch); self.canvas._commitPatch(patch); self.backend.drawPatch(eventDc, patch, self.GetViewStart());
# }}} # }}}
# {{{ dispatchPatch(self, eventDc, isCursor, patch) # {{{ dispatchPatch(self, eventDc, isCursor, patch, viewRect)
def dispatchPatch(self, eventDc, isCursor, patch): def dispatchPatch(self, eventDc, isCursor, patch, viewRect):
if self.canvas.dispatchPatch(isCursor, patch, False if isCursor else True): if self.canvas.dispatchPatch(isCursor, patch, False if isCursor else True):
self._drawPatch(eventDc, isCursor, patch) self._drawPatch(eventDc, isCursor, patch, viewRect)
# }}} # }}}
# {{{ resize(self, newSize, commitUndo=True) # {{{ resize(self, newSize, commitUndo=True)
def resize(self, newSize, commitUndo=True): def resize(self, newSize, commitUndo=True):
oldSize = [0, 0] if self.canvas.map == None else self.canvas.size oldSize = [0, 0] if self.canvas.map == None else self.canvas.size
deltaSize = [b - a for a, b in zip(oldSize, newSize)] deltaSize = [b - a for a, b in zip(oldSize, newSize)]
if self.canvas.resize(newSize, commitUndo): if self.canvas.resize(newSize, commitUndo):
newWinSize = [a * b for a, b in zip(newSize, self.backend.cellSize)] self.winSize = [a * b for a, b in zip(newSize, self.backend.cellSize)]
self.SetMinSize(newWinSize); self.SetSize(wx.DefaultCoord, wx.DefaultCoord, *newWinSize); self.SetMinSize(self.winSize)
self.SetSize(wx.DefaultCoord, wx.DefaultCoord, *self.winSize)
self.SetVirtualSize(self.winSize)
curWindow = self curWindow = self
while curWindow != None: while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent(); curWindow.Layout(); curWindow = curWindow.GetParent();
self.backend.resize(newSize, self.backend.cellSize) self.backend.resize(newSize, self.backend.cellSize)
eventDc = self.backend.getDeviceContext(self) eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
viewRect = self.GetViewStart()
if deltaSize[0] > 0: if deltaSize[0] > 0:
for numRow in range(oldSize[1]): for numRow in range(oldSize[1]):
for numNewCol in range(oldSize[0], newSize[0]): for numNewCol in range(oldSize[0], newSize[0]):
self._drawPatch(eventDc, False, [numNewCol, numRow, 1, 1, 0, " "]) self._drawPatch(eventDc, False, [numNewCol, numRow, 1, 1, 0, " "], viewRect)
if deltaSize[1] > 1: if deltaSize[1] > 1:
for numNewRow in range(oldSize[1], newSize[1]): for numNewRow in range(oldSize[1], newSize[1]):
for numNewCol in range(newSize[0]): for numNewCol in range(newSize[0]):
self._drawPatch(eventDc, False, [numNewCol, numNewRow, 1, 1, 0, " "]) self._drawPatch(eventDc, False, [numNewCol, numNewRow, 1, 1, 0, " "], viewRect)
del eventDc; wx.SafeYield(); del eventDc; wx.SafeYield();
self.interface.update(size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel) self.interface.update(size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel)
# }}} # }}}
@ -61,10 +63,10 @@ class GuiCanvasPanel(wx.Panel):
def update(self, newSize, commitUndo=True, newCanvas=None): def update(self, newSize, commitUndo=True, newCanvas=None):
self.resize(newSize, commitUndo) self.resize(newSize, commitUndo)
self.canvas.update(newSize, newCanvas) self.canvas.update(newSize, newCanvas)
eventDc = self.backend.getDeviceContext(self) eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
for numRow in range(newSize[1]): for numRow in range(newSize[1]):
for numCol in range(newSize[0]): for numCol in range(newSize[0]):
self.backend.drawPatch(eventDc, [numCol, numRow, *self.canvas.map[numRow][numCol]]) self.backend.drawPatch(eventDc, [numCol, numRow, *self.canvas.map[numRow][numCol]], self.GetViewStart())
wx.SafeYield() wx.SafeYield()
# }}} # }}}
@ -79,22 +81,18 @@ class GuiCanvasPanel(wx.Panel):
# {{{ onPanelInput(self, event) # {{{ onPanelInput(self, event)
def onPanelInput(self, event): def onPanelInput(self, event):
self.canvas.dirtyJournal, self.canvas.dirtyCursor = False, False self.canvas.dirtyJournal, self.canvas.dirtyCursor = False, False
eventDc, eventType, tool = self.backend.getDeviceContext(self), event.GetEventType(), self.interface.currentTool eventType, tool, viewRect = event.GetEventType(), self.interface.currentTool, self.GetViewStart()
eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
if eventType == wx.wxEVT_CHAR: if eventType == wx.wxEVT_CHAR:
mapPoint = self.brushPos mapPoint = self.brushPos
doSkip = tool.onKeyboardEvent(event, mapPoint, self.brushColours, self.brushSize, chr(event.GetUnicodeKey()), self.dispatchPatch, eventDc) if tool.onKeyboardEvent(event, mapPoint, self.brushColours, self.brushSize, chr(event.GetUnicodeKey()), self.dispatchPatch, eventDc, viewRect):
if doSkip:
event.Skip(); return; event.Skip(); return;
else: else:
mapPoint = self.backend.xlateEventPoint(event, eventDc) mapPoint = self.backend.xlateEventPoint(event, eventDc, viewRect)
if mapPoint[0] >= self.canvas.size[0] \ if (mapPoint[0] < self.canvas.size[0]) \
or mapPoint[1] >= self.canvas.size[1]: and (mapPoint[1] < self.canvas.size[1]):
return self.brushPos = mapPoint
self.brushPos = mapPoint tool.onMouseEvent(event, self.brushPos, self.brushColours, self.brushSize, event.Dragging(), event.LeftIsDown(), event.RightIsDown(), self.dispatchPatch, eventDc, viewRect)
tool.onMouseEvent( \
event, mapPoint, self.brushColours, self.brushSize, \
event.Dragging(), event.LeftIsDown(), event.RightIsDown(), \
self.dispatchPatch, eventDc)
if self.canvas.dirtyJournal: if self.canvas.dirtyJournal:
self.dirty = True self.dirty = True
self.interface.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel) self.interface.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
@ -103,18 +101,19 @@ class GuiCanvasPanel(wx.Panel):
# }}} # }}}
# {{{ onPanelLeaveWindow(self, event) # {{{ onPanelLeaveWindow(self, event)
def onPanelLeaveWindow(self, event): def onPanelLeaveWindow(self, event):
eventDc = self.backend.getDeviceContext(self) eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc) self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc, self.GetViewStart())
# }}} # }}}
# {{{ onPanelPaint(self, event) # {{{ onPanelPaint(self, event)
def onPanelPaint(self, event): def onPanelPaint(self, event):
self.backend.onPanelPaintEvent(event, self) self.backend.onPanelPaintEvent(self.canvas.size, self.defaultCellSize, self.GetClientSize(), self, self.GetViewStart())
# }}} # }}}
# #
# __init__(self, parent, parentFrame, backend, canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, interface): initialisation method # __init__(self, parent, parentFrame, backend, canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, interface): initialisation method
def __init__(self, parent, parentFrame, backend, canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, interface): def __init__(self, parent, parentFrame, backend, canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, interface):
super().__init__(parent, pos=defaultCanvasPos, size=[w * h for w, h in zip(defaultCanvasSize, defaultCellSize)]) self.winSize = [w * h for w, h in zip(defaultCanvasSize, defaultCellSize)]
super().__init__(parent, pos=defaultCanvasPos, size=self.winSize)
self.backend, self.interface = backend(defaultCanvasSize, defaultCellSize), interface(self, parentFrame) self.backend, self.interface = backend(defaultCanvasSize, defaultCellSize), interface(self, parentFrame)
self.brushColours, self.brushPos, self.brushSize = [4, 1], [0, 0], [1, 1] self.brushColours, self.brushPos, self.brushSize = [4, 1], [0, 0], [1, 1]
self.canvas, self.canvasPos, self.defaultCanvasPos, self.defaultCanvasSize, self.defaultCellSize = canvas, defaultCanvasPos, defaultCanvasPos, defaultCanvasSize, defaultCellSize self.canvas, self.canvasPos, self.defaultCanvasPos, self.defaultCanvasSize, self.defaultCellSize = canvas, defaultCanvasPos, defaultCanvasPos, defaultCanvasSize, defaultCellSize
@ -127,5 +126,6 @@ class GuiCanvasPanel(wx.Panel):
for eventType in (wx.EVT_LEFT_DOWN, wx.EVT_MOTION, wx.EVT_RIGHT_DOWN): for eventType in (wx.EVT_LEFT_DOWN, wx.EVT_MOTION, wx.EVT_RIGHT_DOWN):
self.Bind(eventType, self.onPanelInput) self.Bind(eventType, self.onPanelInput)
self.Bind(wx.EVT_PAINT, self.onPanelPaint) self.Bind(wx.EVT_PAINT, self.onPanelPaint)
self.SetScrollRate(*defaultCellSize); self.SetVirtualSize(self.winSize);
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -5,26 +5,26 @@
# #
from GuiCanvasColours import Colours from GuiCanvasColours import Colours
import wx import math, wx
class GuiCanvasWxBackend(): class GuiCanvasWxBackend():
# {{{ _drawBrushPatch(self, eventDc, patch) # {{{ _drawBrushPatch(self, eventDc, patch, point)
def _drawBrushPatch(self, eventDc, patch): def _drawBrushPatch(self, eventDc, patch, point):
absPoint = self._xlatePoint(patch) absPoint = self._xlatePoint(point)
brushBg, brushFg, pen = self._getBrushPatchColours(patch) brushBg, brushFg, pen = self._getBrushPatchColours(patch)
self._setBrushDc(brushBg, brushFg, eventDc, pen) self._setBrushDc(brushBg, brushFg, eventDc, pen)
eventDc.DrawRectangle(*absPoint, *self.cellSize) eventDc.DrawRectangle(*absPoint, *self.cellSize)
# }}} # }}}
# {{{ _drawCharPatch(self, eventDc, patch) # {{{ _drawCharPatch(self, eventDc, patch, point)
def _drawCharPatch(self, eventDc, patch): def _drawCharPatch(self, eventDc, patch, point):
absPoint, fontBitmap = self._xlatePoint(patch), wx.Bitmap(*self.cellSize) absPoint, fontBitmap = self._xlatePoint(point), wx.Bitmap(*self.cellSize)
brushBg, brushFg, pen = self._getCharPatchColours(patch) brushBg, brushFg, pen = self._getCharPatchColours(patch)
fontDc = wx.MemoryDC(); fontDc.SelectObject(fontBitmap); fontDc = wx.MemoryDC(); fontDc.SelectObject(fontBitmap);
fontDc.SetTextForeground(wx.Colour(Colours[patch[2]][:4])) fontDc.SetTextForeground(wx.Colour(Colours[patch[0]][:4]))
fontDc.SetTextBackground(wx.Colour(Colours[patch[3]][:4])) fontDc.SetTextBackground(wx.Colour(Colours[patch[1]][:4]))
fontDc.SetBrush(brushBg); fontDc.SetBackground(brushBg); fontDc.SetPen(pen); fontDc.SetBrush(brushBg); fontDc.SetBackground(brushBg); fontDc.SetPen(pen);
fontDc.SetFont(self._font) fontDc.SetFont(self._font)
fontDc.DrawRectangle(0, 0, *self.cellSize); fontDc.DrawText(patch[5], 0, 0); fontDc.DrawRectangle(0, 0, *self.cellSize); fontDc.DrawText(patch[3], 0, 0);
eventDc.Blit(*absPoint, *self.cellSize, fontDc, 0, 0) eventDc.Blit(*absPoint, *self.cellSize, fontDc, 0, 0)
# }}} # }}}
# {{{ _finiBrushesAndPens(self) # {{{ _finiBrushesAndPens(self)
@ -35,26 +35,26 @@ class GuiCanvasWxBackend():
# }}} # }}}
# {{{ _getBrushPatchColours(self, patch) # {{{ _getBrushPatchColours(self, patch)
def _getBrushPatchColours(self, patch): def _getBrushPatchColours(self, patch):
if (patch[2] != -1) and (patch[3] != -1): if (patch[0] != -1) and (patch[1] != -1):
brushBg, brushFg, pen = self._brushes[patch[2]], self._brushes[patch[3]], self._pens[patch[3]] brushBg, brushFg, pen = self._brushes[patch[0]], self._brushes[patch[1]], self._pens[patch[1]]
elif (patch[2] == -1) and (patch[3] == -1): elif (patch[0] == -1) and (patch[1] == -1):
brushBg, brushFg, pen = self._brushes[1], self._brushes[1], self._pens[1] brushBg, brushFg, pen = self._brushes[1], self._brushes[1], self._pens[1]
elif patch[2] == -1: elif patch[0] == -1:
brushBg, brushFg, pen = self._brushes[patch[3]], self._brushes[patch[3]], self._pens[patch[3]] brushBg, brushFg, pen = self._brushes[patch[1]], self._brushes[patch[1]], self._pens[patch[1]]
elif patch[3] == -1: elif patch[1] == -1:
brushBg, brushFg, pen = self._brushes[1], self._brushes[patch[2]], self._pens[1] brushBg, brushFg, pen = self._brushes[1], self._brushes[patch[0]], self._pens[1]
return (brushBg, brushFg, pen) return (brushBg, brushFg, pen)
# }}} # }}}
# {{{ _getCharPatchColours(self, patch) # {{{ _getCharPatchColours(self, patch)
def _getCharPatchColours(self, patch): def _getCharPatchColours(self, patch):
if (patch[2] != -1) and (patch[3] != -1): if (patch[0] != -1) and (patch[1] != -1):
brushBg, brushFg, pen = self._brushes[patch[3]], self._brushes[patch[2]], self._pens[patch[3]] brushBg, brushFg, pen = self._brushes[patch[1]], self._brushes[patch[0]], self._pens[patch[1]]
elif (patch[2] == -1) and (patch[3] == -1): elif (patch[0] == -1) and (patch[1] == -1):
brushBg, brushFg, pen = self._brushes[1], self._brushes[1], self._pens[1] brushBg, brushFg, pen = self._brushes[1], self._brushes[1], self._pens[1]
elif patch[2] == -1: elif patch[0] == -1:
brushBg, brushFg, pen = self._brushes[patch[3]], self._brushes[patch[3]], self._pens[patch[3]] brushBg, brushFg, pen = self._brushes[patch[1]], self._brushes[patch[1]], self._pens[patch[1]]
elif patch[3] == -1: elif patch[1] == -1:
brushBg, brushFg, pen = self._brushes[1], self._brushes[patch[2]], self._pens[1] brushBg, brushFg, pen = self._brushes[1], self._brushes[patch[0]], self._pens[1]
return (brushBg, brushFg, pen) return (brushBg, brushFg, pen)
# }}} # }}}
# {{{ _initBrushesAndPens(self) # {{{ _initBrushesAndPens(self)
@ -74,34 +74,51 @@ class GuiCanvasWxBackend():
if self._lastPen != pen: if self._lastPen != pen:
dc.SetPen(pen); self._lastPen = pen; dc.SetPen(pen); self._lastPen = pen;
# }}} # }}}
# {{{ _xlatePoint(self, patch) # {{{ _xlatePoint(self, point)
def _xlatePoint(self, patch): def _xlatePoint(self, point):
return [a * b for a, b in zip(patch[:2], self.cellSize)] return [a * b for a, b in zip(point, self.cellSize)]
# }}} # }}}
# {{{ drawCursorMaskWithJournal(self, canvasJournal, eventDc) # {{{ drawCursorMaskWithJournal(self, canvasJournal, eventDc, viewRect)
def drawCursorMaskWithJournal(self, canvasJournal, eventDc): def drawCursorMaskWithJournal(self, canvasJournal, eventDc, viewRect):
[self.drawPatch(eventDc, patch) for patch in canvasJournal.popCursor()] [self.drawPatch(eventDc, patch, viewRect) for patch in canvasJournal.popCursor()]
# }}} # }}}
# {{{ drawPatch(self, eventDc, patch) # {{{ drawPatch(self, eventDc, patch, viewRect)
def drawPatch(self, eventDc, patch): def drawPatch(self, eventDc, patch, viewRect):
if ((patch[0] >= 0) and (patch[0] < self.canvasSize[0])) \ point = [m - n for m, n in zip(patch[:2], viewRect)]
and ((patch[1] >= 0) and (patch[1] < self.canvasSize[1])): if [(c >= 0) and (c < s) for c, s in zip(point, self.canvasSize)] == [True, True]:
self._drawBrushPatch(eventDc, patch) if patch[5] == " " else self._drawCharPatch(eventDc, patch) if patch[5] == " ":
self._drawBrushPatch(eventDc, patch[2:], point)
else:
self._drawCharPatch(eventDc, patch[2:], point)
return True return True
else: else:
return False return False
# }}} # }}}
# {{{ getDeviceContext(self, parentWindow) # {{{ getDeviceContext(self, parentWindow, viewRect)
def getDeviceContext(self, parentWindow): def getDeviceContext(self, parentWindow, viewRect):
eventDc = wx.BufferedDC(wx.ClientDC(parentWindow), self.canvasBitmap) if viewRect == (0, 0):
eventDc = wx.BufferedDC(wx.ClientDC(parentWindow), self.canvasBitmap)
else:
eventDc = wx.ClientDC(parentWindow)
self._lastBrushBg, self._lastBrushFg, self._lastPen = None, None, None self._lastBrushBg, self._lastBrushFg, self._lastPen = None, None, None
return eventDc return eventDc
# }}} # }}}
# {{{ onPanelPaintEvent(self, panelEvent, panelWindow) # {{{ onPanelPaintEvent(self, canvasSize, cellSize, clientSize, panelWindow, viewRect)
def onPanelPaintEvent(self, panelEvent, panelWindow): def onPanelPaintEvent(self, canvasSize, cellSize, clientSize, panelWindow, viewRect):
if self.canvasBitmap != None: if self.canvasBitmap != None:
eventDc = wx.BufferedPaintDC(panelWindow, self.canvasBitmap) if viewRect == (0, 0):
eventDc = wx.BufferedPaintDC(panelWindow, self.canvasBitmap)
else:
canvasSize = [a - b for a, b in zip(canvasSize, viewRect)]
clientSize = [math.ceil(m / n) for m, n in zip(clientSize, cellSize)]
viewSize = [min(m, n) for m, n in zip(canvasSize, clientSize)]
viewSize = [m * n for m, n in zip(cellSize, viewSize)]
canvasDc = wx.MemoryDC(); canvasDc.SelectObject(self.canvasBitmap);
viewDc = wx.MemoryDC(); viewBitmap = wx.Bitmap(viewSize); viewDc.SelectObject(viewBitmap);
viewDc.Blit(0, 0, *viewSize, canvasDc, *[m * n for m, n in zip(cellSize, viewRect)])
canvasDc.SelectObject(wx.NullBitmap); viewDc.SelectObject(wx.NullBitmap);
eventDc = wx.BufferedPaintDC(panelWindow, viewBitmap)
# }}} # }}}
# {{{ reset(self, canvasSize, cellSize): # {{{ reset(self, canvasSize, cellSize):
def reset(self, canvasSize, cellSize): def reset(self, canvasSize, cellSize):
@ -121,12 +138,12 @@ class GuiCanvasWxBackend():
self.canvasSize, self.cellSize = canvasSize, cellSize self.canvasSize, self.cellSize = canvasSize, cellSize
self._font = wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL) self._font = wx.Font(8, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
# }}} # }}}
# {{{ xlateEventPoint(self, event, eventDc) # {{{ xlateEventPoint(self, event, eventDc, viewRect)
def xlateEventPoint(self, event, eventDc): def xlateEventPoint(self, event, eventDc, viewRect):
eventPoint = event.GetLogicalPosition(eventDc) eventPoint = event.GetLogicalPosition(eventDc)
rectX, rectY = eventPoint.x - (eventPoint.x % self.cellSize[0]), eventPoint.y - (eventPoint.y % self.cellSize[1]) rectX, rectY = eventPoint.x - (eventPoint.x % self.cellSize[0]), eventPoint.y - (eventPoint.y % self.cellSize[1])
mapX, mapY = int(rectX / self.cellSize[0] if rectX else 0), int(rectY / self.cellSize[1] if rectY else 0) mapX, mapY = int(rectX / self.cellSize[0] if rectX else 0), int(rectY / self.cellSize[1] if rectY else 0)
return (mapX, mapY) return [m + n for m, n in zip((mapX, mapY), viewRect)]
# }}} # }}}
# {{{ __del__(self): destructor method # {{{ __del__(self): destructor method

View File

@ -124,6 +124,10 @@ class GuiFrame(wx.Frame):
def onInput(self, event): def onInput(self, event):
eventId = event.GetId(); self.itemsById[eventId](self.canvasPanel.interface, event); eventId = event.GetId(); self.itemsById[eventId](self.canvasPanel.interface, event);
# }}} # }}}
# {{{ onMouseWheel(self, event)
def onMouseWheel(self, event):
self.canvasPanel.GetEventHandler().ProcessEvent(event)
# }}}
# #
# __init__(self, canvasInterface, parent, appSize=(840, 630), defaultCanvasPos=(0, 75), defaultCanvasSize=(100, 30), defaultCellSize=(7, 14)): initialisation method # __init__(self, canvasInterface, parent, appSize=(840, 630), defaultCanvasPos=(0, 75), defaultCanvasSize=(100, 30), defaultCellSize=(7, 14)): initialisation method
@ -157,6 +161,8 @@ class GuiFrame(wx.Frame):
self.canvasPanel.interface.canvasTool(self.canvasPanel.interface.canvasTool, 5)(self.canvasPanel.interface, None) self.canvasPanel.interface.canvasTool(self.canvasPanel.interface.canvasTool, 5)(self.canvasPanel.interface, None)
self.canvasPanel.interface.update(brushSize=self.canvasPanel.brushSize, colours=self.canvasPanel.brushColours) self.canvasPanel.interface.update(brushSize=self.canvasPanel.brushSize, colours=self.canvasPanel.brushColours)
self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
# Set focus on & show window # Set focus on & show window
self.SetFocus(); self.Show(True); self.SetFocus(); self.Show(True);

View File

@ -7,12 +7,12 @@
class Tool(): class Tool():
parentCanvas = None parentCanvas = None
# {{{ onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc): # {{{ onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc, viewRect):
def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc): def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc, viewRect):
return True return True
# }}} # }}}
# {{{ onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # {{{ onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
return () return ()
# }}} # }}}

View File

@ -10,8 +10,8 @@ class ToolCircle(Tool):
name = "Circle" name = "Circle"
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
brushColours = brushColours.copy() brushColours = brushColours.copy()
if isLeftDown: if isLeftDown:
brushColours[1] = brushColours[0] brushColours[1] = brushColours[0]
@ -29,8 +29,8 @@ class ToolCircle(Tool):
atPoint[1] + int(originPoint[1] + brushY), \ atPoint[1] + int(originPoint[1] + brushY), \
*brushColours, 0, " "] *brushColours, 0, " "]
if isLeftDown or isRightDown: if isLeftDown or isRightDown:
dispatchFn(eventDc, False, patch); dispatchFn(eventDc, True, patch); dispatchFn(eventDc, False, patch, viewRect); dispatchFn(eventDc, True, patch, viewRect);
else: else:
dispatchFn(eventDc, True, patch) dispatchFn(eventDc, True, patch, viewRect)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -10,8 +10,8 @@ class ToolFill(Tool):
name = "Fill" name = "Fill"
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
pointStack, pointsDone = [list(atPoint)], [] pointStack, pointsDone = [list(atPoint)], []
testColour = self.parentCanvas.canvas.map[atPoint[1]][atPoint[0]][0:2] testColour = self.parentCanvas.canvas.map[atPoint[1]][atPoint[0]][0:2]
if isLeftDown or isRightDown: if isLeftDown or isRightDown:
@ -23,7 +23,7 @@ class ToolFill(Tool):
if (pointCell[0:2] == testColour) \ if (pointCell[0:2] == testColour) \
or ((pointCell[3] == " ") and (pointCell[1] == testColour[1])): or ((pointCell[3] == " ") and (pointCell[1] == testColour[1])):
if not point in pointsDone: if not point in pointsDone:
dispatchFn(eventDc, False, [*point, brushColours[0], brushColours[0], 0, " "]) dispatchFn(eventDc, False, [*point, brushColours[0], brushColours[0], 0, " "], viewRect)
if point[0] > 0: if point[0] > 0:
pointStack.append([point[0] - 1, point[1]]) pointStack.append([point[0] - 1, point[1]])
if point[0] < (self.parentCanvas.canvas.size[0] - 1): if point[0] < (self.parentCanvas.canvas.size[0] - 1):

View File

@ -30,9 +30,9 @@ class ToolLine(Tool):
originPoint[1] + lineX * lineXY + lineY * lineYY, \ originPoint[1] + lineX * lineXY + lineY * lineYY, \
*brushColours, 0, " "] *brushColours, 0, " "]
if isCursor: if isCursor:
dispatchFn(eventDc, False, patch); dispatchFn(eventDc, True, patch); dispatchFn(eventDc, False, patch, viewRect); dispatchFn(eventDc, True, patch, viewRect);
else: else:
dispatchFn(eventDc, True, patch) dispatchFn(eventDc, True, patch, viewRect)
if lineD > 0: if lineD > 0:
lineD -= pointDelta[0]; lineY += 1; lineD -= pointDelta[0]; lineY += 1;
lineD += pointDelta[1] lineD += pointDelta[1]
@ -47,8 +47,8 @@ class ToolLine(Tool):
# }}} # }}}
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
brushColours = brushColours.copy() brushColours = brushColours.copy()
if isLeftDown: if isLeftDown:
brushColours[1] = brushColours[0] brushColours[1] = brushColours[0]
@ -59,7 +59,7 @@ class ToolLine(Tool):
if self.toolState == self.TS_NONE: if self.toolState == self.TS_NONE:
if isLeftDown or isRightDown: if isLeftDown or isRightDown:
self.toolColours, self.toolOriginPoint, self.toolState = brushColours, list(atPoint), self.TS_ORIGIN self.toolColours, self.toolOriginPoint, self.toolState = brushColours, list(atPoint), self.TS_ORIGIN
dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, " "]) dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, " "], viewRect)
elif self.toolState == self.TS_ORIGIN: elif self.toolState == self.TS_ORIGIN:
originPoint, targetPoint = self.toolOriginPoint, list(atPoint) originPoint, targetPoint = self.toolOriginPoint, list(atPoint)
self._getLine(self.toolColours, brushSize, dispatchFn, eventDc, isLeftDown or isRightDown, originPoint, targetPoint) self._getLine(self.toolColours, brushSize, dispatchFn, eventDc, isLeftDown or isRightDown, originPoint, targetPoint)

View File

@ -10,8 +10,8 @@ class ToolRect(Tool):
name = "Rectangle" name = "Rectangle"
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
brushColours = brushColours.copy() brushColours = brushColours.copy()
if isLeftDown: if isLeftDown:
brushColours[1] = brushColours[0] brushColours[1] = brushColours[0]
@ -26,8 +26,8 @@ class ToolRect(Tool):
for brushCol in range(brushSize[0]): for brushCol in range(brushSize[0]):
patch = [atPoint[0] + brushCol, atPoint[1] + brushRow, *brushColours, 0, " "] patch = [atPoint[0] + brushCol, atPoint[1] + brushRow, *brushColours, 0, " "]
if isLeftDown or isRightDown: if isLeftDown or isRightDown:
dispatchFn(eventDc, False, patch); dispatchFn(eventDc, True, patch); dispatchFn(eventDc, False, patch, viewRect); dispatchFn(eventDc, True, patch, viewRect);
else: else:
dispatchFn(eventDc, True, patch) dispatchFn(eventDc, True, patch, viewRect)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -36,19 +36,19 @@ class ToolSelect(Tool):
curColours = [0, 0] curColours = [0, 0]
for rectX in range(rectFrame[0][0], rectFrame[1][0] + 1): for rectX in range(rectFrame[0][0], rectFrame[1][0] + 1):
curColours = [1, 1] if curColours == [0, 0] else [0, 0] curColours = [1, 1] if curColours == [0, 0] else [0, 0]
dispatchFn(eventDc, True, [rectX, rectFrame[0][1], *curColours, 0, " "]) dispatchFn(eventDc, True, [rectX, rectFrame[0][1], *curColours, 0, " "], viewRect)
dispatchFn(eventDc, True, [rectX, rectFrame[1][1], *curColours, 0, " "]) dispatchFn(eventDc, True, [rectX, rectFrame[1][1], *curColours, 0, " "], viewRect)
for rectY in range(rectFrame[0][1], rectFrame[1][1] + 1): for rectY in range(rectFrame[0][1], rectFrame[1][1] + 1):
curColours = [1, 1] if curColours == [0, 0] else [0, 0] curColours = [1, 1] if curColours == [0, 0] else [0, 0]
dispatchFn(eventDc, True, [rectFrame[0][0], rectY, *curColours, 0, " "]) dispatchFn(eventDc, True, [rectFrame[0][0], rectY, *curColours, 0, " "], viewRect)
dispatchFn(eventDc, True, [rectFrame[1][0], rectY, *curColours, 0, " "]) dispatchFn(eventDc, True, [rectFrame[1][0], rectY, *curColours, 0, " "], viewRect)
# }}} # }}}
# {{{ _mouseEventTsNone(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown) # {{{ _mouseEventTsNone(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown)
def _mouseEventTsNone(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown): def _mouseEventTsNone(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown):
if isLeftDown: if isLeftDown:
self.targetRect, self.toolState = [list(atPoint), []], self.TS_ORIGIN self.targetRect, self.toolState = [list(atPoint), []], self.TS_ORIGIN
else: else:
dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, " "]) dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, " "], viewRect)
# }}} # }}}
# {{{ _mouseEventTsOrigin(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown) # {{{ _mouseEventTsOrigin(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown)
def _mouseEventTsOrigin(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown): def _mouseEventTsOrigin(self, atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown):
@ -98,8 +98,8 @@ class ToolSelect(Tool):
# }}} # }}}
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
if self.toolState == self.TS_NONE: if self.toolState == self.TS_NONE:
self._mouseEventTsNone(atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown) self._mouseEventTsNone(atPoint, brushColours, dispatchFn, eventDc, isDragging, isLeftDown, isRightDown)
elif self.toolState == self.TS_ORIGIN: elif self.toolState == self.TS_ORIGIN:

View File

@ -16,6 +16,6 @@ class ToolSelectClone(ToolSelect):
for numCol in range(len(self.toolSelectMap[numRow])): for numCol in range(len(self.toolSelectMap[numRow])):
cellOld = self.toolSelectMap[numRow][numCol] cellOld = self.toolSelectMap[numRow][numCol]
rectX, rectY = selectRect[0][0] + numCol, selectRect[0][1] + numRow rectX, rectY = selectRect[0][0] + numCol, selectRect[0][1] + numRow
dispatchFn(eventDc, isCursor, [rectX + disp[0], rectY + disp[1], *cellOld]) dispatchFn(eventDc, isCursor, [rectX + disp[0], rectY + disp[1], *cellOld], viewRect)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -14,11 +14,11 @@ class ToolSelectMove(ToolSelect):
def onSelectEvent(self, disp, dispatchFn, eventDc, isCursor, newToolRect, selectRect): def onSelectEvent(self, disp, dispatchFn, eventDc, isCursor, newToolRect, selectRect):
for numRow in range(len(self.toolSelectMap)): for numRow in range(len(self.toolSelectMap)):
for numCol in range(len(self.toolSelectMap[numRow])): for numCol in range(len(self.toolSelectMap[numRow])):
dispatchFn(eventDc, isCursor, [self.srcRect[0] + numCol, self.srcRect[1] + numRow, 1, 1, 0, " "]) dispatchFn(eventDc, isCursor, [self.srcRect[0] + numCol, self.srcRect[1] + numRow, 1, 1, 0, " "], viewRect)
for numRow in range(len(self.toolSelectMap)): for numRow in range(len(self.toolSelectMap)):
for numCol in range(len(self.toolSelectMap[numRow])): for numCol in range(len(self.toolSelectMap[numRow])):
cellOld = self.toolSelectMap[numRow][numCol] cellOld = self.toolSelectMap[numRow][numCol]
rectX, rectY = selectRect[0][0] + numCol, selectRect[0][1] + numRow rectX, rectY = selectRect[0][0] + numCol, selectRect[0][1] + numRow
dispatchFn(eventDc, isCursor, [rectX + disp[0], rectY + disp[1], *cellOld]) dispatchFn(eventDc, isCursor, [rectX + disp[0], rectY + disp[1], *cellOld], viewRect)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -11,8 +11,8 @@ class ToolText(Tool):
name = "Text" name = "Text"
# #
# onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc) # onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc, viewRect)
def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc): def onKeyboardEvent(self, event, atPoint, brushColours, brushSize, keyChar, dispatchFn, eventDc, viewRect):
keyModifiers = event.GetModifiers() keyModifiers = event.GetModifiers()
if keyModifiers != wx.MOD_NONE \ if keyModifiers != wx.MOD_NONE \
and keyModifiers != wx.MOD_SHIFT: and keyModifiers != wx.MOD_SHIFT:
@ -20,7 +20,7 @@ class ToolText(Tool):
else: else:
if self.textPos == None: if self.textPos == None:
self.textPos = list(atPoint) self.textPos = list(atPoint)
dispatchFn(eventDc, False, [*self.textPos, *brushColours, 0, keyChar]) dispatchFn(eventDc, False, [*self.textPos, *brushColours, 0, keyChar], viewRect)
if self.textPos[0] < (self.parentCanvas.canvas.size[0] - 1): if self.textPos[0] < (self.parentCanvas.canvas.size[0] - 1):
self.textPos[0] += 1 self.textPos[0] += 1
elif self.textPos[1] < (self.parentCanvas.canvas.size[1] - 1): elif self.textPos[1] < (self.parentCanvas.canvas.size[1] - 1):
@ -30,11 +30,11 @@ class ToolText(Tool):
return False return False
# #
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc) # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect)
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc, viewRect):
if isLeftDown or isRightDown: if isLeftDown or isRightDown:
self.textPos = list(atPoint) self.textPos = list(atPoint)
dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, "_"]) dispatchFn(eventDc, True, [*atPoint, *brushColours, 0, "_"], viewRect)
# __init__(self, *args): initialisation method # __init__(self, *args): initialisation method
def __init__(self, *args): def __init__(self, *args):