libcanvas/CanvasColours.py, libgui/GuiCanvasColours.py: split from libcanvas/CanvasColours.py.

libcanvas/Canvas.py, libgui/GuiCanvasPanel.py: split from libcanvas/Canvas.py.
libcanvas/CanvasImportStore.py:import{Ansi{Buffer,File},SauceFile}(): fixed (via spoke.)
{libgui/Gui{CanvasInterface,Frame},libtools/Tool{Fill,Select,Text},roar}.py: updated.
libgui/GuiCanvasWxBackend.py: merged from libcanvas/CanvasBackend.py.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-07 10:39:26 +02:00
parent c28c2f87ab
commit f3140d4b3d
13 changed files with 361 additions and 339 deletions

View File

@ -1,14 +1,15 @@
1) General {cleanup,refactor}
2) Implement ANSI CSI CU[BDPU] sequences
3) Incremental auto{load,save} & {backup,restore}
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) GUI: a) scrollbar b) switch from wxPython to GTK c) revisit About dialogue
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:
2) Transparent {back,fore}ground colour
3) Implement ANSI CSI CU[BDPU] sequences
4) Incremental auto{load,save} & {backup,restore}
5) Open and toggle a reference image in the background
6) Client-Server or Peer-to-Peer realtime collaboration
7) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.)
8) Hotkey & graphical interfaces to {composed,parametrised} tools
9) GUI: a) scrollbar b) switch from wxPython to GTK c) revisit About dialogue
10) Layers, layout (e.g. for comics, zines, etc.) & asset management (e.g. kade, lion, etc.) & traits w/ {inserting,merging,linking}
11) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...)
13) 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)

View File

@ -4,194 +4,90 @@
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
from CanvasBackend import CanvasBackend
from CanvasJournal import CanvasJournal
from CanvasExportStore import CanvasExportStore, havePIL, haveUrllib
from CanvasExportStore import CanvasExportStore
from CanvasImportStore import CanvasImportStore
import wx
from CanvasJournal import CanvasJournal
class Canvas(wx.Panel):
class Canvas():
"""XXX"""
# {{{ _commitPatch(self, patch): XXX
def _commitPatch(self, patch):
self.canvasMap[patch[1]][patch[0]] = patch[2:]
# }}}
# {{{ _dispatchDeltaPatches(self, deltaPatches): XXX
def _dispatchDeltaPatches(self, deltaPatches):
eventDc = self.canvasBackend.getDeviceContext(self)
for patch in deltaPatches:
if patch[0] == "resize":
del eventDc
self.resize(patch[1:], False)
eventDc = self.canvasBackend.getDeviceContext(self)
elif self.canvasBackend.drawPatch(eventDc, patch):
self._commitPatch(patch)
self.parentFrame.onCanvasUpdate(undoLevel=self.canvasJournal.patchesUndoLevel)
# }}}
# {{{ _dispatchPatch(self, eventDc, isCursor, patch, commitUndo=True): XXX
def _dispatchPatch(self, eventDc, isCursor, patch, commitUndo=True):
if not self._canvasDirtyCursor:
self.canvasBackend.drawCursorMaskWithJournal(self.canvasJournal, eventDc)
self._canvasDirtyCursor = True
if self.canvasBackend.drawPatch(eventDc, patch):
patchDeltaCell = self.canvasMap[patch[1]][patch[0]]
patchDelta = [*patch[0:2], *patchDeltaCell]
if isCursor and commitUndo:
self.canvasJournal.pushCursor(patchDelta)
else:
if commitUndo:
if not self._canvasDirty:
self.canvasJournal.pushDeltas([], []); self._canvasDirty = True;
self.canvasJournal.updateCurrentDeltas(patch, patchDelta)
self._commitPatch(patch)
self.map[patch[1]][patch[0]] = patch[2:]
# }}}
# {{{ onPanelClose(self, event): XXX
def onPanelClose(self, event):
self.Destroy()
# }}}
# {{{ onPanelEnterWindow(self, event): XXX
def onPanelEnterWindow(self, event):
self.parentFrame.SetFocus()
# }}}
# {{{ onPanelInput(self, event): XXX
def onPanelInput(self, event):
eventDc = self.canvasBackend.getDeviceContext(self)
eventType = event.GetEventType()
self._canvasDirty = self._canvasDirtyCursor = False
tool = self.canvasInterface.canvasTool
if eventType == wx.wxEVT_CHAR:
mapPoint = self.brushPos
doSkip = tool.onKeyboardEvent( \
event, mapPoint, self.brushColours, self.brushSize, \
chr(event.GetUnicodeKey()), self._dispatchPatch, eventDc)
if doSkip:
event.Skip(); return;
# {{{ dispatchPatch(self, isCursor, patch, commitUndo=True): XXX
def dispatchPatch(self, isCursor, patch, commitUndo=True):
patchDeltaCell = self.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
if isCursor:
self.journal.pushCursor(patchDelta)
else:
mapPoint = self.canvasBackend.xlateEventPoint(event, eventDc)
if mapPoint[0] >= self.canvasSize[0] \
or mapPoint[1] >= self.canvasSize[1]:
return
self.brushPos = mapPoint
tool.onMouseEvent( \
event, mapPoint, self.brushColours, self.brushSize, \
event.Dragging(), event.LeftIsDown(), event.RightIsDown(), \
self._dispatchPatch, eventDc)
if self._canvasDirty:
self.parentFrame.onCanvasUpdate(cellPos=self.brushPos, undoLevel=self.canvasJournal.patchesUndoLevel)
if eventType == wx.wxEVT_MOTION:
self.parentFrame.onCanvasUpdate(cellPos=mapPoint)
# }}}
# {{{ onPanelLeaveWindow(self, event): XXX
def onPanelLeaveWindow(self, event):
eventDc = self.canvasBackend.getDeviceContext(self)
self.canvasBackend.drawCursorMaskWithJournal(self.canvasJournal, eventDc)
# }}}
# {{{ onPanelPaint(self, event): XXX
def onPanelPaint(self, event):
self.canvasBackend.onPanelPaintEvent(event, self)
# }}}
# {{{ onStoreUpdate(self, newCanvasSize, newCanvas=None): XXX
def onStoreUpdate(self, newCanvasSize, newCanvas=None):
self.resize(newCanvasSize=newCanvasSize, commitUndo=False)
eventDc = self.canvasBackend.getDeviceContext(self)
for numRow in range(self.canvasSize[1]):
for numCol in range(self.canvasSize[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]])
wx.SafeYield()
# }}}
# {{{ resize(self, newCanvasSize, commitUndo=True): XXX
def resize(self, newCanvasSize, commitUndo=True):
if newCanvasSize != self.canvasSize:
self._canvasDirty, self._canvasDirtyCursor = False, False
if self.canvasMap == None:
self.canvasMap, oldCanvasSize = [], [0, 0]
else:
oldCanvasSize = self.canvasSize
deltaCanvasSize = [b - a for a, b in zip(oldCanvasSize, newCanvasSize)]
newWinSize = [a * b for a, b in zip(newCanvasSize, self.canvasBackend.cellSize)]
self.SetMinSize(newWinSize); self.SetSize(wx.DefaultCoord, wx.DefaultCoord, *newWinSize);
curWindow = self
while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent();
self.canvasBackend.resize(newCanvasSize, self.canvasBackend.cellSize)
eventDc = self.canvasBackend.getDeviceContext(self)
self.canvasJournal.resetCursor()
if commitUndo:
undoPatches, redoPatches = ["resize", *oldCanvasSize], ["resize", *newCanvasSize]
if not self._canvasDirty:
self.canvasJournal.pushDeltas([], []); self._canvasDirty = True;
self.canvasJournal.updateCurrentDeltas(redoPatches, undoPatches)
if deltaCanvasSize[0] < 0:
for numRow in range(oldCanvasSize[1]):
if commitUndo:
for numCol in range((oldCanvasSize[0] + deltaCanvasSize[0]), oldCanvasSize[0]):
if not self._canvasDirty:
self.canvasJournal.pushDeltas([], []); self._canvasDirty = True;
self.canvasJournal.updateCurrentDeltas([numCol, numRow, 1, 1, 0, " "], [numCol, numRow, *self.canvasMap[numRow][numCol]])
del self.canvasMap[numRow][-1:(deltaCanvasSize[0]-1):-1]
else:
for numRow in range(oldCanvasSize[1]):
self.canvasMap[numRow].extend([[1, 1, 0, " "]] * deltaCanvasSize[0])
for numNewCol in range(oldCanvasSize[0], newCanvasSize[0]):
self._dispatchPatch(eventDc, False, [numNewCol, numRow, 1, 1, 0, " "], commitUndo)
if deltaCanvasSize[1] < 0:
if commitUndo:
for numRow in range((oldCanvasSize[1] + deltaCanvasSize[1]), oldCanvasSize[1]):
for numCol in range(oldCanvasSize[0] + deltaCanvasSize[0]):
if not self._canvasDirty:
self.canvasJournal.pushDeltas([], []); self._canvasDirty = True;
self.canvasJournal.updateCurrentDeltas([numCol, numRow, 1, 1, 0, " "], [numCol, numRow, *self.canvasMap[numRow][numCol]])
del self.canvasMap[-1:(deltaCanvasSize[1]-1):-1]
else:
for numNewRow in range(oldCanvasSize[1], newCanvasSize[1]):
self.canvasMap.extend([[[1, 1, 0, " "]] * newCanvasSize[0]])
for numNewCol in range(newCanvasSize[0]):
self._dispatchPatch(eventDc, False, [numNewCol, numNewRow, 1, 1, 0, " "], commitUndo)
self.canvasSize = newCanvasSize; wx.SafeYield(); self.parentFrame.onCanvasUpdate(size=newCanvasSize, undoLevel=self.canvasJournal.patchesUndoLevel)
if not self.dirty:
self.journal.pushDeltas([], []); self.dirty = True;
self.journal.updateCurrentDeltas(patch, patchDelta)
self._commitPatch(patch)
# }}}
# {{{ __del__(self): destructor method
def __del__(self):
if self.canvasMap != None:
self.canvasMap.clear(); self.canvasMap = None;
# {{{ resize(self, newSize, commitUndo=True): XXX
def resize(self, newSize, commitUndo=True):
if newSize != self.size:
self.dirty = False
if self.map == None:
self.map, oldSize = [], [0, 0]
else:
oldSize = self.size
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
self.journal.resetCursor()
if commitUndo:
undoPatches, redoPatches = ["resize", *oldSize], ["resize", *newSize]
if not self.dirty:
self.journal.pushDeltas([], []); self.dirty = True;
self.journal.updateCurrentDeltas(redoPatches, undoPatches)
if deltaSize[0] < 0:
for numRow in range(oldSize[1]):
if commitUndo:
for numCol in range((oldSize[0] + deltaSize[0]), oldSize[0]):
if not self.dirty:
self.journal.pushDeltas([], []); self.dirty = True;
self.journal.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
del self.map[numRow][-1:(deltaSize[0]-1):-1]
else:
for numRow in range(oldSize[1]):
self.map[numRow].extend([[1, 1, 0, " "]] * deltaSize[0])
for numNewCol in range(oldSize[0], newSize[0]):
self.dispatchPatch(False, [numNewCol, numRow, 1, 1, 0, " "], commitUndo)
if deltaSize[1] < 0:
if commitUndo:
for numRow in range((oldSize[1] + deltaSize[1]), oldSize[1]):
for numCol in range(oldSize[0] + deltaSize[0]):
if not self.dirty:
self.journal.pushDeltas([], []); self.dirty = True;
self.journal.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
del self.map[-1:(deltaSize[1]-1):-1]
else:
for numNewRow in range(oldSize[1], newSize[1]):
self.map.extend([[[1, 1, 0, " "]] * newSize[0]])
for numNewCol in range(newSize[0]):
self.dispatchPatch(False, [numNewCol, numNewRow, 1, 1, 0, " "], commitUndo)
self.size = newSize
return True
else:
return False
# }}}
# {{{ update(self, newSize, newCanvas=None): XXX
def update(self, newSize, newCanvas=None):
for numRow in range(self.size[1]):
for numCol in range(self.size[0]):
if (newCanvas != None) \
and (numRow < len(newCanvas)) \
and (numCol < len(newCanvas[numRow])):
self._commitPatch([numCol, numRow, *newCanvas[numRow][numCol]])
# }}}
#
# __init__(self, parent, parentFrame, canvasInterface, defaultCanvasPos, defaultCanvasSize, defaultCellSize): initialisation method
def __init__(self, parent, parentFrame, canvasInterface, defaultCanvasPos, defaultCanvasSize, defaultCellSize):
super().__init__(parent, pos=defaultCanvasPos, size=[w * h for w, h in zip(defaultCanvasSize, defaultCellSize)])
self.brushColours, self.brushPos, self.brushSize = [4, 1], [0, 0], [1, 1]
self._canvasDirty, self._canvasDirtyCursor = False, False
self.canvasMap, self.canvasPos, self.canvasSize, = None, defaultCanvasPos, defaultCanvasSize
self.defaultCanvasPos, self.defaultCanvasSize, self.defaultCellSize = defaultCanvasPos, defaultCanvasSize, defaultCellSize
self.parentFrame = parentFrame
self.parentFrame.onCanvasUpdate(brushSize=self.brushSize, colours=self.brushColours)
self.canvasBackend = CanvasBackend(defaultCanvasSize, defaultCellSize)
self.canvasJournal = CanvasJournal()
self.canvasExportStore = CanvasExportStore()
self.canvasImportStore = CanvasImportStore()
self.canvasInterface = canvasInterface(self, parentFrame)
# Bind event handlers
self.Bind(wx.EVT_CLOSE, self.onPanelClose)
self.Bind(wx.EVT_ENTER_WINDOW, self.onPanelEnterWindow)
self.Bind(wx.EVT_LEAVE_WINDOW, self.onPanelLeaveWindow)
self.parentFrame.Bind(wx.EVT_CHAR, self.onPanelInput)
for eventType in (wx.EVT_LEFT_DOWN, wx.EVT_MOTION, wx.EVT_RIGHT_DOWN):
self.Bind(eventType, self.onPanelInput)
self.Bind(wx.EVT_PAINT, self.onPanelPaint)
# __init__(self, size): initialisation method
def __init__(self, size):
self.dirty, self.dirtyCursor, self.map, self.size = False, False, None, size
self.exportStore, self.importStore, self.journal = CanvasExportStore(), CanvasImportStore(), CanvasJournal()
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0

View File

@ -104,26 +104,6 @@ ColourMapNormal = [
[187, 187, 187], # Light Grey
]
# }}}
# {{{ Colours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline],
Colours = [
[255, 255, 255, 255, "White"],
[0, 0, 0, 255, "Black"],
[0, 0, 187, 255, "Blue"],
[0, 187, 0, 255, "Green"],
[255, 85, 85, 255, "Light Red"],
[187, 0, 0, 255, "Red"],
[187, 0, 187, 255, "Purple"],
[187, 187, 0, 255, "Yellow"],
[255, 255, 85, 255, "Light Yellow"],
[85, 255, 85, 255, "Light Green"],
[0, 187, 187, 255, "Cyan"],
[85, 255, 255, 255, "Light Cyan"],
[85, 85, 255, 255, "Light Blue"],
[255, 85, 255, 255, "Pink"],
[85, 85, 85, 255, "Grey"],
[187, 187, 187, 255, "Light Grey"],
];
# }}}
# {{{ MiRCARTToAnsiColours: XXX
MiRCARTToAnsiColours = [
97, # Bright White

View File

@ -6,7 +6,7 @@
#
from CanvasColours import AnsiBgToMiRCARTColours, AnsiFgToMiRCARTColours, AnsiFgBoldToMiRCARTColours
import os, re, struct, sys
import io, os, re, struct, sys
class CanvasImportStore():
"""XXX"""
@ -23,17 +23,17 @@ class CanvasImportStore():
return cellState & ~bit if cellState & bit else cellState | bit
# }}}
# {{{ importAnsiBuffer(self, inFile, encoding="cp437", width=None): XXX
def importAnsiBuffer(self, inFile, encoding="cp437", width=None):
# {{{ importAnsiBuffer(self, inBuffer, encoding="cp437", width=None): XXX
def importAnsiBuffer(self, inBuffer, encoding="cp437", width=None):
curBg, curBgAnsi, curBoldAnsi, curFg, curFgAnsi = 1, 30, False, 15, 37
done, outMap, outMaxCols = False, [[]], 0
inFileData = inFile.read().decode(encoding)
inFileChar, inFileCharMax = 0, len(inFileData)
inBufferData = inBuffer.decode(encoding)
inBufferChar, inBufferCharMax = 0, len(inBufferData)
while True:
if inFileChar >= inFileCharMax:
if inBufferChar >= inBufferCharMax:
break
else:
m = re.match("\x1b\[((?:\d{1,3};?)+m|\d+C)", inFileData[inFileChar:])
m = re.match("\x1b\[((?:\d{1,3};?)+m|\d+[ABCDEFG])", inBufferData[inBufferChar:])
if m:
if m[1][-1] == "C":
outMap[-1] += [[curFg, curBg, self._CellState.CS_NONE, " "]] * int(m[1][:-1])
@ -48,25 +48,26 @@ class CanvasImportStore():
curBoldAnsi, newFg = False, AnsiFgToMiRCARTColours[curFgAnsi]
elif ansiCode == 7:
curBgAnsi, curFgAnsi, newBg, newFg = curFgAnsi, curBgAnsi, curFg, curBg
elif ansiCode in AnsiBgToMiRCARTColours:
elif (not curBoldAnsi) and (ansiCode in AnsiBgToMiRCARTColours):
curBgAnsi, newBg = ansiCode, AnsiBgToMiRCARTColours[ansiCode]
elif ansiCode in AnsiFgBoldToMiRCARTColours:
elif curBoldAnsi and (ansiCode in AnsiFgBoldToMiRCARTColours):
curFgAnsi, newFg = ansiCode, AnsiFgBoldToMiRCARTColours[ansiCode]
elif ansiCode in AnsiFgToMiRCARTColours:
newFg = AnsiFgBoldToMiRCARTColours[ansiCode] if curBoldAnsi else AnsiFgToMiRCARTColours[ansiCode]
curFgAnsi = ansiCode
curBg = newBg if newBg != -1 else curBg; curFg = newFg if newFg != -1 else curFg;
inFileChar += len(m[0])
elif inFileData[inFileChar:inFileChar + 2] == "\r\n":
done = True; inFileChar += 2;
elif inFileData[inFileChar] in set("\r\n"):
done = True; inFileChar += 1;
inBufferChar += len(m[0])
elif inBufferData[inBufferChar:inBufferChar + 2] == "\r\n":
done = True; inBufferChar += 2;
elif inBufferData[inBufferChar] in set("\r\n"):
done = True; inBufferChar += 1;
else:
outMap[-1].append([curFg, curBg, self._CellState.CS_NONE, inFileData[inFileChar]])
inFileChar += 1
outMap[-1].append([curFg, curBg, self._CellState.CS_NONE, inBufferData[inBufferChar]])
inBufferChar += 1
if done or (width == len(outMap[-1])):
done, outMaxCols, = False, max(outMaxCols, len(outMap[-1])); outMap.append([]);
if len(outMap[0]):
if (len(outMap) > 1) \
or ((len(outMap) == 1) and len(outMap[0])):
for numRow in range(len(outMap)):
for numCol in range(len(outMap[numRow]), outMaxCols):
outMap[numRow].append([curFg, curBg, self._CellState.CS_NONE, " "])
@ -77,16 +78,17 @@ class CanvasImportStore():
# }}}
# {{{ importAnsiFile(self, inPathName, encoding="cp437"): XXX
def importAnsiFile(self, inPathName, encoding="cp437"):
return self.importAnsiBuffer(open(inPathName, "rb"), encoding)
return self.importAnsiBuffer(open(inPathName, "rb").read(), encoding)
# }}}
# {{{ importSauceFile(self, inPathName): XXX
def importSauceFile(self, inPathName):
# {{{ importSauceFile(self, inPathName, encoding="cp437"): XXX
def importSauceFile(self, inPathName, encoding="cp437"):
with open(inPathName, "rb") as inFile:
inFileStat = os.stat(inPathName); inFile.seek(inFileStat.st_size - 128, 0); inFile.seek(94);
inFileStat = os.stat(inPathName)
inFile.seek(inFileStat.st_size - 128, os.SEEK_SET); inFile.seek(94, os.SEEK_CUR);
if inFile.read(2) == b'\x01\x01':
width = struct.unpack("H", inFile.read(2))[0]
inFile.seek(0, 0); inFileData = inFile.read(inFileStat.st_size - 128);
return self.importAnsiFileBuffer(io.StringIO(inFileData), width)
return self.importAnsiBuffer(inFileData, encoding, width)
else:
return (False, "only character based ANSi SAUCE files are supported")
# }}}
@ -124,7 +126,8 @@ class CanvasImportStore():
else:
outMap[-1].append([*inCurColours, inCellState, inChar]); inCurCol += 1;
inLine, outMaxCols = inFile.readline(), max(outMaxCols, len(outMap[-1]))
if len(outMap[0]):
if (len(outMap) > 1) \
or ((len(outMap) == 1) and len(outMap[0])):
self.inSize, self.outMap = [outMaxCols, len(outMap)], outMap
return (True, None)
else:

View File

@ -0,0 +1,29 @@
#!/usr/bin/env python3
#
# GuiCanvasColours.py -- XXX
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
#
# Colours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline)
#
Colours = [
[255, 255, 255, 255, "White"],
[0, 0, 0, 255, "Black"],
[0, 0, 187, 255, "Blue"],
[0, 187, 0, 255, "Green"],
[255, 85, 85, 255, "Light Red"],
[187, 0, 0, 255, "Red"],
[187, 0, 187, 255, "Purple"],
[187, 187, 0, 255, "Yellow"],
[255, 255, 85, 255, "Light Yellow"],
[85, 255, 85, 255, "Light Green"],
[0, 187, 187, 255, "Cyan"],
[85, 255, 255, 255, "Light Cyan"],
[85, 85, 255, 255, "Light Blue"],
[255, 85, 255, 255, "Pink"],
[85, 85, 85, 255, "Grey"],
[187, 187, 187, 255, "Light Grey"],
];
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -15,7 +15,7 @@ from ToolText import ToolText
from glob import glob
from GuiCanvasInterfaceAbout import GuiCanvasInterfaceAbout
from ImgurApiKey import ImgurApiKey
import io, os, random, wx, wx.adv
import io, os, random, sys, wx, wx.adv
class GuiCanvasInterface():
"""XXX"""
@ -42,7 +42,7 @@ class GuiCanvasInterface():
self.parentCanvas.brushColours[0] = numColour
elif event.GetEventType() == wx.wxEVT_TOOL_RCLICKED:
self.parentCanvas.brushColours[1] = numColour
self.parentFrame.onCanvasUpdate(colours=self.parentCanvas.brushColours)
self.parentFrame.update(colours=self.parentCanvas.brushColours)
# }}}
# {{{ canvasCopy(self, event): XXX
def canvasCopy(self, event):
@ -82,10 +82,10 @@ class GuiCanvasInterface():
if newCanvasSize == None:
newCanvasSize = list(self.parentCanvas.defaultCanvasSize)
newMap = [[[1, 1, 0, " "] for x in range(newCanvasSize[0])] for y in range(newCanvasSize[1])]
self.parentCanvas.onStoreUpdate(newCanvasSize, newMap)
self.parentCanvas.update(newCanvasSize, False, newMap)
self.canvasPathName = None
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="", undoLevel=-1)
self.parentFrame.update(pathName="", undoLevel=-1)
# }}}
# {{{ canvasOpen(self, event): XXX
def canvasOpen(self, event):
@ -103,12 +103,11 @@ class GuiCanvasInterface():
else:
self.canvasPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
import pdb; pdb.set_trace()
rc, error = self.parentCanvas.canvasImportStore.importTextFile(self.canvasPathName)
rc, error = self.parentCanvas.canvas.importStore.importTextFile(self.canvasPathName)
if rc:
self.parentCanvas.onStoreUpdate(self.parentCanvas.canvasImportStore.inSize, self.parentCanvas.canvasImportStore.outMap)
self.parentCanvas.update(self.parentCanvas.canvas.importStore.inSize, False, self.parentCanvas.canvas.importStore.outMap)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName=self.canvasPathName, undoLevel=-1)
self.parentFrame.update(pathName=self.canvasPathName, undoLevel=-1)
return True
else:
print("error: {}".format(error), file=sys.stderr)
@ -120,7 +119,8 @@ class GuiCanvasInterface():
# }}}
# {{{ canvasRedo(self, event): XXX
def canvasRedo(self, event):
self.parentCanvas._dispatchDeltaPatches(self.parentCanvas.canvasJournal.popRedo())
self.parentCanvas.dispatchDeltaPatches(self.parentCanvas.canvas.journal.popRedo())
self.parentFrame.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.journal.patchesUndoLevel)
# }}}
# {{{ canvasSave(self, event): XXX
def canvasSave(self, event):
@ -130,8 +130,8 @@ class GuiCanvasInterface():
try:
with open(self.canvasPathName, "w", encoding="utf-8") as outFile:
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasExportStore.exportTextFile( \
self.parentCanvas.canvasMap, self.parentCanvas.canvasSize, outFile)
self.parentCanvas.canvas.exportStore.exportTextFile( \
self.parentCanvas.canvas.map, self.parentCanvas.canvas.size, outFile)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
return True
except IOError as error:
@ -148,14 +148,15 @@ class GuiCanvasInterface():
# }}}
# {{{ canvasUndo(self, event): XXX
def canvasUndo(self, event):
self.parentCanvas._dispatchDeltaPatches(self.parentCanvas.canvasJournal.popUndo())
self.parentCanvas.dispatchDeltaPatches(self.parentCanvas.canvas.journal.popUndo())
self.parentFrame.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.journal.patchesUndoLevel)
# }}}
# {{{ canvasDecrBrushHeight(self, event): XXX
def canvasDecrBrushHeight(self, event):
if self.parentCanvas.brushSize[1] > 1:
self.parentCanvas.brushSize[1] -= 1
self.parentFrame.onCanvasUpdate(brushSize=self.parentCanvas.brushSize)
self.parentFrame.update(brushSize=self.parentCanvas.brushSize)
# }}}
# {{{ canvasDecrBrushHeightWidth(self, event): XXX
def canvasDecrBrushHeightWidth(self, event):
@ -166,12 +167,12 @@ class GuiCanvasInterface():
def canvasDecrBrushWidth(self, event):
if self.parentCanvas.brushSize[0] > 1:
self.parentCanvas.brushSize[0] -= 1
self.parentFrame.onCanvasUpdate(brushSize=self.parentCanvas.brushSize)
self.parentFrame.update(brushSize=self.parentCanvas.brushSize)
# }}}
# {{{ canvasDecrCanvasHeight(self, event): XXX
def canvasDecrCanvasHeight(self, event):
if self.parentCanvas.canvasSize[1] > 1:
self.parentCanvas.resize([self.parentCanvas.canvasSize[0], self.parentCanvas.canvasSize[1] - 1])
if self.parentCanvas.canvas.size[1] > 1:
self.parentCanvas.resize([self.parentCanvas.canvas.size[0], self.parentCanvas.canvas.size[1] - 1])
# }}}
# {{{ canvasDecrCanvasHeightWidth(self, event): XXX
def canvasDecrCanvasHeightWidth(self, event):
@ -180,13 +181,13 @@ class GuiCanvasInterface():
# }}}
# {{{ canvasDecrCanvasWidth(self, event): XXX
def canvasDecrCanvasWidth(self, event):
if self.parentCanvas.canvasSize[0] > 1:
self.parentCanvas.resize([self.parentCanvas.canvasSize[0] - 1, self.parentCanvas.canvasSize[1]])
if self.parentCanvas.canvas.size[0] > 1:
self.parentCanvas.resize([self.parentCanvas.canvas.size[0] - 1, self.parentCanvas.canvas.size[1]])
# }}}
# {{{ canvasIncrBrushHeight(self, event): XXX
def canvasIncrBrushHeight(self, event):
self.parentCanvas.brushSize[1] += 1
self.parentFrame.onCanvasUpdate(brushSize=self.parentCanvas.brushSize)
self.parentFrame.update(brushSize=self.parentCanvas.brushSize)
# }}}
# {{{ canvasIncrBrushHeightWidth(self, event): XXX
def canvasIncrBrushHeightWidth(self, event):
@ -196,11 +197,11 @@ class GuiCanvasInterface():
# {{{ canvasIncrBrushWidth(self, event): XXX
def canvasIncrBrushWidth(self, event):
self.parentCanvas.brushSize[0] += 1
self.parentFrame.onCanvasUpdate(brushSize=self.parentCanvas.brushSize)
self.parentFrame.update(brushSize=self.parentCanvas.brushSize)
# }}}
# {{{ canvasIncrCanvasHeight(self, event): XXX
def canvasIncrCanvasHeight(self, event):
self.parentCanvas.resize([self.parentCanvas.canvasSize[0], self.parentCanvas.canvasSize[1] + 1])
self.parentCanvas.resize([self.parentCanvas.canvas.size[0], self.parentCanvas.canvas.size[1] + 1])
# }}}
# {{{ canvasIncrCanvasHeightWidth(self, event): XXX
def canvasIncrCanvasHeightWidth(self, event):
@ -209,7 +210,7 @@ class GuiCanvasInterface():
# }}}
# {{{ canvasIncrCanvasWidth(self, event): XXX
def canvasIncrCanvasWidth(self, event):
self.parentCanvas.resize([self.parentCanvas.canvasSize[0] + 1, self.parentCanvas.canvasSize[1]])
self.parentCanvas.resize([self.parentCanvas.canvas.size[0] + 1, self.parentCanvas.canvas.size[1]])
# }}}
# {{{ canvasExportAsAnsi(self, event): XXX
@ -221,7 +222,7 @@ class GuiCanvasInterface():
outPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
with open(outPathName, "w", encoding="utf-8") as outFile:
self.parentCanvas.canvasExportStore.exportAnsiFile(self.parentCanvas.canvasMap, self.parentCanvas.canvasSize, outFile)
self.parentCanvas.canvas.exportStore.exportAnsiFile(self.parentCanvas.canvas.map, self.parentCanvas.canvas.size, outFile)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
return True
# }}}
@ -233,7 +234,7 @@ class GuiCanvasInterface():
else:
outPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasExportStore.exportBitmapToPngFile( \
self.parentCanvas.canvas.exportStore.exportBitmapToPngFile( \
self.parentCanvas.canvasBackend.canvasBitmap, outPathName, wx.BITMAP_TYPE_PNG)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
return True
@ -241,7 +242,7 @@ class GuiCanvasInterface():
# {{{ canvasExportImgur(self, event): XXX
def canvasExportImgur(self, event):
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
rc, status, result = self.parentCanvas.canvasExportStore.exportBitmapToImgur( \
rc, status, result = self.parentCanvas.canvas.exportStore.exportBitmapToImgur( \
self.imgurApiKey, self.parentCanvas.canvasBackend.canvasBitmap, "", "", wx.BITMAP_TYPE_PNG)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
if rc:
@ -254,11 +255,7 @@ class GuiCanvasInterface():
# {{{ canvasExportPastebin(self, event): XXX
def canvasExportPastebin(self, event):
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
pasteStatus, pasteResult = \
self.parentCanvas.canvasExportStore.exportPastebin( \
"", \
self.parentCanvas.canvasMap, \
self.parentCanvas.canvasSize)
pasteStatus, pasteResult = self.parentCanvas.canvas.exportStore.exportPastebin("", self.parentCanvas.canvas.map, self.parentCanvas.canvas.size)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
if pasteStatus:
if not wx.TheClipboard.IsOpened():
@ -272,7 +269,7 @@ class GuiCanvasInterface():
# {{{ canvasExportToClipboard(self, event): XXX
def canvasExportToClipboard(self, event):
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
rc, outBuffer = self.parentCanvas.canvasExportStore.exportTextBuffer(self.parentCanvas.canvasMap, self.parentCanvas.canvasSize)
rc, outBuffer = self.parentCanvas.canvas.exportStore.exportTextBuffer(self.parentCanvas.canvas.map, self.parentCanvas.canvas.size)
if rc and wx.TheClipboard.Open():
wx.TheClipboard.SetData(wx.TextDataObject(outBuffer))
wx.TheClipboard.Close()
@ -295,12 +292,12 @@ class GuiCanvasInterface():
else:
self.canvasPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
rc, error = self.parentCanvas.canvasImportStore.importAnsiFile(self.canvasPathName)
rc, error = self.parentCanvas.canvas.importStore.importAnsiFile(self.canvasPathName)
if rc:
self.parentCanvas.onStoreUpdate(self.parentCanvas.canvasImportStore.inSize, self.parentCanvas.canvasImportStore.outMap)
self.parentCanvas.update(self.parentCanvas.canvas.importStore.inSize, False, self.parentCanvas.canvas.importStore.outMap)
self.canvasPathName = "(Imported)"
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="(Imported)", undoLevel=-1)
self.parentFrame.update(pathName="(Imported)", undoLevel=-1)
return True
else:
print("error: {}".format(error), file=sys.stderr)
@ -322,12 +319,12 @@ class GuiCanvasInterface():
elif saveChanges == wx.ID_YES:
self.canvasSave(event)
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
rc, error = self.parentCanvas.canvasImportStore.importTextBuffer(io.StringIO(inBuffer.GetText()))
rc, error = self.parentCanvas.canvas.importStore.importTextBuffer(io.StringIO(inBuffer.GetText()))
if rc:
self.parentCanvas.onStoreUpdate(self.parentCanvas.canvasImportStore.inSize, self.parentCanvas.canvasImportStore.outMap)
self.parentCanvas.update(self.parentCanvas.canvas.importStore.inSize, False, self.parentCanvas.canvas.importStore.outMap)
self.canvasPathName = "(Clipboard)"
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="(Clipboard)", undoLevel=-1)
self.parentFrame.update(pathName="(Clipboard)", undoLevel=-1)
else:
print("error: {}".format(error), file=sys.stderr)
wx.TheClipboard.Close()
@ -351,12 +348,12 @@ class GuiCanvasInterface():
else:
self.canvasPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
rc, error = self.parentCanvas.canvasImportStore.importSauceFile(self.canvasPathName)
rc, error = self.parentCanvas.canvas.importStore.importSauceFile(self.canvasPathName)
if rc:
self.parentCanvas.onStoreUpdate(self.parentCanvas.canvasImportStore.inSize, self.parentCanvas.canvasImportStore.outMap)
self.parentCanvas.update(self.parentCanvas.canvas.importStore.inSize, False, self.parentCanvas.canvas.importStore.outMap)
self.canvasPathName = "(Imported)"
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="(Imported)", undoLevel=-1)
self.parentFrame.update(pathName="(Imported)", undoLevel=-1)
return True
else:
print("error: {}".format(error), file=sys.stderr)
@ -369,7 +366,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_CIRCLE[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_CIRCLE[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_CIRCLE[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolFill(self, event): XXX
def canvasToolFill(self, event):
@ -377,7 +374,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_FILL[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_FILL[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_FILL[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolLine(self, event): XXX
def canvasToolLine(self, event):
@ -385,7 +382,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_LINE[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_LINE[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_LINE[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolSelectClone(self, event): XXX
def canvasToolSelectClone(self, event):
@ -393,7 +390,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_CLONE_SELECT[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_CLONE_SELECT[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_CLONE_SELECT[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolSelectMove(self, event): XXX
def canvasToolSelectMove(self, event):
@ -401,7 +398,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_MOVE_SELECT[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_MOVE_SELECT[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_MOVE_SELECT[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolRect(self, event): XXX
def canvasToolRect(self, event):
@ -409,7 +406,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_RECT[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_RECT[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_RECT[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
# {{{ canvasToolText(self, event): XXX
def canvasToolText(self, event):
@ -417,7 +414,7 @@ class GuiCanvasInterface():
self.parentFrame.menuItemsById[self.parentFrame.CID_TEXT[0]].Check(True)
toolBar = self.parentFrame.toolBarItemsById[self.parentFrame.CID_TEXT[0]].GetToolBar()
toolBar.ToggleTool(self.parentFrame.CID_TEXT[0], True)
self.parentFrame.onCanvasUpdate(toolName=self.canvasTool.name)
self.parentFrame.update(toolName=self.canvasTool.name)
# }}}
#

133
libgui/GuiCanvasPanel.py Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env python3
#
# GuiCanvasPanel.py -- XXX
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
import wx
class GuiCanvasPanel(wx.Panel):
"""XXX"""
# {{{ _drawPatch(self, eventDc, isCursor, patch): XXX
def _drawPatch(self, eventDc, isCursor, patch):
if not self.canvas.dirtyCursor:
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc)
self.canvas.dirtyCursor = True
if self.backend.drawPatch(eventDc, patch) \
and isCursor:
patchDeltaCell = self.canvas.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
self.canvas.journal.pushCursor(patchDelta)
# }}}
# {{{ dispatchDeltaPatches(self, deltaPatches): XXX
def dispatchDeltaPatches(self, deltaPatches):
eventDc = self.backend.getDeviceContext(self)
for patch in deltaPatches:
if patch == None:
continue
elif patch[0] == "resize":
del eventDc; self.resize(patch[1:], False); eventDc = self.backend.getDeviceContext(self);
else:
self.canvas._commitPatch(patch); self.backend.drawPatch(eventDc, patch);
# }}}
# {{{ dispatchPatch(self, eventDc, isCursor, patch): XXX
def dispatchPatch(self, eventDc, isCursor, patch):
self.canvas.dispatchPatch(isCursor, patch, False if isCursor else True)
self._drawPatch(eventDc, isCursor, patch)
# }}}
# {{{ resize(self, newSize, commitUndo=True): XXX
def resize(self, newSize, commitUndo=True):
oldSize = [0, 0] if self.canvas.map == None else self.canvas.size
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
if self.canvas.resize(newSize, commitUndo):
newWinSize = [a * b for a, b in zip(newSize, self.backend.cellSize)]
self.SetMinSize(newWinSize); self.SetSize(wx.DefaultCoord, wx.DefaultCoord, *newWinSize);
curWindow = self
while curWindow != None:
curWindow.Layout(); curWindow = curWindow.GetParent();
self.backend.resize(newSize, self.backend.cellSize)
eventDc = self.backend.getDeviceContext(self)
if deltaSize[0] > 0:
for numRow in range(oldSize[1]):
for numNewCol in range(oldSize[0], newSize[0]):
self._drawPatch(eventDc, False, [numNewCol, numRow, 1, 1, 0, " "])
if deltaSize[1] > 1:
for numNewRow in range(oldSize[1], newSize[1]):
for numNewCol in range(newSize[0]):
self._drawPatch(eventDc, False, [numNewCol, numNewRow, 1, 1, 0, " "])
del eventDc; wx.SafeYield();
self.parentFrame.update(size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel)
# }}}
# {{{ update(self, newSize, commitUndo=True, newCanvas=None): XXX
def update(self, newSize, commitUndo=True, newCanvas=None):
self.resize(newSize, commitUndo)
self.canvas.update(newSize, newCanvas)
eventDc = self.backend.getDeviceContext(self)
for numRow in range(newSize[1]):
for numCol in range(newSize[0]):
self.backend.drawPatch(eventDc, [numCol, numRow, *self.canvas.map[numRow][numCol]])
wx.SafeYield()
# }}}
# {{{ onPanelClose(self, event): XXX
def onPanelClose(self, event):
self.Destroy()
# }}}
# {{{ onPanelEnterWindow(self, event): XXX
def onPanelEnterWindow(self, event):
self.parentFrame.SetFocus()
# }}}
# {{{ onPanelInput(self, event): XXX
def onPanelInput(self, event):
self.canvas.dirty, self.canvas.dirtyCursor = False, False
eventDc, eventType, tool = self.backend.getDeviceContext(self), event.GetEventType(), self.interface.canvasTool
if eventType == wx.wxEVT_CHAR:
mapPoint = self.brushPos
doSkip = tool.onKeyboardEvent(event, mapPoint, self.brushColours, self.brushSize, chr(event.GetUnicodeKey()), self.dispatchPatch, eventDc)
if doSkip:
event.Skip(); return;
else:
mapPoint = self.backend.xlateEventPoint(event, eventDc)
if mapPoint[0] >= self.canvas.size[0] \
or mapPoint[1] >= self.canvas.size[1]:
return
self.brushPos = mapPoint
tool.onMouseEvent( \
event, mapPoint, self.brushColours, self.brushSize, \
event.Dragging(), event.LeftIsDown(), event.RightIsDown(), \
self.dispatchPatch, eventDc)
if self.canvas.dirty:
self.parentFrame.update(cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
if eventType == wx.wxEVT_MOTION:
self.parentFrame.update(cellPos=mapPoint)
# }}}
# {{{ onPanelLeaveWindow(self, event): XXX
def onPanelLeaveWindow(self, event):
eventDc = self.backend.getDeviceContext(self)
self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc)
# }}}
# {{{ onPanelPaint(self, event): XXX
def onPanelPaint(self, event):
self.backend.onPanelPaintEvent(event, self)
# }}}
#
# __init__(self, parent, parentFrame, backend, canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, interface): initialisation method
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.backend, self.interface = backend(defaultCanvasSize, defaultCellSize), interface(self, parentFrame)
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.parentFrame = parentFrame
self.parentFrame.update(brushSize=self.brushSize, colours=self.brushColours)
self.Bind(wx.EVT_CLOSE, self.onPanelClose)
self.Bind(wx.EVT_ENTER_WINDOW, self.onPanelEnterWindow)
self.Bind(wx.EVT_LEAVE_WINDOW, self.onPanelLeaveWindow)
self.parentFrame.Bind(wx.EVT_CHAR, self.onPanelInput)
for eventType in (wx.EVT_LEFT_DOWN, wx.EVT_MOTION, wx.EVT_RIGHT_DOWN):
self.Bind(eventType, self.onPanelInput)
self.Bind(wx.EVT_PAINT, self.onPanelPaint)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python3
#
# CanvasBackend.py -- XXX
# GuiCanvasWxBackend.py -- XXX
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
from CanvasColours import Colours
from GuiCanvasColours import Colours
import wx
class CanvasBackend():
class GuiCanvasWxBackend():
"""XXX"""
# {{{ _drawBrushPatch(self, eventDc, patch): XXX

View File

@ -4,9 +4,12 @@
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
from Canvas import Canvas, haveUrllib
from CanvasColours import Colours
from Canvas import Canvas
from CanvasExportStore import haveUrllib
from GuiCanvasColours import Colours
from GuiCanvasInterface import GuiCanvasInterface
from GuiCanvasPanel import GuiCanvasPanel
from GuiCanvasWxBackend import GuiCanvasWxBackend
from GuiGeneralFrame import GuiGeneralFrame, \
TID_ACCELS, TID_COMMAND, TID_LIST, TID_MENU, TID_NOTHING, TID_SELECT, TID_TOOLBAR, \
NID_MENU_SEP, NID_TOOLBAR_HSEP, NID_TOOLBAR_VSEP
@ -116,9 +119,7 @@ class GuiFrame(GuiGeneralFrame):
def _initIcon(self):
iconPathNames = glob(os.path.join("assets", "images", "logo*.bmp"))
iconPathName = iconPathNames[random.randint(0, len(iconPathNames) - 1)]
icon = wx.Icon()
icon.CopyFromBitmap(wx.Bitmap(iconPathName, wx.BITMAP_TYPE_ANY))
self.SetIcon(icon)
icon = wx.Icon(); icon.CopyFromBitmap(wx.Bitmap(iconPathName, wx.BITMAP_TYPE_ANY)); self.SetIcon(icon);
# }}}
# {{{ _initPaletteToolBitmaps(self): XXX
def _initPaletteToolBitmaps(self):
@ -131,8 +132,7 @@ class GuiFrame(GuiGeneralFrame):
toolBitmapColour = Colours[numColour][0:4]
toolBitmap = wx.Bitmap((16,16))
toolBitmapDc = wx.MemoryDC(); toolBitmapDc.SelectObject(toolBitmap);
toolBitmapBrush = wx.Brush( \
wx.Colour(toolBitmapColour), wx.BRUSHSTYLE_SOLID)
toolBitmapBrush = wx.Brush(wx.Colour(toolBitmapColour), wx.BRUSHSTYLE_SOLID)
toolBitmapDc.SetBrush(toolBitmapBrush)
toolBitmapDc.SetBackground(toolBitmapBrush)
toolBitmapDc.SetPen(wx.Pen(wx.Colour(toolBitmapColour), 1))
@ -140,35 +140,18 @@ class GuiFrame(GuiGeneralFrame):
paletteDescr[numColour][4] = ["", None, toolBitmap]
# }}}
# {{{ onInput(self, event): XXX
def onInput(self, event):
eventId = event.GetId()
if eventId >= self.CID_COLOUR00[0] \
and eventId <= self.CID_COLOUR15[0]:
numColour = eventId - self.CID_COLOUR00[0]
self.itemsById[eventId][7](self.panelCanvas.canvasInterface, event, numColour)
else:
self.itemsById[eventId][7](self.panelCanvas.canvasInterface, event)
# }}}
# {{{ onCanvasUpdate(self, newBrushSize=None, newCellPos=None, newColours=None, newPathName=None, newSize=None, newToolName=None, newUndoLevel=None): XXX
def onCanvasUpdate(self, **kwargs):
self.lastPanelState.update(kwargs)
textItems = []
# {{{ update(self, **kwargs): XXX
def update(self, **kwargs):
self.lastPanelState.update(kwargs); textItems = [];
if "cellPos" in self.lastPanelState:
textItems.append("X: {:03d} Y: {:03d}".format( \
*self.lastPanelState["cellPos"]))
textItems.append("X: {:03d} Y: {:03d}".format(*self.lastPanelState["cellPos"]))
if "size" in self.lastPanelState:
textItems.append("W: {:03d} H: {:03d}".format( \
*self.lastPanelState["size"]))
textItems.append("W: {:03d} H: {:03d}".format(*self.lastPanelState["size"]))
if "brushSize" in self.lastPanelState:
textItems.append("Brush: {:02d}x{:02d}".format( \
*self.lastPanelState["brushSize"]))
textItems.append("Brush: {:02d}x{:02d}".format(*self.lastPanelState["brushSize"]))
if "colours" in self.lastPanelState:
textItems.append("FG: {:02d}, BG: {:02d}".format( \
*self.lastPanelState["colours"]))
textItems.append("{} on {}".format( \
Colours[self.lastPanelState["colours"][0]][4], \
Colours[self.lastPanelState["colours"][1]][4]))
textItems.append("FG: {:02d}, BG: {:02d}".format(*self.lastPanelState["colours"]))
textItems.append("{} on {}".format(Colours[self.lastPanelState["colours"][0]][4], Colours[self.lastPanelState["colours"][1]][4]))
if "pathName" in self.lastPanelState:
if self.lastPanelState["pathName"] != "":
basePathName = os.path.basename(self.lastPanelState["pathName"])
@ -177,8 +160,7 @@ class GuiFrame(GuiGeneralFrame):
else:
self.SetTitle("roar")
if "toolName" in self.lastPanelState:
textItems.append("Current tool: {}".format( \
self.lastPanelState["toolName"]))
textItems.append("Current tool: {}".format(self.lastPanelState["toolName"]))
self.statusBar.SetStatusText(" | ".join(textItems))
if "undoLevel" in self.lastPanelState:
if self.lastPanelState["undoLevel"] >= 0:
@ -198,11 +180,15 @@ class GuiFrame(GuiGeneralFrame):
toolBar = self.toolBarItemsById[self.CID_REDO[0]].GetToolBar()
toolBar.EnableTool(self.CID_REDO[0], False)
# }}}
# {{{ __del__(self): destructor method
def __del__(self):
if self.panelCanvas != None:
del self.panelCanvas; self.panelCanvas = None;
# {{{ onInput(self, event): XXX
def onInput(self, event):
eventId = event.GetId()
if eventId >= self.CID_COLOUR00[0] \
and eventId <= self.CID_COLOUR15[0]:
numColour = eventId - self.CID_COLOUR00[0]
self.itemsById[eventId][7](self.canvasPanel.interface, event, numColour)
else:
self.itemsById[eventId][7](self.canvasPanel.interface, event)
# }}}
#
@ -210,18 +196,15 @@ class GuiFrame(GuiGeneralFrame):
def __init__(self, parent, appSize=(840, 630), defaultCanvasPos=(0, 75), defaultCanvasSize=(100, 30), defaultCellSize=(7, 14)):
self._initPaletteToolBitmaps()
self.panelSkin = super().__init__(parent, wx.ID_ANY, "", size=appSize)
self.lastPanelState, self.panelCanvas = {}, None
self.lastPanelState, self.canvasPanel = {}, None
self._initIcon()
self.panelCanvas = Canvas(self.panelSkin, parentFrame=self, \
canvasInterface=GuiCanvasInterface, \
defaultCanvasPos=defaultCanvasPos, \
defaultCanvasSize=defaultCanvasSize, \
defaultCellSize=defaultCellSize)
self.panelCanvas.canvasInterface.canvasNew(None)
self.canvas = Canvas(defaultCanvasSize)
self.canvasPanel = GuiCanvasPanel(self.panelSkin, self, GuiCanvasWxBackend, self.canvas, defaultCanvasPos, defaultCanvasSize, defaultCellSize, GuiCanvasInterface)
self.canvasPanel.interface.canvasNew(None)
self.sizerSkin.AddSpacer(5)
self.sizerSkin.Add(self.panelCanvas, 0, wx.ALL|wx.EXPAND, 14)
self.sizerSkin.Add(self.canvasPanel, 0, wx.ALL|wx.EXPAND, 14)
self.panelSkin.SetSizer(self.sizerSkin)
self.panelSkin.SetAutoLayout(1)
self.sizerSkin.Fit(self.panelSkin)

View File

@ -14,24 +14,24 @@ class ToolFill(Tool):
# onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc): XXX
def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown, dispatchFn, eventDc):
pointStack, pointsDone = [list(atPoint)], []
testColour = self.parentCanvas.canvasMap[atPoint[1]][atPoint[0]][0:2]
testColour = self.parentCanvas.canvas.map[atPoint[1]][atPoint[0]][0:2]
if isLeftDown or isRightDown:
if isRightDown:
brushColours = [brushColours[1], brushColours[0]]
while len(pointStack) > 0:
point = pointStack.pop()
pointCell = self.parentCanvas.canvasMap[point[1]][point[0]]
if pointCell[0:2] == testColour:
pointCell = self.parentCanvas.canvas.map[point[1]][point[0]]
if (pointCell[0:2] == testColour) \
or ((pointCell[3] == " ") and (pointCell[1] == testColour[1])):
if not point in pointsDone:
dispatchFn(eventDc, False, [*point, \
brushColours[0], brushColours[0], 0, " "])
dispatchFn(eventDc, False, [*point, brushColours[0], brushColours[0], 0, " "])
if point[0] > 0:
pointStack.append([point[0] - 1, point[1]])
if point[0] < (self.parentCanvas.canvasSize[0] - 1):
if point[0] < (self.parentCanvas.canvas.size[0] - 1):
pointStack.append([point[0] + 1, point[1]])
if point[1] > 0:
pointStack.append([point[0], point[1] - 1])
if point[1] < (self.parentCanvas.canvasSize[1] - 1):
if point[1] < (self.parentCanvas.canvas.size[1] - 1):
pointStack.append([point[0], point[1] + 1])
pointsDone += [point]

View File

@ -64,7 +64,7 @@ class ToolSelect(Tool):
self.toolSelectMap.append([])
for numCol in range((self.targetRect[1][0] - self.targetRect[0][0]) + 1):
rectX, rectY = self.targetRect[0][0] + numCol, self.targetRect[0][1] + numRow
self.toolSelectMap[numRow].append(self.parentCanvas.canvasMap[rectY][rectX])
self.toolSelectMap[numRow].append(self.parentCanvas.canvas.map[rectY][rectX])
self._drawSelectRect(self.targetRect, dispatchFn, eventDc)
elif isRightDown:
self.targetRect, self.toolState = None, self.TS_NONE

View File

@ -24,9 +24,9 @@ class ToolText(Tool):
if self.textPos == None:
self.textPos = list(atPoint)
dispatchFn(eventDc, False, [*self.textPos, *self.textColours, 0, keyChar])
if self.textPos[0] < (self.parentCanvas.canvasSize[0] - 1):
if self.textPos[0] < (self.parentCanvas.canvas.size[0] - 1):
self.textPos[0] += 1
elif self.textPos[1] < (self.parentCanvas.canvasSize[1] - 1):
elif self.textPos[1] < (self.parentCanvas.canvas.size[1] - 1):
self.textPos[0] = 0; self.textPos[1] += 1;
else:
self.textPos = [0, 0]

View File

@ -18,11 +18,11 @@ def main(*argv):
appFrame = GuiFrame(None)
if len(argv) > 1 \
and len(argv[1]) > 0:
appFrame.panelCanvas.canvasInterface.canvasPathName = argv[1]
rc, error = appFrame.panelCanvas.canvasImportStore.importTextFile(argv[1])
appFrame.canvasPanel.interface.canvasPathName = argv[1]
rc, error = appFrame.canvasPanel.canvas.importStore.importTextFile(argv[1])
if rc:
appFrame.panelCanvas.onStoreUpdate(appFrame.panelCanvas.canvasImportStore.inSize, appFrame.panelCanvas.canvasImportStore.outMap)
appFrame.onCanvasUpdate(pathName=argv[1], undoLevel=-1)
appFrame.canvasPanel.update(appFrame.canvasPanel.canvas.importStore.inSize, False, appFrame.canvasPanel.canvas.importStore.outMap)
appFrame.update(pathName=argv[1], undoLevel=-1)
else:
print("error: {}".format(error), file=sys.stderr)
wxApp.MainLoop()