libgui/GuiCanvasWxBackend.py:GuiBufferedDC(): implement double-buffered wx.MemoryDC() honouring view{Rect,Size}.

libgui/GuiCanvasWxBackend.py:{getDeviceContext,onPaint}(): use GuiBufferedDC() if viewRect > (0, 0).
libroar/RoarCanvas{CommandsTools,Window}.py: updated.
assets/text/TODO: updated.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-11 08:28:56 +02:00
parent 05da368849
commit 474f3be4a7
4 changed files with 47 additions and 38 deletions

View File

@ -1,20 +1,16 @@
1) Implement ANSI CSI CU[BDPU] sequences & italic
2) Incremental auto{load,save} & {backup,restore}
3) Implement instrumentation & unit tests, document
4) Open and toggle a reference image in the background
5) Client-Server or Peer-to-Peer realtime collaboration
6) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.)
7) Hotkey & graphical interfaces to {composed,parametrised} tools
8) Layers, layout (e.g. for comics, zines, etc.) & asset management (e.g. kade, lion, etc.) & traits w/ {inserting,merging,linking}
9) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...)
10) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools:
2) Implement instrumentation & unit tests, document
3) Open and toggle a reference image in the background
4) Client-Server or Peer-to-Peer realtime collaboration
5) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.)
6) Hotkey & graphical interfaces to {composed,parametrised} tools
7) Incremental auto{load,save} & {backup,restore} (needs Settings window)
8) GUI: a) switch from wxPython to GTK b) {copy,cut,insert from,paste}, {de,in}crease cell size c) MRU {directories,files}
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, ...)
11) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools:
a) geometric primitives (arrow, circle, cloud/speech bubble, curve, heart, hexagon, line, pentagon, polygon, rhombus, triangle, square, star)
b) regions (crop, duplicate, erase, fill, invert, measure, pick, rotate, scale, select, shift, slice, tile, translate)
c) text (edit, Unicode sets)
11) GUI:
a) Settings panel
b) switch from wxPython to GTK
c) {fix,reduce} flickering when viewRect > (0, 0)
d) {copy,cut,insert from,paste}, {de,in}crease cell size
vim:ff=dos tw=0

View File

@ -7,6 +7,27 @@
from GuiCanvasColours import Colours
import math, wx
class GuiBufferedDC(wx.MemoryDC):
# {{{ __del__(self)
def __del__(self):
self.dc.Blit(0, 0, *self.viewSize, self, 0, 0)
self.SelectObject(wx.NullBitmap)
# }}}
# {{{ __init__(self, backend, buffer, clientSize, dc, viewRect)
def __init__(self, backend, buffer, clientSize, dc, viewRect):
super().__init__()
canvasSize = [a - b for a, b in zip(backend.canvasSize, viewRect)]
clientSize = [math.ceil(m / n) for m, n in zip(clientSize, backend.cellSize)]
viewRect = [m * n for m, n in zip(backend.cellSize, viewRect)]
viewSize = [min(m, n) for m, n in zip(canvasSize, clientSize)]
viewSize = [m * n for m, n in zip(backend.cellSize, viewSize)]
bitmap = wx.Bitmap(viewSize); self.SelectObject(bitmap);
bufferDc = wx.MemoryDC(); bufferDc.SelectObject(buffer);
self.Blit(0, 0, *viewSize, bufferDc, *viewRect)
bufferDc.SelectObject(wx.NullBitmap)
self.dc, self.viewSize = dc, viewSize
# }}}
class GuiCanvasWxBackend():
# {{{ _drawBrushPatch(self, eventDc, patch, point)
def _drawBrushPatch(self, eventDc, patch, point):
@ -95,30 +116,22 @@ class GuiCanvasWxBackend():
else:
return False
# }}}
# {{{ getDeviceContext(self, parentWindow, viewRect)
def getDeviceContext(self, parentWindow, viewRect):
# {{{ getDeviceContext(self, clientSize, parentWindow, viewRect)
def getDeviceContext(self, clientSize, parentWindow, viewRect):
if viewRect == (0, 0):
eventDc = wx.BufferedDC(wx.ClientDC(parentWindow), self.canvasBitmap)
else:
eventDc = wx.ClientDC(parentWindow)
eventDc = GuiBufferedDC(self, self.canvasBitmap, clientSize, wx.ClientDC(parentWindow), viewRect)
self._lastBrushBg, self._lastBrushFg, self._lastPen = None, None, None
return eventDc
# }}}
# {{{ onPaintEvent(self, canvasSize, cellSize, clientSize, panelWindow, viewRect)
def onPaintEvent(self, canvasSize, cellSize, clientSize, panelWindow, viewRect):
# {{{ onPaint(self, clientSize, panelWindow, viewRect)
def onPaint(self, clientSize, panelWindow, viewRect):
if self.canvasBitmap != None:
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)
eventDc = GuiBufferedDC(self, self.canvasBitmap, clientSize, wx.PaintDC(panelWindow), viewRect)
# }}}
# {{{ resize(self, canvasSize, cellSize):
def resize(self, canvasSize, cellSize):

View File

@ -31,7 +31,7 @@ class RoarCanvasCommandsTools():
toolBar.ToggleTool(self.canvasTool.attrList[idx]["id"], True)
self.update(toolName=self.currentTool.name)
viewRect = self.parentCanvas.GetViewStart()
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas, viewRect)
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas, viewRect)
self.parentCanvas.applyTool(eventDc, True, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, viewRect)
setattr(canvasTool_, "attrDict", f.attrList[idx])
setattr(canvasTool_, "isSelect", True)

View File

@ -38,12 +38,12 @@ class RoarCanvasWindow(GuiWindow):
# }}}
# {{{ dispatchDeltaPatches(self, deltaPatches)
def dispatchDeltaPatches(self, deltaPatches):
eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
for patch in deltaPatches:
if patch == None:
continue
elif patch[0] == "resize":
del eventDc; self.resize(patch[1:], False); eventDc = self.backend.getDeviceContext(self, self.GetViewStart());
del eventDc; self.resize(patch[1:], False); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart());
else:
self.canvas._commitPatch(patch); self.backend.drawPatch(eventDc, patch, self.GetViewStart());
# }}}
@ -64,7 +64,7 @@ class RoarCanvasWindow(GuiWindow):
if self.canvas.resize(newSize, commitUndo):
super().resize([a * b for a, b in zip(newSize, self.backend.cellSize)])
self.backend.resize(newSize, self.backend.cellSize)
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self, viewRect);
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
if deltaSize[0] > 0:
for numRow in range(oldSize[1]):
for numNewCol in range(oldSize[0], newSize[0]):
@ -79,7 +79,7 @@ class RoarCanvasWindow(GuiWindow):
def update(self, newSize, commitUndo=True, newCanvas=None):
self.resize(newSize, commitUndo)
self.canvas.update(newSize, newCanvas)
eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
for numRow in range(newSize[1]):
for numCol in range(newSize[0]):
self.backend.drawPatch(eventDc, [numCol, numRow, *self.canvas.map[numRow][numCol]], self.GetViewStart())
@ -87,19 +87,19 @@ class RoarCanvasWindow(GuiWindow):
# {{{ onKeyboardInput(self, event)
def onKeyboardInput(self, event):
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self, viewRect);
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
keyChar, keyModifiers = chr(event.GetUnicodeKey()), event.GetModifiers()
if not self.applyTool(eventDc, False, keyChar, keyModifiers, None, None, None, None, self.commands.currentTool, viewRect):
event.Skip()
# }}}
# {{{ onLeaveWindow(self, event)
def onLeaveWindow(self, event):
eventDc = self.backend.getDeviceContext(self, self.GetViewStart())
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc, self.GetViewStart())
# }}}
# {{{ onMouseInput(self, event)
def onMouseInput(self, event):
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self, viewRect);
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
mouseDragging, mouseLeftDown, mouseRightDown = event.Dragging(), event.LeftIsDown(), event.RightIsDown()
mapPoint = self.backend.xlateEventPoint(event, eventDc, viewRect)
if not self.applyTool(eventDc, True, None, None, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, self.commands.currentTool, viewRect):
@ -107,13 +107,13 @@ class RoarCanvasWindow(GuiWindow):
# }}}
# {{{ onPaint(self, event)
def onPaint(self, event):
self.backend.onPaintEvent(self.canvas.size, self.cellSize, self.GetClientSize(), self, self.GetViewStart())
self.backend.onPaint(self.GetClientSize(), self, self.GetViewStart())
# }}}
# {{{ onScroll(self, event)
def onScroll(self, event):
if self.canvas.dirtyCursor:
viewRect = self.GetViewStart()
eventDc = self.backend.getDeviceContext(self, viewRect)
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect)
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc, viewRect)
self.canvas.dirtyCursor = False
event.Skip()