mirror of
https://github.com/lalbornoz/roar.git
synced 2024-11-02 13:56:39 +00:00
Cleanup, bugfixes & C++ backend implementation.
1) {About,Melp?} window: switch to green on black. 2) Assets window: scroll assets list on selected item update w/ <Cursor> or on deletion. 3) Canvas window: change default brush colours to [3, -1]. 4) Canvas window: copy canvas cells given transparent cells from tools. 5) Canvas window: don't disable {re,un}do during object tool usage. 6) Canvas window: don't hide cursor during {re,un}do. 7) Canvas window: draw new cells using current brush background colour on resize. 8) Canvas window: fix memory leak on cell size updating. 9) Text tool: process [\r\n] in text pasted from clipboard. assets/audio/roar{vap0r[1-8],viking[1-5]}.wav: added. assets/text/README.txt: updated. assets/tools/AnsiToMiRCART.py: added (for spoke.) assets/tools/deploy-python.sh: updated.
This commit is contained in:
parent
90840bd0a0
commit
0c66f94797
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -6,7 +6,7 @@
|
|||||||
{
|
{
|
||||||
"label": "Build libgui/GuiCanvasWxBackendFast.pyd",
|
"label": "Build libgui/GuiCanvasWxBackendFast.pyd",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "cd \"${workspaceFolder}/libgui\" && cmd /c cl /LD /IC:/Python37/include GuiCanvasWxBackendFast.c C:/Python37/libs/python37.lib /FeGuiCanvasWxBackendFast.pyd",
|
"command": "cd \"${workspaceFolder}/libgui\" && cmd /c cl /EHsc /LD /Ox /Wall /WX /IC:/Python37/include GuiCanvasWxBackendFast.cpp C:/Python37/libs/python37.lib /FeGuiCanvasWxBackendFast.pyd",
|
||||||
"problemMatcher": [
|
"problemMatcher": [
|
||||||
"$msCompile"
|
"$msCompile"
|
||||||
]
|
]
|
||||||
|
BIN
assets/audio/roarvap0r1.wav
Normal file
BIN
assets/audio/roarvap0r1.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r2.wav
Normal file
BIN
assets/audio/roarvap0r2.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r3.wav
Normal file
BIN
assets/audio/roarvap0r3.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r4.wav
Normal file
BIN
assets/audio/roarvap0r4.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r5.wav
Normal file
BIN
assets/audio/roarvap0r5.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r6.wav
Normal file
BIN
assets/audio/roarvap0r6.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r7.wav
Normal file
BIN
assets/audio/roarvap0r7.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarvap0r8.wav
Normal file
BIN
assets/audio/roarvap0r8.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarviking1.wav
Normal file
BIN
assets/audio/roarviking1.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarviking2.wav
Normal file
BIN
assets/audio/roarviking2.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarviking3.wav
Normal file
BIN
assets/audio/roarviking3.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarviking4.wav
Normal file
BIN
assets/audio/roarviking4.wav
Normal file
Binary file not shown.
BIN
assets/audio/roarviking5.wav
Normal file
BIN
assets/audio/roarviking5.wav
Normal file
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
# roar.py -- mIRC art editor for Windows & Linux (WIP)
|
# roar.py -- mIRC art editor for Windows & Linux (WIP)
|
||||||
* Prerequisites on Windows: install Python v3.6.x[1] and script dependencies w/ the following elevated command prompt command line:
|
* Prerequisites on Windows: install Python v3.7.x[1] and script dependencies w/ the following elevated command prompt command line:
|
||||||
`pip install requests urllib3 wxPython`
|
`pip install requests urllib3 wxPython`
|
||||||
* Prerequisites on Linux: python3 && python-wx{gtk2.8,tools} on Debian-family Linux distributions
|
* Prerequisites on Linux: python3 (v3.7.x) && python-wx{gtk2.8,tools} on Debian-family Linux distributions
|
||||||
* Screenshot:
|
* Screenshot:
|
||||||
![Screenshot](https://github.com/lalbornoz/roar/raw/master/assets/images/roar.png "Screenshot")
|
![Screenshot](https://github.com/lalbornoz/roar/raw/master/assets/images/roar.png "Screenshot")
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
1) Backend: correctly refresh transparent cursor cells when drawing cursor patches
|
1) GUI: drag & drop file outside of canvas to open, into canvas as object w/ select tool
|
||||||
2) GUI: edit asset in new canvas, import from {canvas,object}
|
2) GUI: edit asset in new canvas, import from {canvas,object}
|
||||||
3) GUI: implement GuiCanvasWxBackendFast.c{,c}
|
3) GUI: implement GuiCanvasWxBackendFast.c{,c}
|
||||||
4) GUI: select all
|
4) GUI: select all
|
||||||
@ -6,8 +6,10 @@
|
|||||||
6) Operators: copy, cut, delete, insert from, paste
|
6) Operators: copy, cut, delete, insert from, paste
|
||||||
7) Operators: crop, scale, shift, slice operators
|
7) Operators: crop, scale, shift, slice operators
|
||||||
8) Tools: measure, triangle, unicode block elements tool
|
8) Tools: measure, triangle, unicode block elements tool
|
||||||
9) Tools: object tool: reimplement cloning correctly outside of object tool
|
9) Tools: object tool: allow application of arbitrary tool to selection before setting
|
||||||
10) Tools: text tool: finish Arabic/RTL text implementation
|
10) Tools: object tool: reimplement cloning correctly outside of object tool
|
||||||
11) Tools: text tool: implicitly draw (text) w/ bg -1, toggle drawing actual brushColours[1] mode w/ RMB
|
11) Tools: reimplement in C++
|
||||||
|
12) Tools: text tool: finish Arabic/RTL text implementation
|
||||||
|
13) Tools: text tool: implicitly draw (text) w/ bg -1, toggle drawing actual brushColours[1] mode w/ RMB
|
||||||
|
|
||||||
vim:ff=dos tw=0
|
vim:ff=dos tw=0
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
3,6▟6,3▝
|
3,6▟6,3▝15
|
||||||
3,6▟6,3▜▛3,6▟6,3▝
|
3,6▟6,3▜▛3,6▟6,3▝15
|
||||||
3,6▟6,3▝▜3,6▟6,3▝▜▛3,6▟6,3▝
|
3,6▟6,3▝▜3,6▟6,3▝▜▛3,6▟6,3▝15
|
||||||
3,6▟6,3▝3,8/\3,6▟6,3▜▛3,6▟6,3▝3,8/\3,6▟6,3▝
|
3,6▟6,3▝3,8/\3,6▟6,3▜▛3,6▟6,3▝3,8/\3,6▟6,3▝15
|
||||||
9,1/\ 9,1/ 6,3▝▜▛3,6▟6,3▝8,8 3,6▟6,3▝▜▛3,6▟6,3▝
|
9,1/\15 9,1/15 6,3▝▜▛3,6▟6,3▝8,8 3,6▟6,3▝▜▛3,6▟6,3▝15
|
||||||
6,1(0o9 6) 6,1( 6,3▜▛3,6▟6,3▝8,8 3o _ o8 3,6▟6,3▝▜▛3,6▟
|
6,1(0o9 6)15 6,1(15 6,3▜▛3,6▟6,3▝8,8 3o _ o8 3,6▟6,3▝▜▛3,6▟
|
||||||
9,1( \ 9,1) 6,3▝▜▛▜8,8 6(_3Y6_)6,3▛▝▛3,6▟6,3▝
|
9,1( \15 9,1)15 6,3▝▜▛▜8,8 6(_3Y6_)6,3▛▝▛3,6▟6,3▝15
|
||||||
6,1|(__)/ 3,6▟6,3▝▜▛8,8 6\_/6,3▜▛3,6▟6,3▝
|
6,1|(__)/15 3,6▟6,3▝▜▛8,8 6\_/6,3▜▛3,6▟6,3▝15
|
||||||
1,3\\ 1,3.'0s3 6▜▛3,6▟6,3▝
|
1,3\\15 1,3.'0s3 6▜▛3,6▟6,3▝15
|
||||||
1,6\\ 1,6/6 0p6 1\ \ 6,3▜▛
|
1,6\\15 1,6/6 0p6 1\ \ 6,3▜▛15
|
||||||
1,3\\/3 0o3 1\3 1\ \6▜
|
1,3\\/3 0o3 1\3 1\ \6▜15
|
||||||
1,6\6 0k6 1/)___|_|6,3▛
|
1,6\6 0k6 1/)___|_|6,3▛15
|
||||||
1,3(_0e1__/__))) )))6▛
|
1,3(_0e1__/__))) )))6▛15
|
||||||
12,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲
|
12,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲15
|
||||||
12,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱
|
12,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱15
|
||||||
2,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱
|
2,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱15
|
||||||
2,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲
|
2,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲15
|
||||||
|
31
assets/tools/AnsiToMiRCART.py
Executable file
31
assets/tools/AnsiToMiRCART.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# AnsiToMiRCART.py -- convert ANSI to mIRC art file (for spoke)
|
||||||
|
# Copyright (c) 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
|
# This project is licensed under the terms of the MIT licence.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os, sys
|
||||||
|
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
|
||||||
|
|
||||||
|
from CanvasExportStore import CanvasExportStore
|
||||||
|
from CanvasImportStore import CanvasImportStore
|
||||||
|
|
||||||
|
#
|
||||||
|
# Entry point
|
||||||
|
def main(*argv):
|
||||||
|
if (len(sys.argv) - 1) != 2:
|
||||||
|
print("usage: {} <ANSI input file pathname> <mIRC art output file pathname>".format(sys.argv[0]), file=sys.stderr)
|
||||||
|
else:
|
||||||
|
canvasImportStore = CanvasImportStore()
|
||||||
|
rc, error = canvasImportStore.importAnsiFile(argv[1])
|
||||||
|
if rc:
|
||||||
|
canvasExportStore = CanvasExportStore()
|
||||||
|
with open(argv[2], "w", encoding="utf-8") as outFile:
|
||||||
|
canvasExportStore.exportTextFile(canvasImportStore.outMap, canvasImportStore.inSize, outFile)
|
||||||
|
else:
|
||||||
|
print("error: {}".format(error), file=sys.stderr)
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main(*sys.argv)
|
||||||
|
|
||||||
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
@ -32,6 +32,9 @@ deploy() {
|
|||||||
-not -path '*/__pycache__/*' \
|
-not -path '*/__pycache__/*' \
|
||||||
-not -path '*/__pycache__' \
|
-not -path '*/__pycache__' \
|
||||||
-not -path './librtl/ImgurApiKey.py' \
|
-not -path './librtl/ImgurApiKey.py' \
|
||||||
|
-not -name '*.exp' \
|
||||||
|
-not -name '*.lib' \
|
||||||
|
-not -name '*.obj' \
|
||||||
-not -name '*.sw*' \
|
-not -name '*.sw*' \
|
||||||
-not -name "${0##*/}" |\
|
-not -name "${0##*/}" |\
|
||||||
cpio --quiet -dLmp "${_release_dname}";
|
cpio --quiet -dLmp "${_release_dname}";
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
from CanvasExportStore import CanvasExportStore
|
from CanvasExportStore import CanvasExportStore
|
||||||
from CanvasImportStore import CanvasImportStore
|
from CanvasImportStore import CanvasImportStore
|
||||||
from CanvasJournal import CanvasJournal
|
|
||||||
|
|
||||||
class Canvas():
|
class Canvas():
|
||||||
def _commitPatch(self, patch):
|
def _commitPatch(self, patch):
|
||||||
@ -18,11 +17,51 @@ class Canvas():
|
|||||||
else:
|
else:
|
||||||
patchDeltaCell = self.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
|
patchDeltaCell = self.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self.journal.updateCurrentDeltas(patch, patchDelta)
|
self.updateCurrentDeltas(patch, patchDelta)
|
||||||
self._commitPatch(patch)
|
self._commitPatch(patch)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def resize(self, newSize, commitUndo=True):
|
def begin(self):
|
||||||
|
deltaItem = [[], []]; self.patchesUndo.insert(self.patchesUndoLevel, deltaItem);
|
||||||
|
|
||||||
|
def end(self):
|
||||||
|
if self.patchesUndo[self.patchesUndoLevel] == [[], []]:
|
||||||
|
del self.patchesUndo[self.patchesUndoLevel]
|
||||||
|
else:
|
||||||
|
if self.patchesUndoLevel > 0:
|
||||||
|
del self.patchesUndo[:self.patchesUndoLevel]; self.patchesUndoLevel = 0;
|
||||||
|
|
||||||
|
def popCursor(self, reset=True):
|
||||||
|
patchesCursor = []
|
||||||
|
if len(self.patchesCursor):
|
||||||
|
patchesCursor = self.patchesCursor
|
||||||
|
if reset:
|
||||||
|
self.resetCursor()
|
||||||
|
return patchesCursor
|
||||||
|
|
||||||
|
def popUndo(self, redo=False):
|
||||||
|
patches = []
|
||||||
|
if not redo:
|
||||||
|
if self.patchesUndo[self.patchesUndoLevel] != None:
|
||||||
|
patches = self.patchesUndo[self.patchesUndoLevel][0]; self.patchesUndoLevel += 1;
|
||||||
|
else:
|
||||||
|
if self.patchesUndoLevel > 0:
|
||||||
|
self.patchesUndoLevel -= 1; patches = self.patchesUndo[self.patchesUndoLevel][1];
|
||||||
|
return patches
|
||||||
|
|
||||||
|
def pushCursor(self, patches):
|
||||||
|
self.patchesCursor = patches
|
||||||
|
|
||||||
|
def resetCursor(self):
|
||||||
|
self.patchesCursor = []
|
||||||
|
|
||||||
|
def resetUndo(self):
|
||||||
|
if self.patchesUndo != None:
|
||||||
|
self.patchesUndo.clear()
|
||||||
|
self.patchesUndo = [None]; self.patchesUndoLevel = 0;
|
||||||
|
|
||||||
|
def resize(self, brushColours, newSize, commitUndo=True):
|
||||||
|
newCells = []
|
||||||
if newSize != self.size:
|
if newSize != self.size:
|
||||||
if self.map == None:
|
if self.map == None:
|
||||||
self.map, oldSize = [], [0, 0]
|
self.map, oldSize = [], [0, 0]
|
||||||
@ -30,41 +69,43 @@ class Canvas():
|
|||||||
oldSize = self.size
|
oldSize = self.size
|
||||||
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self.journal.begin()
|
self.begin()
|
||||||
undoPatches, redoPatches = ["resize", *oldSize], ["resize", *newSize]
|
undoPatches, redoPatches = ["resize", *oldSize], ["resize", *newSize]
|
||||||
self.journal.updateCurrentDeltas(redoPatches, undoPatches)
|
self.updateCurrentDeltas(redoPatches, undoPatches)
|
||||||
if deltaSize[0] < 0:
|
if deltaSize[0] < 0:
|
||||||
for numRow in range(oldSize[1]):
|
for numRow in range(oldSize[1]):
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
for numCol in range((oldSize[0] + deltaSize[0]), oldSize[0]):
|
for numCol in range((oldSize[0] + deltaSize[0]), oldSize[0]):
|
||||||
self.journal.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
|
self.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
|
||||||
del self.map[numRow][-1:(deltaSize[0]-1):-1]
|
del self.map[numRow][-1:(deltaSize[0]-1):-1]
|
||||||
else:
|
else:
|
||||||
for numRow in range(oldSize[1]):
|
for numRow in range(oldSize[1]):
|
||||||
self.map[numRow].extend([[1, 1, 0, " "]] * deltaSize[0])
|
self.map[numRow].extend([[*brushColours, 0, " "]] * deltaSize[0])
|
||||||
for numNewCol in range(oldSize[0], newSize[0]):
|
for numNewCol in range(oldSize[0], newSize[0]):
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self.journal.updateCurrentDeltas([numNewCol, numRow, 1, 1, 0, " "], None)
|
self.updateCurrentDeltas([numNewCol, numRow, *brushColours, 0, " "], None)
|
||||||
self.applyPatch([numNewCol, numRow, 1, 1, 0, " "], False)
|
newCells += [[numNewCol, numRow, *brushColours, 0, " "]]
|
||||||
|
self.applyPatch([numNewCol, numRow, *brushColours, 0, " "], False)
|
||||||
if deltaSize[1] < 0:
|
if deltaSize[1] < 0:
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
for numRow in range((oldSize[1] + deltaSize[1]), oldSize[1]):
|
for numRow in range((oldSize[1] + deltaSize[1]), oldSize[1]):
|
||||||
for numCol in range(oldSize[0] + deltaSize[0]):
|
for numCol in range(oldSize[0] + deltaSize[0]):
|
||||||
self.journal.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
|
self.updateCurrentDeltas(None, [numCol, numRow, *self.map[numRow][numCol]])
|
||||||
del self.map[-1:(deltaSize[1]-1):-1]
|
del self.map[-1:(deltaSize[1]-1):-1]
|
||||||
else:
|
else:
|
||||||
for numNewRow in range(oldSize[1], newSize[1]):
|
for numNewRow in range(oldSize[1], newSize[1]):
|
||||||
self.map.extend([[[1, 1, 0, " "]] * newSize[0]])
|
self.map.extend([[[*brushColours, 0, " "]] * newSize[0]])
|
||||||
for numNewCol in range(newSize[0]):
|
for numNewCol in range(newSize[0]):
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self.journal.updateCurrentDeltas([numNewCol, numNewRow, 1, 1, 0, " "], None)
|
self.updateCurrentDeltas([numNewCol, numNewRow, *brushColours, 0, " "], None)
|
||||||
self.applyPatch([numNewCol, numNewRow, 1, 1, 0, " "], False)
|
newCells += [[numNewCol, numNewRow, *brushColours, 0, " "]]
|
||||||
|
self.applyPatch([numNewCol, numNewRow, *brushColours, 0, " "], False)
|
||||||
self.size = newSize
|
self.size = newSize
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self.journal.end()
|
self.end()
|
||||||
return True
|
return True, newCells
|
||||||
else:
|
else:
|
||||||
return False
|
return False, newCells
|
||||||
|
|
||||||
def update(self, newSize, newCanvas=None):
|
def update(self, newSize, newCanvas=None):
|
||||||
for numRow in range(self.size[1]):
|
for numRow in range(self.size[1]):
|
||||||
@ -73,7 +114,15 @@ class Canvas():
|
|||||||
and (numRow < len(newCanvas)) and (numCol < len(newCanvas[numRow])):
|
and (numRow < len(newCanvas)) and (numCol < len(newCanvas[numRow])):
|
||||||
self._commitPatch([numCol, numRow, *newCanvas[numRow][numCol]])
|
self._commitPatch([numCol, numRow, *newCanvas[numRow][numCol]])
|
||||||
|
|
||||||
|
def updateCurrentDeltas(self, redoPatches, undoPatches):
|
||||||
|
self.patchesUndo[self.patchesUndoLevel][0].append(undoPatches)
|
||||||
|
self.patchesUndo[self.patchesUndoLevel][1].append(redoPatches)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.resetCursor(); self.resetUndo();
|
||||||
|
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
self.exportStore, self.importStore, self.journal, self.map, self.size = CanvasExportStore(), CanvasImportStore(), CanvasJournal(), None, size
|
self.exportStore, self.importStore, self.map, self.size = CanvasExportStore(), CanvasImportStore(), None, size
|
||||||
|
self.patchesCursor, self.patchesUndo, self.patchesUndoLevel = [], [None], 0
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
#
|
|
||||||
# CanvasJournal.py
|
|
||||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
|
||||||
#
|
|
||||||
|
|
||||||
class CanvasJournal():
|
|
||||||
def begin(self):
|
|
||||||
deltaItem = [[], []]; self.patchesUndo.insert(self.patchesUndoLevel, deltaItem);
|
|
||||||
|
|
||||||
def end(self):
|
|
||||||
if self.patchesUndo[self.patchesUndoLevel] == [[], []]:
|
|
||||||
del self.patchesUndo[self.patchesUndoLevel]
|
|
||||||
else:
|
|
||||||
if self.patchesUndoLevel > 0:
|
|
||||||
del self.patchesUndo[:self.patchesUndoLevel]; self.patchesUndoLevel = 0;
|
|
||||||
|
|
||||||
def popCursor(self, reset=True):
|
|
||||||
if len(self.patchesCursor):
|
|
||||||
patchesCursor = self.patchesCursor
|
|
||||||
if reset:
|
|
||||||
self.resetCursor()
|
|
||||||
return patchesCursor
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def popRedo(self):
|
|
||||||
if self.patchesUndoLevel > 0:
|
|
||||||
self.patchesUndoLevel -= 1; patches = self.patchesUndo[self.patchesUndoLevel];
|
|
||||||
return patches[1]
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def popUndo(self):
|
|
||||||
if self.patchesUndo[self.patchesUndoLevel] != None:
|
|
||||||
patches = self.patchesUndo[self.patchesUndoLevel]; self.patchesUndoLevel += 1;
|
|
||||||
return patches[0]
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def pushCursor(self, patches):
|
|
||||||
self.patchesCursor = patches
|
|
||||||
|
|
||||||
def resetCursor(self):
|
|
||||||
self.patchesCursor = []
|
|
||||||
|
|
||||||
def resetUndo(self):
|
|
||||||
if self.patchesUndo != None:
|
|
||||||
self.patchesUndo.clear()
|
|
||||||
self.patchesUndo = [None]; self.patchesUndoLevel = 0;
|
|
||||||
|
|
||||||
def updateCurrentDeltas(self, redoPatches, undoPatches):
|
|
||||||
self.patchesUndo[self.patchesUndoLevel][0].append(undoPatches)
|
|
||||||
self.patchesUndo[self.patchesUndoLevel][1].append(redoPatches)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self.resetCursor(); self.resetUndo();
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.patchesUndo = None; self.resetCursor(); self.resetUndo();
|
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
|
@ -4,10 +4,14 @@
|
|||||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
#
|
#
|
||||||
|
|
||||||
from ctypes import *
|
try:
|
||||||
|
import GuiCanvasWxBackendFast; haveGuiCanvasWxBackendFast = True;
|
||||||
|
except ImportError as e:
|
||||||
|
print("Failed to import GuiCanvasWxBackendFast: {}".format(e)); haveGuiCanvasWxBackendFast = False;
|
||||||
|
|
||||||
|
from ctypes import WinDLL
|
||||||
from GuiCanvasColours import Colours
|
from GuiCanvasColours import Colours
|
||||||
import GuiCanvasWxBackendFast
|
import math, os, platform, Rtl, wx
|
||||||
import math, os, platform, wx
|
|
||||||
|
|
||||||
class GuiBufferedDC(wx.MemoryDC):
|
class GuiBufferedDC(wx.MemoryDC):
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
@ -143,20 +147,7 @@ class GuiCanvasWxBackend():
|
|||||||
brush, pen = self._brushesBlend[bg][14], self._pensBlend[bg][14]
|
brush, pen = self._brushesBlend[bg][14], self._pensBlend[bg][14]
|
||||||
return brush, pen
|
return brush, pen
|
||||||
|
|
||||||
def drawCursorMaskWithJournal(self, canvas, canvasJournal, eventDc, reset=True):
|
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
cursorPatches = canvasJournal.popCursor(reset=reset); patches = [];
|
|
||||||
for cursorCell in [p[:2] for p in cursorPatches]:
|
|
||||||
if (cursorCell[0] < canvas.size[0]) \
|
|
||||||
and (cursorCell[1] < canvas.size[1]):
|
|
||||||
patches += [[*cursorCell, *canvas.map[cursorCell[1]][cursorCell[0]]]]
|
|
||||||
if len(patches) > 0:
|
|
||||||
self.drawPatches(canvas, eventDc, patches, False)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
return cursorPatches
|
|
||||||
|
|
||||||
def drawPatches(self, canvas, eventDc, patches, isCursor=False):
|
def drawPatches(self, canvas, eventDc, patches, isCursor=False):
|
||||||
GuiCanvasWxBackendFast.drawPatches()
|
|
||||||
patchesRender = []
|
patchesRender = []
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
point = patch[:2]
|
point = patch[:2]
|
||||||
@ -166,6 +157,8 @@ class GuiCanvasWxBackend():
|
|||||||
patchesRender += [patchReshaped]
|
patchesRender += [patchReshaped]
|
||||||
else:
|
else:
|
||||||
patchesRender += [patch]
|
patchesRender += [patch]
|
||||||
|
if haveGuiCanvasWxBackendFast:
|
||||||
|
GuiCanvasWxBackendFast.drawPatches(self.canvasBitmap, canvas.map, canvas.size, eventDc, isCursor, patchesRender); return;
|
||||||
numPatch, textBg = 0, wx.Colour(0, 0, 0, 0)
|
numPatch, textBg = 0, wx.Colour(0, 0, 0, 0)
|
||||||
rectangles, pens, brushes = [None] * len(patchesRender), [None] * len(patchesRender), [None] * len(patchesRender)
|
rectangles, pens, brushes = [None] * len(patchesRender), [None] * len(patchesRender), [None] * len(patchesRender)
|
||||||
textList, coords, foregrounds, backgrounds = [], [], [], []
|
textList, coords, foregrounds, backgrounds = [], [], [], []
|
||||||
@ -173,10 +166,10 @@ class GuiCanvasWxBackend():
|
|||||||
for patchRender in patchesRender:
|
for patchRender in patchesRender:
|
||||||
if (patchRender[5] == " ") and (patchRender[3] == -1):
|
if (patchRender[5] == " ") and (patchRender[3] == -1):
|
||||||
text, textFg = "░", wx.Colour(0, 0, 0, 255)
|
text, textFg = "░", wx.Colour(0, 0, 0, 255)
|
||||||
elif isCursor and (patchRender[5] == " ") and (canvas.map[patchRender[1]][patchRender[0]][3] != " "):
|
elif False and isCursor and (patchRender[5] == " ") and (canvas.map[patchRender[1]][patchRender[0]][3] != " "):
|
||||||
patchRender = [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]]
|
patchRender = [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]]
|
||||||
text, textFg = canvas.map[patchRender[1]][patchRender[0]][3], wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
|
text, textFg = canvas.map[patchRender[1]][patchRender[0]][3], wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
|
||||||
elif isCursor and (patchRender[5] == " ") and (canvas.map[patchRender[1]][patchRender[0]][2] & self._CellState.CS_UNDERLINE):
|
elif False and isCursor and (patchRender[5] == " ") and (canvas.map[patchRender[1]][patchRender[0]][2] & self._CellState.CS_UNDERLINE):
|
||||||
patchRender = [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]]
|
patchRender = [*patchRender[:-2], *canvas.map[patchRender[1]][patchRender[0]][2:]]
|
||||||
text, textFg = "_", wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
|
text, textFg = "_", wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
|
||||||
elif patchRender[5] != " ":
|
elif patchRender[5] != " ":
|
||||||
@ -228,9 +221,11 @@ class GuiCanvasWxBackend():
|
|||||||
oldDc = wx.MemoryDC(); oldDc.SelectObject(self.canvasBitmap);
|
oldDc = wx.MemoryDC(); oldDc.SelectObject(self.canvasBitmap);
|
||||||
newDc = wx.MemoryDC(); newBitmap = wx.Bitmap(winSize); newDc.SelectObject(newBitmap);
|
newDc = wx.MemoryDC(); newBitmap = wx.Bitmap(winSize); newDc.SelectObject(newBitmap);
|
||||||
newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0)
|
newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0)
|
||||||
oldDc.SelectObject(wx.NullBitmap)
|
oldDc.SelectObject(wx.NullBitmap); newDc.SelectObject(wx.NullBitmap);
|
||||||
self.canvasBitmap.Destroy(); self.canvasBitmap = newBitmap;
|
self.canvasBitmap.Destroy(); self.canvasBitmap = newBitmap;
|
||||||
self.canvasSize = canvasSize
|
self.canvasSize = canvasSize;
|
||||||
|
if haveGuiCanvasWxBackendFast:
|
||||||
|
GuiCanvasWxBackendFast.resize(tuple(self.cellSize), self._font, tuple(winSize))
|
||||||
|
|
||||||
def xlateEventPoint(self, event, eventDc, viewRect):
|
def xlateEventPoint(self, event, eventDc, viewRect):
|
||||||
eventPoint = event.GetLogicalPosition(eventDc)
|
eventPoint = event.GetLogicalPosition(eventDc)
|
||||||
@ -244,6 +239,8 @@ class GuiCanvasWxBackend():
|
|||||||
self._finiBrushesAndPens()
|
self._finiBrushesAndPens()
|
||||||
|
|
||||||
def __init__(self, canvasSize, fontName="Dejavu Sans Mono", fontPathName=os.path.join("assets", "fonts", "DejaVuSansMono.ttf"), fontSize=8):
|
def __init__(self, canvasSize, fontName="Dejavu Sans Mono", fontPathName=os.path.join("assets", "fonts", "DejaVuSansMono.ttf"), fontSize=8):
|
||||||
|
if haveGuiCanvasWxBackendFast:
|
||||||
|
GuiCanvasWxBackendFast.init(wx)
|
||||||
self._brushes, self._font, self._lastBrush, self._lastPen, self._pens = None, None, None, None, None
|
self._brushes, self._font, self._lastBrush, self._lastPen, self._pens = None, None, None, None, None
|
||||||
self.canvasBitmap, self.cellSize, self.fontName, self.fontPathName, self.fontSize = None, None, fontName, fontPathName, fontSize
|
self.canvasBitmap, self.cellSize, self.fontName, self.fontPathName, self.fontSize = None, None, fontName, fontPathName, fontSize
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
GuiCanvasWxBackendFast_drawPatches(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyMethodDef
|
|
||||||
GuiCanvasWxBackendFast_methods[] = {
|
|
||||||
{"drawPatches", GuiCanvasWxBackendFast_drawPatches, METH_VARARGS, "XXX"},
|
|
||||||
{NULL, NULL, 0, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct PyModuleDef
|
|
||||||
GuiCanvasWxBackendFastmodule = {
|
|
||||||
PyModuleDef_HEAD_INIT, "GuiCanvasWxBackendFast", NULL, -1, GuiCanvasWxBackendFast_methods,
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
|
||||||
PyInit_GuiCanvasWxBackendFast(void)
|
|
||||||
{
|
|
||||||
return PyModule_Create(&GuiCanvasWxBackendFastmodule);
|
|
||||||
}
|
|
577
libgui/GuiCanvasWxBackendFast.cpp
Normal file
577
libgui/GuiCanvasWxBackendFast.cpp
Normal file
@ -0,0 +1,577 @@
|
|||||||
|
/*
|
||||||
|
* GuiCanvasWxBackendFast.cpp
|
||||||
|
* Copyright (c) 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(disable : 4514)
|
||||||
|
#pragma warning(disable : 4530)
|
||||||
|
#pragma warning(disable : 4577)
|
||||||
|
#pragma warning(disable : 4706)
|
||||||
|
#pragma warning(disable : 4710)
|
||||||
|
#pragma warning(disable : 4711)
|
||||||
|
#pragma warning(disable : 4820)
|
||||||
|
#pragma warning(disable : 5045)
|
||||||
|
#endif /* _MSC_VER_ */
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private types
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint32_t COLOUR;
|
||||||
|
#define COLOUR_ALPHA(colour) (((colour) >> 24) & 0xff)
|
||||||
|
|
||||||
|
typedef uint64_t COORD;
|
||||||
|
|
||||||
|
typedef struct point_s {
|
||||||
|
COORD x, y;
|
||||||
|
} POINT;
|
||||||
|
#define POINT_EMPTY {0ULL, 0ULL}
|
||||||
|
|
||||||
|
typedef enum cell_attrs_e {
|
||||||
|
CATTR_NONE = 0x00,
|
||||||
|
CATTR_BOLD = 0x01,
|
||||||
|
CATTR_UNDERLINE = 0x02,
|
||||||
|
} CELL_ATTRS;
|
||||||
|
|
||||||
|
typedef struct cell_s {
|
||||||
|
CELL_ATTRS attrs;
|
||||||
|
COLOUR bg, fg;
|
||||||
|
POINT p;
|
||||||
|
wchar_t txt[8];
|
||||||
|
} CELL;
|
||||||
|
#define CELL_EMPTY {CATTR_NONE, 0UL, 0UL, POINT_EMPTY, {L'\0',}}
|
||||||
|
|
||||||
|
typedef struct rect_s {
|
||||||
|
POINT p0, p1;
|
||||||
|
} RECT;
|
||||||
|
#define RECT_EMPTY {POINT_EMPTY, POINT_EMPTY}
|
||||||
|
#define RECT_HEIGHT(r) ((r).p1.y - (r).p0.y)
|
||||||
|
#define RECT_WIDTH(r) ((r).p1.x - (r).p0.x)
|
||||||
|
|
||||||
|
typedef struct size_s {
|
||||||
|
uint64_t h, w;
|
||||||
|
} SIZE;
|
||||||
|
#define SIZE_EMPTY {0ULL, 0ULL}
|
||||||
|
|
||||||
|
typedef std::vector<std::vector<uint8_t>> COLOUR_LIST;
|
||||||
|
typedef std::vector<std::vector<COLOUR>> CHAR_MAP_ITEM;
|
||||||
|
typedef std::map<wchar_t, CHAR_MAP_ITEM> CHAR_MAP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private constants and variables
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define BITMAP_BPS 24
|
||||||
|
#define BITMAP_BPS_BYTES 3
|
||||||
|
#define BLEND_ALPHA_COEFFICIENT 0.8
|
||||||
|
|
||||||
|
static PyObject *s_bitmap = NULL, *s_dc = NULL, *s_dc_tmp = NULL, *s_font = NULL, *s_wx = NULL, *s_wx_NullBitmap = NULL;
|
||||||
|
static uint8_t *s_bitmap_buffer = NULL;
|
||||||
|
static size_t s_bitmap_buffer_size = 0;
|
||||||
|
static SIZE s_bitmap_size = SIZE_EMPTY, s_cell_size = SIZE_EMPTY;
|
||||||
|
static CHAR_MAP s_char_map;
|
||||||
|
static PyObject *s_colour_black = NULL, *s_colour_white = NULL;
|
||||||
|
static PyObject *s_error = NULL;
|
||||||
|
|
||||||
|
static COLOUR_LIST s_colours = {
|
||||||
|
{255, 255, 255}, // Bright White
|
||||||
|
{0, 0, 0}, // Black
|
||||||
|
{0, 0, 187}, // Light Blue
|
||||||
|
{0, 187, 0}, // Green
|
||||||
|
{255, 85, 85}, // Red
|
||||||
|
{187, 0, 0}, // Light Red
|
||||||
|
{187, 0, 187}, // Pink
|
||||||
|
{187, 187, 0}, // Yellow
|
||||||
|
{255, 255, 85}, // Light Yellow
|
||||||
|
{85, 255, 85}, // Light Green
|
||||||
|
{0, 187, 187}, // Cyan
|
||||||
|
{85, 255, 255}, // Light Cyan
|
||||||
|
{85, 85, 255}, // Blue
|
||||||
|
{255, 85, 255}, // Light Pink
|
||||||
|
{85, 85, 85}, // Grey
|
||||||
|
{187, 187, 187}, // Light Grey
|
||||||
|
};
|
||||||
|
|
||||||
|
static COLOUR_LIST s_colours_bold = {
|
||||||
|
{255, 255, 255}, // Bright White
|
||||||
|
{85, 85, 85}, // Black
|
||||||
|
{85, 85, 255}, // Light Blue
|
||||||
|
{85, 255, 85}, // Green
|
||||||
|
{255, 85, 85}, // Red
|
||||||
|
{255, 85, 85}, // Light Red
|
||||||
|
{255, 85, 255}, // Pink
|
||||||
|
{255, 255, 85}, // Yellow
|
||||||
|
{255, 255, 85}, // Light Yellow
|
||||||
|
{85, 255, 85}, // Light Green
|
||||||
|
{85, 255, 255}, // Cyan
|
||||||
|
{85, 255, 255}, // Light Cyan
|
||||||
|
{85, 85, 255}, // Blue
|
||||||
|
{255, 85, 255}, // Light Pink
|
||||||
|
{85, 85, 85}, // Grey
|
||||||
|
{255, 255, 255}, // Light Grey
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private preprocessor macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#define PYTHON_TRY(expr, msg) \
|
||||||
|
[&](){bool rc = (bool)(expr); if (!rc) { PyErr_SetString(s_error, msg); }; return rc;}()
|
||||||
|
#define PYTHON_TRY_NOMEMORY(expr, msg) \
|
||||||
|
[&](){bool rc = (bool)(expr); if (!rc) { PyErr_SetString(PyExc_MemoryError, msg); }; return rc;}()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* N.B. required due to absence of Python_CallMethodV()
|
||||||
|
*/
|
||||||
|
#define COMMA ,
|
||||||
|
#define PYTHON_WRAP_METHOD(fn, fmt, args1, args2) \
|
||||||
|
static bool \
|
||||||
|
python_##fn(PyObject *obj, const char *default_error, PyObject **presult, args1) \
|
||||||
|
{ \
|
||||||
|
bool rc = true; \
|
||||||
|
PyObject *result; \
|
||||||
|
\
|
||||||
|
if ((result = PyObject_CallMethod(obj, #fn, fmt, args2))) { \
|
||||||
|
if (!presult) { \
|
||||||
|
Py_XDECREF(result); \
|
||||||
|
} else { \
|
||||||
|
*presult = result; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
rc = false; \
|
||||||
|
setErrorFromLast(default_error ? default_error \
|
||||||
|
: "Failed to call " # fn "()"); \
|
||||||
|
} \
|
||||||
|
return rc; \
|
||||||
|
}
|
||||||
|
#define PYTHON_WRAP_METHOD0(fn) \
|
||||||
|
static bool \
|
||||||
|
python_##fn(PyObject *obj, const char *default_error, PyObject **presult) \
|
||||||
|
{ \
|
||||||
|
bool rc = true; \
|
||||||
|
PyObject *result; \
|
||||||
|
\
|
||||||
|
if ((result = PyObject_CallMethod(obj, #fn, ""))) { \
|
||||||
|
if (!presult) { \
|
||||||
|
Py_XDECREF(result); \
|
||||||
|
} else { \
|
||||||
|
*presult = result; \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
rc = false; \
|
||||||
|
setErrorFromLast(default_error ? default_error \
|
||||||
|
: "Failed to call " # fn "()"); \
|
||||||
|
} \
|
||||||
|
return rc; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Static private subroutine prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
static COLOUR blendColours(COLOUR bg, COLOUR fg);
|
||||||
|
static void cellDraw(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, RECT *prect);
|
||||||
|
static bool cellDrawPixel(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, COLOUR colour, RECT *prect, COORD rx, COORD ry);
|
||||||
|
static bool cellDrawText(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, CHAR_MAP& char_map, RECT *prect);
|
||||||
|
static bool cellFetch(const COLOUR_LIST& colours, const COLOUR_LIST& colours_bold, PyObject *object, bool fromCanvas, POINT canvasPoint, CELL *pcell);
|
||||||
|
static void setErrorFromLast(const char *default_fmt, ...);
|
||||||
|
#ifdef TIMING
|
||||||
|
static std::chrono::system_clock::time_point timeBegin();
|
||||||
|
static double timeDelta(std::chrono::system_clock::time_point t0);
|
||||||
|
#endif /* TIMING */
|
||||||
|
static bool updateCharMap(SIZE cell_size, CHAR_MAP& char_map, wchar_t wch);
|
||||||
|
|
||||||
|
PYTHON_WRAP_METHOD(Bitmap, "lll", unsigned long long width COMMA unsigned long long height COMMA unsigned long long bits, width COMMA height COMMA bits);
|
||||||
|
PYTHON_WRAP_METHOD(Blit, "OllllOll", PyObject *self COMMA unsigned long long xdest COMMA unsigned long long ydest COMMA unsigned long long width COMMA unsigned long long height COMMA PyObject *source COMMA unsigned long long xsrc COMMA unsigned long long ysrc, self COMMA xdest COMMA ydest COMMA width COMMA height COMMA source COMMA xsrc COMMA ysrc);
|
||||||
|
PYTHON_WRAP_METHOD(Colour, "lll", unsigned long long red COMMA unsigned long long green COMMA unsigned long long blue, red COMMA green COMMA blue);
|
||||||
|
PYTHON_WRAP_METHOD(CopyFromBuffer, "Ol", PyObject *data COMMA unsigned long long format, data COMMA format);
|
||||||
|
PYTHON_WRAP_METHOD(CopyToBuffer, "Ol", PyObject *data COMMA unsigned long long format, data COMMA format);
|
||||||
|
PYTHON_WRAP_METHOD(DrawText, "u#ll", wchar_t *text COMMA size_t text_size COMMA unsigned long long x COMMA unsigned long long y, text COMMA text_size COMMA x COMMA y);
|
||||||
|
PYTHON_WRAP_METHOD0(MemoryDC);
|
||||||
|
PYTHON_WRAP_METHOD(SelectObject, "O", PyObject *bitmap, bitmap);
|
||||||
|
PYTHON_WRAP_METHOD(SetFont, "O", PyObject *font, font);
|
||||||
|
PYTHON_WRAP_METHOD(SetTextBackground, "O", PyObject *colour, colour);
|
||||||
|
PYTHON_WRAP_METHOD(SetTextForeground, "O", PyObject *colour, colour);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Static private subroutines
|
||||||
|
*/
|
||||||
|
|
||||||
|
static COLOUR
|
||||||
|
blendColours(COLOUR bg, COLOUR fg)
|
||||||
|
{
|
||||||
|
return (COLOUR)
|
||||||
|
(std::llround(((fg & 0xff) * BLEND_ALPHA_COEFFICIENT) + ((bg & 0xff) * (1.0 - BLEND_ALPHA_COEFFICIENT))) |
|
||||||
|
(std::llround((((fg >> 8) & 0xff) * BLEND_ALPHA_COEFFICIENT) + (((bg >> 8) & 0xff) * (1.0 - BLEND_ALPHA_COEFFICIENT))) << 8) |
|
||||||
|
(std::llround((((fg >> 16) & 0xff) * BLEND_ALPHA_COEFFICIENT) + (((bg >> 16) & 0xff) * (1.0 - BLEND_ALPHA_COEFFICIENT))) << 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cellDraw(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, RECT *prect)
|
||||||
|
{
|
||||||
|
for (COORD ry = 0; ry < cell_size.h; ry++) {
|
||||||
|
for (COORD rx = 0; rx < cell_size.w; rx++)
|
||||||
|
cellDrawPixel(bitmap_bps_bytes, bitmap_buffer, bitmap_size, cell, cell_size, cell.bg, prect, rx, ry);
|
||||||
|
}
|
||||||
|
if (cell.attrs & CATTR_UNDERLINE) {
|
||||||
|
for (COORD rx = 0, ry = (cell_size.h - 1); rx < cell_size.w; rx++)
|
||||||
|
cellDrawPixel(bitmap_bps_bytes, bitmap_buffer, bitmap_size, cell, cell_size, cell.fg, prect, rx, ry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cellDrawPixel(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, COLOUR colour, RECT *prect, COORD rx, COORD ry)
|
||||||
|
{
|
||||||
|
COORD offset, x_, y_;
|
||||||
|
bool rc = false;
|
||||||
|
|
||||||
|
x_ = (cell.p.x * cell_size.w) + rx, y_ = (cell.p.y * cell_size.h) + ry;
|
||||||
|
offset = ((y_ * bitmap_size.w) + x_) * bitmap_bps_bytes;
|
||||||
|
if ((x_ < bitmap_size.w) && (y_ < bitmap_size.h)) {
|
||||||
|
prect->p0.x = MIN(prect->p0.x > 0 ? prect->p0.x : x_, x_);
|
||||||
|
prect->p0.y = MIN(prect->p0.y > 0 ? prect->p0.y : y_, y_);
|
||||||
|
prect->p1.x = MAX(prect->p1.x, x_+ 1); prect->p1.y = MAX(prect->p1.y, y_+ 1);
|
||||||
|
bitmap_buffer[offset] = colour & 0xff;
|
||||||
|
bitmap_buffer[offset + 1] = (colour >> 8) & 0xff;
|
||||||
|
bitmap_buffer[offset + 2] = (colour >> 16) & 0xff;
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cellDrawText(size_t bitmap_bps_bytes, uint8_t *bitmap_buffer, SIZE bitmap_size, CELL cell, SIZE cell_size, CHAR_MAP& char_map, RECT *prect)
|
||||||
|
{
|
||||||
|
CHAR_MAP::iterator char_map_item;
|
||||||
|
COLOUR colour;
|
||||||
|
bool rc = true;
|
||||||
|
|
||||||
|
for (size_t nch = 0; (nch < (sizeof(cell.txt) / sizeof(cell.txt[0]))) && (cell.txt[nch]); nch++) {
|
||||||
|
if ((char_map_item = char_map.find(cell.txt[nch])) == char_map.end()) {
|
||||||
|
if (updateCharMap(cell_size, char_map, cell.txt[nch]))
|
||||||
|
char_map_item = char_map.find(cell.txt[nch]);
|
||||||
|
else {
|
||||||
|
rc = false; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (COORD ry = 0; ry < cell_size.h; ry++) {
|
||||||
|
for (COORD rx = 0; rx < cell_size.w; rx++) {
|
||||||
|
if ((char_map_item != char_map.end())
|
||||||
|
&& (char_map_item->second[ry][rx] != (COLOUR)0x0L))
|
||||||
|
colour = cell.fg;
|
||||||
|
else
|
||||||
|
colour = cell.bg;
|
||||||
|
cellDrawPixel(bitmap_bps_bytes, bitmap_buffer, bitmap_size, cell, cell_size, colour, prect, rx, ry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cell.attrs & CATTR_UNDERLINE) {
|
||||||
|
for (COORD rx = 0, ry = (cell_size.h - 1); rx < cell_size.w; rx++)
|
||||||
|
cellDrawPixel(bitmap_bps_bytes, bitmap_buffer, bitmap_size, cell, cell_size, cell.fg, prect, rx, ry);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
cellFetch(const COLOUR_LIST& colours, const COLOUR_LIST& colours_bold, PyObject *object, bool fromCanvas, POINT canvasPoint, CELL *pcell)
|
||||||
|
{
|
||||||
|
long bg, fg;
|
||||||
|
PyObject *canvasMapRow, *cellObject = NULL, *txt;
|
||||||
|
Py_ssize_t offset, txt_len;
|
||||||
|
const COLOUR_LIST *pcolours;
|
||||||
|
bool rc = false;
|
||||||
|
|
||||||
|
if (fromCanvas) {
|
||||||
|
offset = -2;
|
||||||
|
if ((canvasMapRow = PyList_GetItem(object, (Py_ssize_t)canvasPoint.y)))
|
||||||
|
cellObject = PyList_GetItem(canvasMapRow, (Py_ssize_t)canvasPoint.x);
|
||||||
|
} else
|
||||||
|
cellObject = object, offset = 0;
|
||||||
|
if (cellObject && PyList_Check(cellObject) && (PyList_Size(cellObject) == 6 + offset)) {
|
||||||
|
if (!fromCanvas) {
|
||||||
|
pcell->p.x = PyLong_AsUnsignedLongLong(PyList_GetItem(cellObject, 0));
|
||||||
|
pcell->p.y = PyLong_AsUnsignedLongLong(PyList_GetItem(cellObject, 1));
|
||||||
|
}
|
||||||
|
fg = PyLong_AsLong(PyList_GetItem(cellObject, 2 + offset));
|
||||||
|
bg = PyLong_AsLong(PyList_GetItem(cellObject, 3 + offset));
|
||||||
|
pcell->attrs = (CELL_ATTRS)PyLong_AsUnsignedLong(PyList_GetItem(cellObject, 4 + offset));
|
||||||
|
if (pcell->attrs & CATTR_BOLD)
|
||||||
|
pcolours = &colours_bold;
|
||||||
|
else
|
||||||
|
pcolours = &colours;
|
||||||
|
pcell->bg = (bg == -1) ? 0xff000000 : (COLOUR)((colours[(uint8_t)bg][0]) | ((colours[(uint8_t)bg][1] << 8) & 0xff00) | ((colours[(uint8_t)bg][2] << 16) & 0xff0000));
|
||||||
|
pcell->fg = (fg == -1) ? pcell->bg : (COLOUR)(((*pcolours)[(uint8_t)fg][0]) | (((*pcolours)[(uint8_t)fg][1] << 8) & 0xff00) | (((*pcolours)[(uint8_t)fg][2] << 16) & 0xff0000));
|
||||||
|
txt = PyList_GetItem(cellObject, 5 + offset);
|
||||||
|
if ((txt_len = PyUnicode_AsWideChar(txt, pcell->txt, sizeof(pcell->txt) / sizeof(pcell->txt[0]))) > 0) {
|
||||||
|
if (txt_len < (sizeof(pcell->txt) / sizeof(pcell->txt[0])))
|
||||||
|
pcell->txt[txt_len] = L'\0';
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setErrorFromLast(const char *default_fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
static char default_buf[1024];
|
||||||
|
PyObject *exc_traceback, *exc_type, *exc_value = NULL;
|
||||||
|
|
||||||
|
PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
|
||||||
|
if (exc_value)
|
||||||
|
PyErr_SetObject(s_error, exc_value);
|
||||||
|
else {
|
||||||
|
va_start(ap, default_fmt);
|
||||||
|
vsnprintf_s(default_buf, sizeof(default_buf), default_fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
PyErr_SetString(s_error, default_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TIMING
|
||||||
|
static std::chrono::system_clock::time_point
|
||||||
|
timeBegin()
|
||||||
|
{
|
||||||
|
return std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
static double
|
||||||
|
timeDelta(std::chrono::system_clock::time_point t0)
|
||||||
|
{
|
||||||
|
return ((std::chrono::duration<double>)(std::chrono::system_clock::now() - t0)).count();
|
||||||
|
}
|
||||||
|
#endif /* TIMING */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
updateCharMap(SIZE cell_size, CHAR_MAP& char_map, wchar_t wch)
|
||||||
|
{
|
||||||
|
PyObject *bitmap, *mv = NULL;
|
||||||
|
Py_buffer buffer;
|
||||||
|
uint8_t *char_buffer = NULL;
|
||||||
|
size_t char_buffer_size;
|
||||||
|
bool rc = false;
|
||||||
|
|
||||||
|
PyBuffer_FillInfo(&buffer, 0, NULL, 0, false, PyBUF_WRITABLE);
|
||||||
|
char_buffer_size = s_cell_size.w * s_cell_size.h * BITMAP_BPS_BYTES;
|
||||||
|
if (python_Bitmap(s_wx, NULL, &bitmap, s_cell_size.w, s_cell_size.h, BITMAP_BPS)
|
||||||
|
&& python_SelectObject(s_dc_tmp, NULL, NULL, bitmap)
|
||||||
|
&& python_SetFont(s_dc_tmp, NULL, NULL, s_font)
|
||||||
|
&& python_SetTextBackground(s_dc_tmp, NULL, NULL, s_colour_black)
|
||||||
|
&& python_SetTextForeground(s_dc_tmp, NULL, NULL, s_colour_white)
|
||||||
|
&& python_DrawText(s_dc_tmp, NULL, NULL, &wch, 1, 0, 0)
|
||||||
|
&& PYTHON_TRY_NOMEMORY((char_buffer = (uint8_t *)malloc(char_buffer_size)), "Failed to allocate character bitmap buffer")
|
||||||
|
&& PYTHON_TRY(PyBuffer_FillInfo(&buffer, 0, char_buffer, (Py_ssize_t)char_buffer_size, false, PyBUF_WRITABLE) == 0, "Failed to create Py_buffer")
|
||||||
|
&& PYTHON_TRY((mv = PyMemoryView_FromBuffer(&buffer)), "Failed to create Py_buffer memory view")
|
||||||
|
&& python_CopyToBuffer(bitmap, NULL, NULL, mv, 0)) {
|
||||||
|
char_map[wch] = CHAR_MAP_ITEM(cell_size.h);
|
||||||
|
for (COORD ry = 0; ry < cell_size.h; ry++) {
|
||||||
|
for (COORD rx = 0; rx < cell_size.w; rx++)
|
||||||
|
char_map[wch][ry].push_back(
|
||||||
|
(((COLOUR)char_buffer[(((ry * cell_size.w) + rx) * BITMAP_BPS_BYTES)]) & 0xff) |
|
||||||
|
(((COLOUR)char_buffer[(((ry * cell_size.w) + rx) * BITMAP_BPS_BYTES) + 1] << 8) & 0xff00) |
|
||||||
|
(((COLOUR)char_buffer[(((ry * cell_size.w) + rx) * BITMAP_BPS_BYTES) + 2] << 16) & 0xff0000));
|
||||||
|
}
|
||||||
|
rc = true;
|
||||||
|
}
|
||||||
|
if (s_dc_tmp)
|
||||||
|
python_SelectObject(s_dc_tmp, NULL, NULL, s_wx_NullBitmap);
|
||||||
|
Py_XDECREF(bitmap);
|
||||||
|
if (char_buffer) {
|
||||||
|
free(char_buffer);
|
||||||
|
}
|
||||||
|
Py_XDECREF(mv); PyBuffer_Release(&buffer);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private Python module subroutine prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyObject *GuiCanvasWxBackendFast_drawPatches(PyObject *self, PyObject *args);
|
||||||
|
static PyObject *GuiCanvasWxBackendFast_init(PyObject *self, PyObject *args);
|
||||||
|
static PyObject *GuiCanvasWxBackendFast_resize(PyObject *self, PyObject *args);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Private Python module subroutines
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
GuiCanvasWxBackendFast_drawPatches(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *bitmap, *canvas_map, *canvas_size_obj, *eventDc, *patches;
|
||||||
|
Py_buffer buffer;
|
||||||
|
SIZE canvas_size;
|
||||||
|
CELL cell, cell_canvas;
|
||||||
|
bool isCursor, skip, status = true;
|
||||||
|
PyObject *iter, *iter_cur, *mv = NULL, *rc = NULL;
|
||||||
|
RECT rect = RECT_EMPTY;
|
||||||
|
|
||||||
|
(void)self;
|
||||||
|
PyBuffer_FillInfo(&buffer, 0, NULL, 0, false, PyBUF_WRITABLE);
|
||||||
|
#ifdef TIMING
|
||||||
|
auto t0 = timeBegin();
|
||||||
|
#endif /* TIMING */
|
||||||
|
if (PYTHON_TRY(PyArg_ParseTuple(args, "OOOOpO", &bitmap, &canvas_map, &canvas_size_obj, &eventDc, &isCursor, &patches), "Invalid arguments")
|
||||||
|
&& PYTHON_TRY((iter = PyObject_GetIter(patches)), "Failed to get patches iterator object")) {
|
||||||
|
canvas_size.w = PyLong_AsUnsignedLong(PyList_GetItem(canvas_size_obj, 0));
|
||||||
|
canvas_size.h = PyLong_AsUnsignedLong(PyList_GetItem(canvas_size_obj, 1));
|
||||||
|
while (iter_cur = PyIter_Next(iter)) {
|
||||||
|
skip = false, status = true;
|
||||||
|
if (PYTHON_TRY(cellFetch(s_colours, s_colours_bold, iter_cur, false, POINT_EMPTY, &cell), "Failed to get patch cell")) {
|
||||||
|
if (isCursor) {
|
||||||
|
if (!(skip = !cellFetch(s_colours, s_colours_bold, canvas_map, true, cell.p, &cell_canvas))) {
|
||||||
|
cell.attrs = cell_canvas.attrs;
|
||||||
|
if (COLOUR_ALPHA(cell.bg) != 0xff) {
|
||||||
|
cell.fg = blendColours(cell_canvas.fg, cell.bg); cell.bg = blendColours(cell_canvas.bg, cell.bg);
|
||||||
|
if ((cell_canvas.txt[0] == L' ') && (COLOUR_ALPHA(cell_canvas.bg) == 0xff))
|
||||||
|
cell.txt[0] = L'\u2591', cell.txt[1] = L'\0';
|
||||||
|
else
|
||||||
|
memcpy(cell.txt, cell_canvas.txt, sizeof(cell.txt));
|
||||||
|
} else if (COLOUR_ALPHA(cell_canvas.bg) == 0xff) {
|
||||||
|
cell.fg = cell_canvas.fg, cell.bg = cell_canvas.bg;
|
||||||
|
if (cell_canvas.txt[0] == L' ')
|
||||||
|
cell.txt[0] = L'\u2591', cell.txt[1] = L'\0';
|
||||||
|
else
|
||||||
|
memcpy(cell.txt, cell_canvas.txt, sizeof(cell.txt));
|
||||||
|
} else {
|
||||||
|
cell.fg = cell_canvas.fg, cell.bg = cell_canvas.bg;
|
||||||
|
memcpy(cell.txt, cell_canvas.txt, sizeof(cell.txt));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((cell.txt[0] == L' ') && (COLOUR_ALPHA(cell.bg) == 0xff))
|
||||||
|
cell.bg = 0x00000000, cell.txt[0] = L'\u2591', cell.txt[1] = L'\0';
|
||||||
|
if (status && !skip) {
|
||||||
|
if (cell.txt[0] != L' ')
|
||||||
|
status = cellDrawText(BITMAP_BPS_BYTES, s_bitmap_buffer, s_bitmap_size, cell, s_cell_size, s_char_map, &rect);
|
||||||
|
else
|
||||||
|
cellDraw(BITMAP_BPS_BYTES, s_bitmap_buffer, s_bitmap_size, cell, s_cell_size, &rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_XDECREF(iter_cur);
|
||||||
|
}
|
||||||
|
Py_XDECREF(iter);
|
||||||
|
if (status
|
||||||
|
&& PYTHON_TRY(PyBuffer_FillInfo(&buffer, 0, s_bitmap_buffer, (Py_ssize_t)s_bitmap_buffer_size, false, PyBUF_WRITABLE) == 0, "Failed to create Py_buffer")
|
||||||
|
&& PYTHON_TRY((mv = PyMemoryView_FromBuffer(&buffer)), "Failed to create Py_buffer memory view")
|
||||||
|
&& python_CopyFromBuffer(s_bitmap, NULL, NULL, mv, 0)
|
||||||
|
&& python_Blit((PyObject *)eventDc->ob_type, NULL, NULL, eventDc, rect.p0.x, rect.p0.y, RECT_WIDTH(rect), RECT_HEIGHT(rect), s_dc, rect.p0.x, rect.p0.y)) {
|
||||||
|
Py_INCREF(Py_True), rc = Py_True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef TIMING
|
||||||
|
printf("drawing took %.2f ms\n", timeDelta(t0) * 1000);
|
||||||
|
#endif /* TIMING */
|
||||||
|
Py_XDECREF(mv); PyBuffer_Release(&buffer);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
GuiCanvasWxBackendFast_init(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *colour_black = NULL, *colour_white = NULL, *dc = NULL, *dc_tmp = NULL, *wx = NULL, *wx_NullBitmap = NULL;
|
||||||
|
PyObject *rc = NULL, *wx_dict;
|
||||||
|
|
||||||
|
(void)self;
|
||||||
|
if (PYTHON_TRY(PyArg_ParseTuple(args, "O", &wx), "Invalid arguments")
|
||||||
|
&& PYTHON_TRY((wx_dict = PyModule_GetDict(wx)), "Failed to get wx module dictionary")
|
||||||
|
&& python_Colour(wx, NULL, &colour_black, 0, 0, 0)
|
||||||
|
&& python_Colour(wx, NULL, &colour_white, 255, 255, 255)
|
||||||
|
&& python_MemoryDC(wx, NULL, &dc)
|
||||||
|
&& python_MemoryDC(wx, NULL, &dc_tmp)
|
||||||
|
&& PYTHON_TRY((wx_NullBitmap = PyObject_GetAttrString(wx, "NullBitmap")), "Failed to get wx.NullBitmap attribute")) {
|
||||||
|
s_colour_black = colour_black, s_colour_white = colour_white, s_dc = dc, s_dc_tmp = dc_tmp;
|
||||||
|
s_wx = wx; Py_INCREF(wx_NullBitmap), s_wx_NullBitmap = wx_NullBitmap;
|
||||||
|
Py_INCREF(Py_True), rc = Py_True;
|
||||||
|
}
|
||||||
|
if (!rc) {
|
||||||
|
Py_XDECREF(colour_black); Py_XDECREF(colour_white); Py_XDECREF(dc); Py_XDECREF(dc_tmp); Py_XDECREF(wx_NullBitmap);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
GuiCanvasWxBackendFast_resize(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
uint8_t *bitmap_buffer_new = NULL;
|
||||||
|
size_t bitmap_buffer_size_new;
|
||||||
|
PyObject *bitmap_new = NULL;
|
||||||
|
SIZE bitmap_size_new, cell_size_new;
|
||||||
|
PyObject *cellSize, *cellSizeHeightObj, *cellSizeWidthObj, *font, *winSize, *winSizeHeightObj, *winSizeWidthObj, *rc = NULL;
|
||||||
|
|
||||||
|
(void)self;
|
||||||
|
if (PYTHON_TRY(PyArg_ParseTuple(args, "OOO", &cellSize, &font, &winSize) && PyTuple_Check(cellSize) && PyTuple_Check(winSize), "Invalid arguments")) {
|
||||||
|
cellSizeWidthObj = PyTuple_GetItem(cellSize, 0); cellSizeHeightObj = PyTuple_GetItem(cellSize, 1);
|
||||||
|
cell_size_new.w = PyLong_AsUnsignedLong(cellSizeWidthObj); cell_size_new.h = PyLong_AsUnsignedLong(cellSizeHeightObj);
|
||||||
|
winSizeWidthObj = PyTuple_GetItem(winSize, 0); bitmap_size_new.w = PyLong_AsUnsignedLong(winSizeWidthObj);
|
||||||
|
winSizeHeightObj = PyTuple_GetItem(winSize, 1); bitmap_size_new.h = PyLong_AsUnsignedLong(winSizeHeightObj);
|
||||||
|
bitmap_buffer_size_new = bitmap_size_new.h * bitmap_size_new.w * BITMAP_BPS_BYTES;
|
||||||
|
if (python_Bitmap(s_wx, NULL, &bitmap_new, bitmap_size_new.w, bitmap_size_new.h, BITMAP_BPS)
|
||||||
|
&& (s_bitmap ? python_SelectObject(s_dc, NULL, NULL, s_wx_NullBitmap) : true)
|
||||||
|
&& python_SelectObject(s_dc, NULL, NULL, bitmap_new)
|
||||||
|
&& PYTHON_TRY_NOMEMORY((bitmap_buffer_new = (uint8_t *)malloc(bitmap_buffer_size_new)), "Failed to allocate bitmap buffer")) {
|
||||||
|
if (s_bitmap_buffer)
|
||||||
|
free(s_bitmap_buffer);
|
||||||
|
s_bitmap_buffer = bitmap_buffer_new;
|
||||||
|
Py_XDECREF(s_bitmap); s_bitmap = bitmap_new;
|
||||||
|
s_bitmap_buffer_size = bitmap_buffer_size_new, s_bitmap_size = bitmap_size_new;
|
||||||
|
if ((cell_size_new.h != s_cell_size.h) || (cell_size_new.w != s_cell_size.w))
|
||||||
|
s_char_map.clear();
|
||||||
|
s_cell_size = cell_size_new; Py_INCREF(font), s_font = font; Py_INCREF(Py_True), rc = Py_True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rc) {
|
||||||
|
if (bitmap_buffer_new)
|
||||||
|
free(bitmap_buffer_new);
|
||||||
|
Py_XDECREF(bitmap_new); Py_XDECREF(font);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Python C/C++ extension footer
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyMethodDef
|
||||||
|
GuiCanvasWxBackendFast_methods[] = {
|
||||||
|
{"drawPatches", GuiCanvasWxBackendFast_drawPatches, METH_VARARGS, "drawPatches"},
|
||||||
|
{"init", GuiCanvasWxBackendFast_init, METH_VARARGS, "init"},
|
||||||
|
{"resize", GuiCanvasWxBackendFast_resize, METH_VARARGS, "resize"},
|
||||||
|
{NULL, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct PyModuleDef
|
||||||
|
GuiCanvasWxBackendFastmodule = {
|
||||||
|
PyModuleDef_HEAD_INIT, "GuiCanvasWxBackendFast", NULL, -1, GuiCanvasWxBackendFast_methods,
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit_GuiCanvasWxBackendFast(void)
|
||||||
|
{
|
||||||
|
PyObject *m = NULL;
|
||||||
|
|
||||||
|
m = PyModule_Create(&GuiCanvasWxBackendFastmodule);
|
||||||
|
s_error = PyErr_NewException("GuiCanvasWxBackendFast.error", NULL, NULL);
|
||||||
|
Py_XINCREF(s_error);
|
||||||
|
if (PyModule_AddObject(m, "error", s_error) < 0) {
|
||||||
|
Py_XDECREF(s_error); Py_CLEAR(s_error); Py_DECREF(m); m = NULL;
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
@ -165,7 +165,7 @@ class RoarAssetsWindow(GuiMiniFrame):
|
|||||||
def resize(self, canvas, newSize):
|
def resize(self, canvas, newSize):
|
||||||
oldSize = [0, 0] if canvas.map == None else canvas.size
|
oldSize = [0, 0] if canvas.map == None else canvas.size
|
||||||
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
||||||
if canvas.resize(newSize, False):
|
if canvas.resize((1, 1,), newSize, False):
|
||||||
panelSize = [a * b for a, b in zip(canvas.size, self.backend.cellSize)]
|
panelSize = [a * b for a, b in zip(canvas.size, self.backend.cellSize)]
|
||||||
self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize);
|
self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize);
|
||||||
curWindow = self.panelCanvas
|
curWindow = self.panelCanvas
|
||||||
@ -228,6 +228,7 @@ class RoarAssetsWindow(GuiMiniFrame):
|
|||||||
id = +1 if keyCode == wx.WXK_DOWN else -1
|
id = +1 if keyCode == wx.WXK_DOWN else -1
|
||||||
self.currentIndex = (self.currentIndex + id) % len(self.canvasList)
|
self.currentIndex = (self.currentIndex + id) % len(self.canvasList)
|
||||||
self.listView.Select(self.currentIndex, on=1)
|
self.listView.Select(self.currentIndex, on=1)
|
||||||
|
self.listView.EnsureVisible(self.currentIndex)
|
||||||
else:
|
else:
|
||||||
index, rc = self.listView.GetFirstSelected(), False
|
index, rc = self.listView.GetFirstSelected(), False
|
||||||
if index != -1:
|
if index != -1:
|
||||||
@ -304,6 +305,8 @@ class RoarAssetsWindow(GuiMiniFrame):
|
|||||||
break
|
break
|
||||||
while len(items):
|
while len(items):
|
||||||
self._removeAsset(items[0]); del items[0]; items = [i - 1 for i in items];
|
self._removeAsset(items[0]); del items[0]; items = [i - 1 for i in items];
|
||||||
|
if self.currentIndex != None:
|
||||||
|
self.listView.EnsureVisible(self.currentIndex)
|
||||||
|
|
||||||
def onSaveList(self, event):
|
def onSaveList(self, event):
|
||||||
rc = True
|
rc = True
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from GuiCanvasColours import Colours
|
from GuiCanvasColours import Colours
|
||||||
from GuiFrame import NID_TOOLBAR_HSEP
|
from GuiFrame import NID_MENU_SEP, NID_TOOLBAR_HSEP
|
||||||
from RoarCanvasCommandsEdit import RoarCanvasCommandsEdit
|
from RoarCanvasCommandsEdit import RoarCanvasCommandsEdit
|
||||||
from RoarCanvasCommandsFile import RoarCanvasCommandsFile
|
from RoarCanvasCommandsFile import RoarCanvasCommandsFile
|
||||||
from RoarCanvasCommandsHelp import RoarCanvasCommandsHelp
|
from RoarCanvasCommandsHelp import RoarCanvasCommandsHelp
|
||||||
from RoarCanvasCommandsOperators import RoarCanvasCommandsOperators
|
from RoarCanvasCommandsOperators import RoarCanvasCommandsOperators
|
||||||
from RoarCanvasCommandsTools import RoarCanvasCommandsTools
|
from RoarCanvasCommandsTools import RoarCanvasCommandsTools
|
||||||
|
from ToolObject import ToolObject
|
||||||
import os, wx
|
import os, wx
|
||||||
|
|
||||||
class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCanvasCommandsTools, RoarCanvasCommandsOperators, RoarCanvasCommandsHelp):
|
class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCanvasCommandsTools, RoarCanvasCommandsOperators, RoarCanvasCommandsHelp):
|
||||||
@ -40,6 +41,65 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||||||
_initColourBitmaps_(RoarCanvasCommandsEdit.canvasColour, RoarCanvasCommandsEdit.canvasColourAlpha, 1.0)
|
_initColourBitmaps_(RoarCanvasCommandsEdit.canvasColour, RoarCanvasCommandsEdit.canvasColourAlpha, 1.0)
|
||||||
_initColourBitmaps_(RoarCanvasCommandsEdit.canvasColourBackground, RoarCanvasCommandsEdit.canvasColourAlphaBackground, 1.5)
|
_initColourBitmaps_(RoarCanvasCommandsEdit.canvasColourBackground, RoarCanvasCommandsEdit.canvasColourAlphaBackground, 1.5)
|
||||||
|
|
||||||
|
def _initInterface(self):
|
||||||
|
accels = ()
|
||||||
|
menus = (
|
||||||
|
("&File",
|
||||||
|
self.canvasNew, self.canvasOpen, self.canvasOpenRecent, self.canvasRestore, self.canvasSave, self.canvasSaveAs, NID_MENU_SEP,
|
||||||
|
("&Export...", self.canvasExportAsAnsi, self.canvasExportToClipboard, self.canvasExportImgur, self.canvasExportPastebin, self.canvasExportAsPng,),
|
||||||
|
("&Import...", self.canvasImportAnsi, self.canvasImportFromClipboard, self.canvasImportSauce,),
|
||||||
|
NID_MENU_SEP,
|
||||||
|
self.canvasExit,
|
||||||
|
),
|
||||||
|
("&Edit",
|
||||||
|
self.canvasUndo, self.canvasRedo, NID_MENU_SEP,
|
||||||
|
self.canvasCut, self.canvasCopy, self.canvasPaste,
|
||||||
|
self.canvasDelete, NID_MENU_SEP,
|
||||||
|
("Brush size", self.canvasBrushSize(self.canvasBrushSize, 0, True), self.canvasBrushSize(self.canvasBrushSize, 0, False), self.canvasBrushSize(self.canvasBrushSize, 1, True), self.canvasBrushSize(self.canvasBrushSize, 1, False), NID_MENU_SEP,
|
||||||
|
self.canvasBrushSize(self.canvasBrushSize, 2, True), self.canvasBrushSize(self.canvasBrushSize, 2, False),),
|
||||||
|
("Canvas size", self.canvasCanvasSize(self.canvasCanvasSize, 1, True), self.canvasCanvasSize(self.canvasCanvasSize, 1, False), self.canvasCanvasSize(self.canvasCanvasSize, 0, True), self.canvasCanvasSize(self.canvasCanvasSize, 0, False), NID_MENU_SEP,
|
||||||
|
self.canvasCanvasSize(self.canvasCanvasSize, 2, True), self.canvasCanvasSize(self.canvasCanvasSize, 2, False),),
|
||||||
|
self.canvasColoursFlip,
|
||||||
|
NID_MENU_SEP,
|
||||||
|
self.canvasBrush(self.canvasBrush, 0), NID_MENU_SEP,
|
||||||
|
self.canvasAssetsWindowHide, self.canvasAssetsWindowShow,
|
||||||
|
),
|
||||||
|
("&Tools",
|
||||||
|
self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6),
|
||||||
|
),
|
||||||
|
("&Operators",
|
||||||
|
self.canvasOperator(self.canvasOperator, 0), self.canvasOperator(self.canvasOperator, 1), self.canvasOperator(self.canvasOperator, 2), self.canvasOperator(self.canvasOperator, 3), self.canvasOperator(self.canvasOperator, 4),
|
||||||
|
),
|
||||||
|
("&Help",
|
||||||
|
self.canvasMelp, NID_MENU_SEP, self.canvasNewIssueGitHub, self.canvasVisitGitHub, NID_MENU_SEP, self.canvasAbout,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
toolBars = (
|
||||||
|
(self.canvasNew, self.canvasOpen, self.canvasSave, self.canvasSaveAs, NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasUndo, self.canvasRedo, NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasCut, self.canvasCopy, self.canvasPaste, self.canvasDelete, NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasAssetsWindowHide, self.canvasAssetsWindowShow, NID_TOOLBAR_HSEP,
|
||||||
|
),
|
||||||
|
(self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6),),
|
||||||
|
(self.canvasColour(self.canvasColour, 0), self.canvasColour(self.canvasColour, 1), self.canvasColour(self.canvasColour, 2), self.canvasColour(self.canvasColour, 3),
|
||||||
|
self.canvasColour(self.canvasColour, 4), self.canvasColour(self.canvasColour, 5), self.canvasColour(self.canvasColour, 6), self.canvasColour(self.canvasColour, 7),
|
||||||
|
self.canvasColour(self.canvasColour, 8), self.canvasColour(self.canvasColour, 9), self.canvasColour(self.canvasColour, 10), self.canvasColour(self.canvasColour, 11),
|
||||||
|
self.canvasColour(self.canvasColour, 12), self.canvasColour(self.canvasColour, 13), self.canvasColour(self.canvasColour, 14), self.canvasColour(self.canvasColour, 15),
|
||||||
|
self.canvasColourAlpha(self.canvasColourAlpha, 0), self.canvasColoursFlip, NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasBrushSize(self.canvasBrushSize, 1, True), self.canvasBrushSize(self.canvasBrushSize, 1, False), self.canvasBrushSize(self.canvasBrushSize, 0, True), self.canvasBrushSize(self.canvasBrushSize, 0, False), NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasBrushSize(self.canvasBrushSize, 2, True), self.canvasBrushSize(self.canvasBrushSize, 2, False),
|
||||||
|
),
|
||||||
|
(self.canvasColourBackground(self.canvasColourBackground, 0), self.canvasColourBackground(self.canvasColourBackground, 1), self.canvasColourBackground(self.canvasColourBackground, 2), self.canvasColourBackground(self.canvasColourBackground, 3),
|
||||||
|
self.canvasColourBackground(self.canvasColourBackground, 4), self.canvasColourBackground(self.canvasColourBackground, 5), self.canvasColourBackground(self.canvasColourBackground, 6), self.canvasColourBackground(self.canvasColourBackground, 7),
|
||||||
|
self.canvasColourBackground(self.canvasColourBackground, 8), self.canvasColourBackground(self.canvasColourBackground, 9), self.canvasColourBackground(self.canvasColourBackground, 10), self.canvasColourBackground(self.canvasColourBackground, 11),
|
||||||
|
self.canvasColourBackground(self.canvasColourBackground, 12), self.canvasColourBackground(self.canvasColourBackground, 13), self.canvasColourBackground(self.canvasColourBackground, 14), self.canvasColourBackground(self.canvasColourBackground, 15),
|
||||||
|
self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0), self.canvasColoursFlip, NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasCanvasSize(self.canvasCanvasSize, 1, True), self.canvasCanvasSize(self.canvasCanvasSize, 1, False), self.canvasCanvasSize(self.canvasCanvasSize, 0, True), self.canvasCanvasSize(self.canvasCanvasSize, 0, False), NID_TOOLBAR_HSEP,
|
||||||
|
self.canvasCanvasSize(self.canvasCanvasSize, 2, True), self.canvasCanvasSize(self.canvasCanvasSize, 2, False),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return accels, menus, toolBars
|
||||||
|
|
||||||
def update(self, **kwargs):
|
def update(self, **kwargs):
|
||||||
self.lastPanelState.update(kwargs); textItems = [];
|
self.lastPanelState.update(kwargs); textItems = [];
|
||||||
if "cellPos" in self.lastPanelState:
|
if "cellPos" in self.lastPanelState:
|
||||||
@ -53,17 +113,13 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"]][0]
|
toolBar = self.parentFrame.toolBarItemsById[self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"]][0]
|
||||||
toolBarBg = self.parentFrame.toolBarItemsById[self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"]][0]
|
toolBarBg = self.parentFrame.toolBarItemsById[self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"]][0]
|
||||||
if self.lastPanelState["colours"][0] != -1:
|
if self.lastPanelState["colours"][0] != -1:
|
||||||
toolBar.ToggleTool(self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"], True)
|
toolBar.ToggleTool(self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"], True); toolBar.Refresh()
|
||||||
toolBar.Refresh()
|
|
||||||
else:
|
else:
|
||||||
toolBar.ToggleTool(self.canvasColourAlpha(self.canvasColourAlpha, 0).attrDict["id"], True)
|
toolBar.ToggleTool(self.canvasColourAlpha(self.canvasColourAlpha, 0).attrDict["id"], True); toolBar.Refresh()
|
||||||
toolBar.Refresh()
|
|
||||||
if self.lastPanelState["colours"][1] != -1:
|
if self.lastPanelState["colours"][1] != -1:
|
||||||
toolBarBg.ToggleTool(self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"], True)
|
toolBarBg.ToggleTool(self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"], True); toolBarBg.Refresh()
|
||||||
toolBarBg.Refresh()
|
|
||||||
else:
|
else:
|
||||||
toolBarBg.ToggleTool(self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0).attrDict["id"], True)
|
toolBarBg.ToggleTool(self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0).attrDict["id"], True); toolBarBg.Refresh()
|
||||||
toolBarBg.Refresh()
|
|
||||||
if "pathName" in self.lastPanelState:
|
if "pathName" in self.lastPanelState:
|
||||||
if self.lastPanelState["pathName"] != None:
|
if self.lastPanelState["pathName"] != None:
|
||||||
basePathName = os.path.basename(self.lastPanelState["pathName"])
|
basePathName = os.path.basename(self.lastPanelState["pathName"])
|
||||||
@ -71,27 +127,25 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||||||
self.parentFrame.SetTitle("{} - roar".format(basePathName))
|
self.parentFrame.SetTitle("{} - roar".format(basePathName))
|
||||||
else:
|
else:
|
||||||
self.parentFrame.SetTitle("roar")
|
self.parentFrame.SetTitle("roar")
|
||||||
if "toolName" in self.lastPanelState:
|
if "currentTool" in self.lastPanelState:
|
||||||
textItems.append("T: {}".format(self.lastPanelState["toolName"]))
|
self.parentFrame.menuItemsById[self.canvasTool.attrList[self.lastPanelState["currentToolIdx"]]["id"]].Check(True)
|
||||||
if ("operator" in self.lastPanelState) \
|
toolBar = self.parentFrame.toolBarItemsById[self.canvasTool.attrList[self.lastPanelState["currentToolIdx"]]["id"]][0]
|
||||||
and (self.lastPanelState["operator"] != None):
|
toolBar.ToggleTool(self.canvasTool.attrList[self.lastPanelState["currentToolIdx"]]["id"], True); toolBar.Refresh();
|
||||||
|
if (self.lastPanelState["currentTool"] != None) and (self.lastPanelState["currentTool"].__class__ == ToolObject):
|
||||||
|
self.parentFrame.menuItemsById[self.canvasOperator.attrList[4]["id"]].Enable(True)
|
||||||
|
else:
|
||||||
|
self.parentFrame.menuItemsById[self.canvasOperator.attrList[4]["id"]].Enable(False)
|
||||||
|
textItems.append("T: {}".format(self.lastPanelState["currentTool"].name if (self.lastPanelState["currentTool"] != None) else "Cursor"))
|
||||||
|
if ("operator" in self.lastPanelState) and (self.lastPanelState["operator"] != None):
|
||||||
textItems.append("O: {}".format(self.lastPanelState["operator"]))
|
textItems.append("O: {}".format(self.lastPanelState["operator"]))
|
||||||
if "dirty" in self.lastPanelState \
|
if ("dirty" in self.lastPanelState) and self.lastPanelState["dirty"]:
|
||||||
and self.lastPanelState["dirty"]:
|
|
||||||
textItems.append("*")
|
textItems.append("*")
|
||||||
if "backupStatus" in self.lastPanelState \
|
if ("backupStatus" in self.lastPanelState) and (self.lastPanelState["backupStatus"] == True):
|
||||||
and self.lastPanelState["backupStatus"] == True:
|
|
||||||
textItems.append("Saving backup...")
|
textItems.append("Saving backup...")
|
||||||
self.parentFrame.statusBar.SetStatusText(" | ".join(textItems))
|
self.parentFrame.statusBar.SetStatusText(" | ".join(textItems))
|
||||||
if ("undoInhibit" in self.lastPanelState) \
|
if "undoLevel" in self.lastPanelState:
|
||||||
and (self.lastPanelState["undoInhibit"]):
|
|
||||||
for item in (self.canvasRedo, self.canvasUndo):
|
|
||||||
self.parentFrame.menuItemsById[item.attrDict["id"]].Enable(False)
|
|
||||||
toolBar = self.parentFrame.toolBarItemsById[item.attrDict["id"]][0]
|
|
||||||
toolBar.EnableTool(item.attrDict["id"], False); toolBar.Refresh();
|
|
||||||
elif "undoLevel" in self.lastPanelState:
|
|
||||||
if (self.lastPanelState["undoLevel"] >= 0) \
|
if (self.lastPanelState["undoLevel"] >= 0) \
|
||||||
and (self.lastPanelState["undoLevel"] < (len(self.parentCanvas.canvas.journal.patchesUndo) - 1)):
|
and (self.lastPanelState["undoLevel"] < (len(self.parentCanvas.canvas.patchesUndo) - 1)):
|
||||||
self.parentFrame.menuItemsById[self.canvasUndo.attrDict["id"]].Enable(True)
|
self.parentFrame.menuItemsById[self.canvasUndo.attrDict["id"]].Enable(True)
|
||||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasUndo.attrDict["id"]][0]
|
toolBar = self.parentFrame.toolBarItemsById[self.canvasUndo.attrDict["id"]][0]
|
||||||
toolBar.EnableTool(self.canvasUndo.attrDict["id"], True); toolBar.Refresh();
|
toolBar.EnableTool(self.canvasUndo.attrDict["id"], True); toolBar.Refresh();
|
||||||
@ -109,45 +163,8 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||||||
toolBar.EnableTool(self.canvasRedo.attrDict["id"], False); toolBar.Refresh();
|
toolBar.EnableTool(self.canvasRedo.attrDict["id"], False); toolBar.Refresh();
|
||||||
|
|
||||||
def __init__(self, parentCanvas, parentFrame):
|
def __init__(self, parentCanvas, parentFrame):
|
||||||
accels, menus, toolBars = [], [], []
|
[classObject.__init__(self) for classObject in self.__class__.__bases__]
|
||||||
|
self._initColourBitmaps(); self.accels, self.menus, self.toolBars = self._initInterface();
|
||||||
self.canvasPathName, self.lastPanelState, self.parentCanvas, self.parentFrame = None, {}, parentCanvas, parentFrame
|
self.canvasPathName, self.lastPanelState, self.parentCanvas, self.parentFrame = None, {}, parentCanvas, parentFrame
|
||||||
for classObject in self.__class__.__bases__:
|
|
||||||
classObject.__init__(self)
|
|
||||||
if len(self.accels):
|
|
||||||
accels += self.accels
|
|
||||||
if len(self.menus):
|
|
||||||
menus += self.menus
|
|
||||||
if len(self.toolBars):
|
|
||||||
toolBars += self.toolBars
|
|
||||||
self._initColourBitmaps()
|
|
||||||
|
|
||||||
toolBars.append(
|
|
||||||
[self.canvasNew, self.canvasOpen, self.canvasSave, self.canvasSaveAs, NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasUndo, self.canvasRedo, NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasCut, self.canvasCopy, self.canvasPaste, self.canvasDelete, NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasAssetsWindowHide, self.canvasAssetsWindowShow, NID_TOOLBAR_HSEP,
|
|
||||||
])
|
|
||||||
toolBars.append(
|
|
||||||
[self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6),
|
|
||||||
])
|
|
||||||
toolBars.append(
|
|
||||||
[self.canvasColour(self.canvasColour, 0), self.canvasColour(self.canvasColour, 1), self.canvasColour(self.canvasColour, 2), self.canvasColour(self.canvasColour, 3),
|
|
||||||
self.canvasColour(self.canvasColour, 4), self.canvasColour(self.canvasColour, 5), self.canvasColour(self.canvasColour, 6), self.canvasColour(self.canvasColour, 7),
|
|
||||||
self.canvasColour(self.canvasColour, 8), self.canvasColour(self.canvasColour, 9), self.canvasColour(self.canvasColour, 10), self.canvasColour(self.canvasColour, 11),
|
|
||||||
self.canvasColour(self.canvasColour, 12), self.canvasColour(self.canvasColour, 13), self.canvasColour(self.canvasColour, 14), self.canvasColour(self.canvasColour, 15),
|
|
||||||
self.canvasColourAlpha(self.canvasColourAlpha, 0), self.canvasColoursFlip, NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasBrushSize(self.canvasBrushSize, 1, True), self.canvasBrushSize(self.canvasBrushSize, 1, False), self.canvasBrushSize(self.canvasBrushSize, 0, True), self.canvasBrushSize(self.canvasBrushSize, 0, False), NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasBrushSize(self.canvasBrushSize, 2, True), self.canvasBrushSize(self.canvasBrushSize, 2, False),
|
|
||||||
])
|
|
||||||
toolBars.append(
|
|
||||||
[self.canvasColourBackground(self.canvasColourBackground, 0), self.canvasColourBackground(self.canvasColourBackground, 1), self.canvasColourBackground(self.canvasColourBackground, 2), self.canvasColourBackground(self.canvasColourBackground, 3),
|
|
||||||
self.canvasColourBackground(self.canvasColourBackground, 4), self.canvasColourBackground(self.canvasColourBackground, 5), self.canvasColourBackground(self.canvasColourBackground, 6), self.canvasColourBackground(self.canvasColourBackground, 7),
|
|
||||||
self.canvasColourBackground(self.canvasColourBackground, 8), self.canvasColourBackground(self.canvasColourBackground, 9), self.canvasColourBackground(self.canvasColourBackground, 10), self.canvasColourBackground(self.canvasColourBackground, 11),
|
|
||||||
self.canvasColourBackground(self.canvasColourBackground, 12), self.canvasColourBackground(self.canvasColourBackground, 13), self.canvasColourBackground(self.canvasColourBackground, 14), self.canvasColourBackground(self.canvasColourBackground, 15),
|
|
||||||
self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0), self.canvasColoursFlip, NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasCanvasSize(self.canvasCanvasSize, 1, True), self.canvasCanvasSize(self.canvasCanvasSize, 1, False), self.canvasCanvasSize(self.canvasCanvasSize, 0, True), self.canvasCanvasSize(self.canvasCanvasSize, 0, False), NID_TOOLBAR_HSEP,
|
|
||||||
self.canvasCanvasSize(self.canvasCanvasSize, 2, True), self.canvasCanvasSize(self.canvasCanvasSize, 2, False),
|
|
||||||
])
|
|
||||||
self.accels, self.menus, self.toolBars = accels, menus, toolBars
|
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
#
|
#
|
||||||
|
|
||||||
from GuiFrame import GuiCommandDecorator, GuiCommandListDecorator, GuiSelectDecorator, NID_MENU_SEP
|
from GuiFrame import GuiCommandDecorator, GuiCommandListDecorator, GuiSelectDecorator
|
||||||
import wx
|
import wx
|
||||||
|
|
||||||
class RoarCanvasCommandsEdit():
|
class RoarCanvasCommandsEdit():
|
||||||
@ -194,31 +194,10 @@ class RoarCanvasCommandsEdit():
|
|||||||
|
|
||||||
@GuiCommandDecorator("Redo", "&Redo", ["", wx.ART_REDO], [wx.ACCEL_CTRL, ord("Y")], False)
|
@GuiCommandDecorator("Redo", "&Redo", ["", wx.ART_REDO], [wx.ACCEL_CTRL, ord("Y")], False)
|
||||||
def canvasRedo(self, event):
|
def canvasRedo(self, event):
|
||||||
self.parentCanvas.undo(redo=True); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.journal.patchesUndoLevel);
|
self.parentCanvas.undo(redo=True); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.patchesUndoLevel);
|
||||||
|
|
||||||
@GuiCommandDecorator("Undo", "&Undo", ["", wx.ART_UNDO], [wx.ACCEL_CTRL, ord("Z")], False)
|
@GuiCommandDecorator("Undo", "&Undo", ["", wx.ART_UNDO], [wx.ACCEL_CTRL, ord("Z")], False)
|
||||||
def canvasUndo(self, event):
|
def canvasUndo(self, event):
|
||||||
self.parentCanvas.undo(); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.journal.patchesUndoLevel);
|
self.parentCanvas.undo(); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.patchesUndoLevel);
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.accels = (
|
|
||||||
(self.canvasColourBackground(self.canvasColourBackground, 0), self.canvasColourBackground(self.canvasColourBackground, 1), self.canvasColourBackground(self.canvasColourBackground, 2), self.canvasColourBackground(self.canvasColourBackground, 3), self.canvasColourBackground(self.canvasColourBackground, 4), self.canvasColourBackground(self.canvasColourBackground, 5), self.canvasColourBackground(self.canvasColourBackground, 6), self.canvasColourBackground(self.canvasColourBackground, 7), self.canvasColourBackground(self.canvasColourBackground, 8), self.canvasColourBackground(self.canvasColourBackground, 9), self.canvasColourBackground(self.canvasColourBackground, 10), self.canvasColourBackground(self.canvasColourBackground, 11), self.canvasColourBackground(self.canvasColourBackground, 12), self.canvasColourBackground(self.canvasColourBackground, 13), self.canvasColourBackground(self.canvasColourBackground, 14), self.canvasColourBackground(self.canvasColourBackground, 15), self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0),),
|
|
||||||
)
|
|
||||||
self.menus = (
|
|
||||||
("&Edit",
|
|
||||||
self.canvasUndo, self.canvasRedo, NID_MENU_SEP,
|
|
||||||
self.canvasCut, self.canvasCopy, self.canvasPaste,
|
|
||||||
self.canvasDelete, NID_MENU_SEP,
|
|
||||||
("Brush size", self.canvasBrushSize(self.canvasBrushSize, 0, True), self.canvasBrushSize(self.canvasBrushSize, 0, False), self.canvasBrushSize(self.canvasBrushSize, 1, True), self.canvasBrushSize(self.canvasBrushSize, 1, False), NID_MENU_SEP,
|
|
||||||
self.canvasBrushSize(self.canvasBrushSize, 2, True), self.canvasBrushSize(self.canvasBrushSize, 2, False),),
|
|
||||||
("Canvas size", self.canvasCanvasSize(self.canvasCanvasSize, 1, True), self.canvasCanvasSize(self.canvasCanvasSize, 1, False), self.canvasCanvasSize(self.canvasCanvasSize, 0, True), self.canvasCanvasSize(self.canvasCanvasSize, 0, False), NID_MENU_SEP,
|
|
||||||
self.canvasCanvasSize(self.canvasCanvasSize, 2, True), self.canvasCanvasSize(self.canvasCanvasSize, 2, False),),
|
|
||||||
self.canvasColoursFlip,
|
|
||||||
NID_MENU_SEP,
|
|
||||||
self.canvasBrush(self.canvasBrush, 0), NID_MENU_SEP,
|
|
||||||
self.canvasAssetsWindowHide, self.canvasAssetsWindowShow,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.toolBars = ()
|
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -5,14 +5,12 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from ImgurApiKey import ImgurApiKey
|
from ImgurApiKey import ImgurApiKey; haveImgurApiKey = True;
|
||||||
haveImgurApiKey = True
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
haveImgurApiKey = False
|
haveImgurApiKey = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import base64, json, requests, urllib.request
|
import base64, json, requests, urllib.request; haveUrllib = True;
|
||||||
haveUrllib = True
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
haveUrllib = False
|
haveUrllib = False
|
||||||
|
|
||||||
@ -35,8 +33,7 @@ class RoarCanvasCommandsFile():
|
|||||||
self.canvasPathName = None
|
self.canvasPathName = None
|
||||||
self.parentCanvas._snapshotsReset()
|
self.parentCanvas._snapshotsReset()
|
||||||
self.update(dirty=self.parentCanvas.dirty, pathName=self.canvasPathName, undoLevel=-1)
|
self.update(dirty=self.parentCanvas.dirty, pathName=self.canvasPathName, undoLevel=-1)
|
||||||
self.parentCanvas.canvas.journal.resetCursor()
|
self.parentCanvas.canvas.resetCursor(); self.parentCanvas.canvas.resetUndo();
|
||||||
self.parentCanvas.canvas.journal.resetUndo()
|
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
rc, error, newMap, newPathName, newSize = False, str(e), None, None, None
|
rc, error, newMap, newPathName, newSize = False, str(e), None, None, None
|
||||||
if not rc:
|
if not rc:
|
||||||
@ -52,28 +49,10 @@ class RoarCanvasCommandsFile():
|
|||||||
if dialog.ShowModal() == wx.ID_CANCEL:
|
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||||
return False, None
|
return False, None
|
||||||
elif self._promptSaveChanges():
|
elif self._promptSaveChanges():
|
||||||
pathName = dialog.GetPath(); self.lastDir = os.path.dirname(pathName); self._storeLastDir(self.lastDir);
|
pathName = dialog.GetPath(); self.lastDir = os.path.dirname(pathName); self._recentDirSave(self.lastDir);
|
||||||
return self._import(f, newDirty, pathName, emptyPathName=emptyPathName)
|
return self._import(f, newDirty, pathName, emptyPathName=emptyPathName)
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
def _loadLastDir(self):
|
|
||||||
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
|
||||||
if os.path.exists(localConfFileName):
|
|
||||||
with open(localConfFileName, "r", encoding="utf-8") as inFile:
|
|
||||||
self.lastDir = inFile.read().rstrip("\r\n")
|
|
||||||
|
|
||||||
def _loadRecent(self):
|
|
||||||
localConfFileName = getLocalConfPathName("Recent.lst")
|
|
||||||
if os.path.exists(localConfFileName):
|
|
||||||
with open(localConfFileName, "r", encoding="utf-8") as inFile:
|
|
||||||
for lastFile in inFile.readlines():
|
|
||||||
self._pushRecent(lastFile.rstrip("\r\n"), False)
|
|
||||||
|
|
||||||
def _popSnapshot(self, pathName):
|
|
||||||
if pathName in self.snapshots.keys():
|
|
||||||
self.canvasRestore.attrDict["menu"].Delete(self.snapshots[pathName]["menuItemId"])
|
|
||||||
del self.snapshots[pathName]
|
|
||||||
|
|
||||||
def _promptSaveChanges(self):
|
def _promptSaveChanges(self):
|
||||||
if self.parentCanvas.dirty:
|
if self.parentCanvas.dirty:
|
||||||
message = "Do you want to save changes to {}?".format(self.canvasPathName if self.canvasPathName != None else "(Untitled)")
|
message = "Do you want to save changes to {}?".format(self.canvasPathName if self.canvasPathName != None else "(Untitled)")
|
||||||
@ -90,7 +69,25 @@ class RoarCanvasCommandsFile():
|
|||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _pushRecent(self, pathName, serialise=True):
|
def _recentDirLoad(self):
|
||||||
|
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
||||||
|
if os.path.exists(localConfFileName):
|
||||||
|
with open(localConfFileName, "r", encoding="utf-8") as inFile:
|
||||||
|
self.lastDir = inFile.read().rstrip("\r\n")
|
||||||
|
|
||||||
|
def _recentDirSave(self, pathName):
|
||||||
|
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
||||||
|
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
||||||
|
print(pathName, file=outFile)
|
||||||
|
|
||||||
|
def _recentLoad(self):
|
||||||
|
localConfFileName = getLocalConfPathName("Recent.lst")
|
||||||
|
if os.path.exists(localConfFileName):
|
||||||
|
with open(localConfFileName, "r", encoding="utf-8") as inFile:
|
||||||
|
for lastFile in inFile.readlines():
|
||||||
|
self._recentPush(lastFile.rstrip("\r\n"), False)
|
||||||
|
|
||||||
|
def _recentPush(self, pathName, serialise=True):
|
||||||
menuItemId = wx.NewId()
|
menuItemId = wx.NewId()
|
||||||
if not pathName in [l["pathName"] for l in self.lastFiles]:
|
if not pathName in [l["pathName"] for l in self.lastFiles]:
|
||||||
numLastFiles = len(self.lastFiles) if self.lastFiles != None else 0
|
numLastFiles = len(self.lastFiles) if self.lastFiles != None else 0
|
||||||
@ -102,9 +99,20 @@ class RoarCanvasCommandsFile():
|
|||||||
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasOpenRecent(event, pathName), menuItemWindow)
|
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasOpenRecent(event, pathName), menuItemWindow)
|
||||||
self.lastFiles += [{"menuItemId":menuItemId, "menuItemWindow":menuItemWindow, "pathName":pathName}]
|
self.lastFiles += [{"menuItemId":menuItemId, "menuItemWindow":menuItemWindow, "pathName":pathName}]
|
||||||
if serialise:
|
if serialise:
|
||||||
self._saveRecent()
|
self._recentSave()
|
||||||
|
|
||||||
def _pushSnapshot(self, pathName):
|
def _recentSave(self):
|
||||||
|
localConfFileName = getLocalConfPathName("Recent.lst")
|
||||||
|
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
||||||
|
for lastFile in [l["pathName"] for l in self.lastFiles]:
|
||||||
|
print(lastFile, file=outFile)
|
||||||
|
|
||||||
|
def _snapshotsPop(self, pathName):
|
||||||
|
if pathName in self.snapshots.keys():
|
||||||
|
self.canvasRestore.attrDict["menu"].Delete(self.snapshots[pathName]["menuItemId"])
|
||||||
|
del self.snapshots[pathName]
|
||||||
|
|
||||||
|
def _snapshotsPush(self, pathName):
|
||||||
menuItemId = wx.NewId()
|
menuItemId = wx.NewId()
|
||||||
if not (pathName in self.snapshots.keys()):
|
if not (pathName in self.snapshots.keys()):
|
||||||
label = datetime.datetime.fromtimestamp(os.stat(pathName)[stat.ST_MTIME]).strftime("%c")
|
label = datetime.datetime.fromtimestamp(os.stat(pathName)[stat.ST_MTIME]).strftime("%c")
|
||||||
@ -113,23 +121,12 @@ class RoarCanvasCommandsFile():
|
|||||||
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasRestore(event, pathName), menuItemWindow)
|
self.parentFrame.Bind(wx.EVT_MENU, lambda event: self.canvasRestore(event, pathName), menuItemWindow)
|
||||||
self.snapshots[pathName] = {"menuItemId":menuItemId, "menuItemWindow":menuItemWindow}
|
self.snapshots[pathName] = {"menuItemId":menuItemId, "menuItemWindow":menuItemWindow}
|
||||||
|
|
||||||
def _resetSnapshots(self):
|
def _snapshotsReset(self):
|
||||||
for pathName in list(self.snapshots.keys()):
|
for pathName in list(self.snapshots.keys()):
|
||||||
self._popSnapshot(pathName)
|
self._snapshotsPop(pathName)
|
||||||
if self.canvasRestore.attrDict["id"] in self.parentFrame.menuItemsById:
|
if self.canvasRestore.attrDict["id"] in self.parentFrame.menuItemsById:
|
||||||
self.parentFrame.menuItemsById[self.canvasRestore.attrDict["id"]].Enable(False)
|
self.parentFrame.menuItemsById[self.canvasRestore.attrDict["id"]].Enable(False)
|
||||||
|
|
||||||
def _saveRecent(self):
|
|
||||||
localConfFileName = getLocalConfPathName("Recent.lst")
|
|
||||||
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
|
||||||
for lastFile in [l["pathName"] for l in self.lastFiles]:
|
|
||||||
print(lastFile, file=outFile)
|
|
||||||
|
|
||||||
def _storeLastDir(self, pathName):
|
|
||||||
localConfFileName = getLocalConfPathName("RecentDir.txt")
|
|
||||||
with open(localConfFileName, "w", encoding="utf-8") as outFile:
|
|
||||||
print(pathName, file=outFile)
|
|
||||||
|
|
||||||
@GuiCommandDecorator("Clear list", "&Clear list", None, None, False)
|
@GuiCommandDecorator("Clear list", "&Clear list", None, None, False)
|
||||||
def canvasClearRecent(self, event):
|
def canvasClearRecent(self, event):
|
||||||
if self.lastFiles != None:
|
if self.lastFiles != None:
|
||||||
@ -155,7 +152,7 @@ class RoarCanvasCommandsFile():
|
|||||||
if dialog.ShowModal() == wx.ID_CANCEL:
|
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
outPathName = dialog.GetPath(); self.lastDir = os.path.dirname(outPathName); self._storeLastDir(self.lastDir);
|
outPathName = dialog.GetPath(); self.lastDir = os.path.dirname(outPathName); self._recentDirSave(self.lastDir);
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||||
with open(outPathName, "w", encoding="utf-8") as outFile:
|
with open(outPathName, "w", encoding="utf-8") as outFile:
|
||||||
self.parentCanvas.canvas.exportStore.exportAnsiFile(self.parentCanvas.canvas.map, self.parentCanvas.canvas.size, outFile)
|
self.parentCanvas.canvas.exportStore.exportAnsiFile(self.parentCanvas.canvas.map, self.parentCanvas.canvas.size, outFile)
|
||||||
@ -170,30 +167,20 @@ class RoarCanvasCommandsFile():
|
|||||||
if dialog.ShowModal() == wx.ID_CANCEL:
|
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
outPathName = dialog.GetPath(); self.lastDir = os.path.dirname(outPathName); self._storeLastDir(self.lastDir);
|
outPathName = dialog.GetPath(); self.lastDir = os.path.dirname(outPathName); self._recentDirSave(self.lastDir);
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
self.parentCanvas.cursorHide()
|
||||||
self.parentCanvas.backend.drawCursorMaskWithJournal(self.parentCanvas.canvas, self.parentCanvas.canvas.journal, eventDc, reset=False)
|
|
||||||
self.parentCanvas.canvas.exportStore.exportBitmapToPngFile(self.parentCanvas.backend.canvasBitmap, outPathName, wx.BITMAP_TYPE_PNG)
|
self.parentCanvas.canvas.exportStore.exportBitmapToPngFile(self.parentCanvas.backend.canvasBitmap, outPathName, wx.BITMAP_TYPE_PNG)
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
self.parentCanvas.cursorShow()
|
||||||
cursorPatches = self.parentCanvas.canvas.journal.popCursor(reset=False)
|
|
||||||
if len(cursorPatches) > 0:
|
|
||||||
self.parentCanvas.backend.drawPatches(self.parentCanvas.canvas, eventDc, cursorPatches, isCursor=True)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@GuiCommandDecorator("Export to Imgur...", "Export to I&mgur...", None, None, haveImgurApiKey and haveUrllib)
|
@GuiCommandDecorator("Export to Imgur...", "Export to I&mgur...", None, None, haveImgurApiKey and haveUrllib)
|
||||||
def canvasExportImgur(self, event):
|
def canvasExportImgur(self, event):
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
self.parentCanvas.cursorHide()
|
||||||
self.parentCanvas.backend.drawCursorMaskWithJournal(self.parentCanvas.canvas, self.parentCanvas.canvas.journal, eventDc, reset=False)
|
|
||||||
rc, status, result = self.parentCanvas.canvas.exportStore.exportBitmapToImgur(self.imgurApiKey, self.parentCanvas.backend.canvasBitmap, "", "", wx.BITMAP_TYPE_PNG)
|
rc, status, result = self.parentCanvas.canvas.exportStore.exportBitmapToImgur(self.imgurApiKey, self.parentCanvas.backend.canvasBitmap, "", "", wx.BITMAP_TYPE_PNG)
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
self.parentCanvas.cursorShow()
|
||||||
cursorPatches = self.parentCanvas.canvas.journal.popCursor(reset=False)
|
|
||||||
if len(cursorPatches) > 0:
|
|
||||||
self.parentCanvas.backend.drawPatches(self.parentCanvas.canvas, eventDc, cursorPatches, isCursor=True)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
||||||
if rc:
|
if rc:
|
||||||
if not wx.TheClipboard.IsOpened():
|
if not wx.TheClipboard.IsOpened():
|
||||||
@ -261,7 +248,7 @@ class RoarCanvasCommandsFile():
|
|||||||
nonlocal newCanvasSize
|
nonlocal newCanvasSize
|
||||||
if newCanvasSize == None:
|
if newCanvasSize == None:
|
||||||
newCanvasSize = list(self.parentCanvas.canvas.size)
|
newCanvasSize = list(self.parentCanvas.canvas.size)
|
||||||
newMap = [[[-1, -1, 0, " "] for x in range(newCanvasSize[0])] for y in range(newCanvasSize[1])]
|
newMap = [[[*self.parentCanvas.brushColours, 0, " "] for x in range(newCanvasSize[0])] for y in range(newCanvasSize[1])]
|
||||||
return (True, "", newMap, None, newCanvasSize)
|
return (True, "", newMap, None, newCanvasSize)
|
||||||
if self._promptSaveChanges():
|
if self._promptSaveChanges():
|
||||||
self._import(canvasImportEmpty, False, None)
|
self._import(canvasImportEmpty, False, None)
|
||||||
@ -273,7 +260,7 @@ class RoarCanvasCommandsFile():
|
|||||||
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
return (rc, error, self.parentCanvas.canvas.importStore.outMap, pathName, self.parentCanvas.canvas.importStore.inSize)
|
||||||
rc, newPathName = self._importFile(canvasImportmIRC, False, "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*")
|
rc, newPathName = self._importFile(canvasImportmIRC, False, "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*")
|
||||||
if rc:
|
if rc:
|
||||||
self._pushRecent(newPathName)
|
self._recentPush(newPathName)
|
||||||
|
|
||||||
@GuiSubMenuDecorator("Open Recent", "Open &Recent", None, None, False)
|
@GuiSubMenuDecorator("Open Recent", "Open &Recent", None, None, False)
|
||||||
def canvasOpenRecent(self, event, pathName=None):
|
def canvasOpenRecent(self, event, pathName=None):
|
||||||
@ -285,7 +272,7 @@ class RoarCanvasCommandsFile():
|
|||||||
if not rc:
|
if not rc:
|
||||||
numLastFile = [i for i in range(len(self.lastFiles)) if self.lastFiles[i]["pathName"] == pathName][0]
|
numLastFile = [i for i in range(len(self.lastFiles)) if self.lastFiles[i]["pathName"] == pathName][0]
|
||||||
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[numLastFile]["menuItemId"]); del self.lastFiles[numLastFile];
|
self.canvasOpenRecent.attrDict["menu"].Delete(self.lastFiles[numLastFile]["menuItemId"]); del self.lastFiles[numLastFile];
|
||||||
self._saveRecent()
|
self._recentSave()
|
||||||
|
|
||||||
@GuiSubMenuDecorator("Restore Snapshot", "Res&tore Snapshot", None, None, False)
|
@GuiSubMenuDecorator("Restore Snapshot", "Res&tore Snapshot", None, None, False)
|
||||||
def canvasRestore(self, event, pathName=None):
|
def canvasRestore(self, event, pathName=None):
|
||||||
@ -328,27 +315,16 @@ class RoarCanvasCommandsFile():
|
|||||||
if dialog.ShowModal() == wx.ID_CANCEL:
|
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.canvasPathName = dialog.GetPath(); self.lastDir = os.path.dirname(self.canvasPathName); self._storeLastDir(self.lastDir);
|
self.canvasPathName = dialog.GetPath(); self.lastDir = os.path.dirname(self.canvasPathName); self._recentDirSave(self.lastDir);
|
||||||
if self.canvasSave(event, newDirty=False):
|
if self.canvasSave(event, newDirty=False):
|
||||||
self.update(pathName=self.canvasPathName)
|
self.update(pathName=self.canvasPathName)
|
||||||
self._pushRecent(self.canvasPathName)
|
self._recentPush(self.canvasPathName)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.imgurApiKey, self.lastFiles, self.lastDir, self.snapshots = ImgurApiKey.imgurApiKey if haveImgurApiKey else None, [], None, {}
|
self.exiting, self.lastFiles, self.lastDir, self.snapshots = False, [], None, {}
|
||||||
self.accels = ()
|
self.imgurApiKey = ImgurApiKey.imgurApiKey if haveImgurApiKey else None
|
||||||
self.menus = (
|
|
||||||
("&File",
|
|
||||||
self.canvasNew, self.canvasOpen, self.canvasOpenRecent, self.canvasRestore, self.canvasSave, self.canvasSaveAs, NID_MENU_SEP,
|
|
||||||
("&Export...", self.canvasExportAsAnsi, self.canvasExportToClipboard, self.canvasExportImgur, self.canvasExportPastebin, self.canvasExportAsPng,),
|
|
||||||
("&Import...", self.canvasImportAnsi, self.canvasImportFromClipboard, self.canvasImportSauce,),
|
|
||||||
NID_MENU_SEP,
|
|
||||||
self.canvasExit,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.toolBars = ()
|
|
||||||
self.exiting = False
|
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
#
|
#
|
||||||
|
|
||||||
from GuiFrame import GuiCommandDecorator, NID_MENU_SEP
|
from GuiFrame import GuiCommandDecorator
|
||||||
from RoarWindowAbout import RoarWindowAbout
|
from RoarWindowAbout import RoarWindowAbout
|
||||||
from RoarWindowMelp import RoarWindowMelp
|
from RoarWindowMelp import RoarWindowMelp
|
||||||
import webbrowser, wx
|
import webbrowser, wx
|
||||||
@ -26,8 +26,4 @@ class RoarCanvasCommandsHelp():
|
|||||||
def canvasVisitGitHub(self, event):
|
def canvasVisitGitHub(self, event):
|
||||||
webbrowser.open("https://www.github.com/lalbornoz/roar")
|
webbrowser.open("https://www.github.com/lalbornoz/roar")
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.accels = ()
|
|
||||||
self.menus, self.toolBars = (("&Help", self.canvasMelp, NID_MENU_SEP, self.canvasNewIssueGitHub, self.canvasVisitGitHub, NID_MENU_SEP, self.canvasAbout,),), ()
|
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -4,14 +4,13 @@
|
|||||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from GuiFrame import GuiCommandListDecorator
|
||||||
from OperatorFlipHorizontal import OperatorFlipHorizontal
|
from OperatorFlipHorizontal import OperatorFlipHorizontal
|
||||||
from OperatorFlipVertical import OperatorFlipVertical
|
from OperatorFlipVertical import OperatorFlipVertical
|
||||||
from OperatorInvert import OperatorInvert
|
from OperatorInvert import OperatorInvert
|
||||||
from OperatorRotate import OperatorRotate
|
from OperatorRotate import OperatorRotate
|
||||||
from OperatorTile import OperatorTile
|
from OperatorTile import OperatorTile
|
||||||
from GuiFrame import GuiCommandListDecorator
|
|
||||||
from ToolObject import ToolObject
|
from ToolObject import ToolObject
|
||||||
import copy, wx
|
|
||||||
|
|
||||||
class RoarCanvasCommandsOperators():
|
class RoarCanvasCommandsOperators():
|
||||||
@GuiCommandListDecorator(0, "Flip", "&Flip", None, None, None)
|
@GuiCommandListDecorator(0, "Flip", "&Flip", None, None, None)
|
||||||
@ -28,13 +27,6 @@ class RoarCanvasCommandsOperators():
|
|||||||
return canvasOperator_
|
return canvasOperator_
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.accels = ()
|
|
||||||
self.menus = (
|
|
||||||
("&Operators",
|
|
||||||
self.canvasOperator(self.canvasOperator, 0), self.canvasOperator(self.canvasOperator, 1), self.canvasOperator(self.canvasOperator, 2), self.canvasOperator(self.canvasOperator, 3), self.canvasOperator(self.canvasOperator, 4),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.toolBars = ()
|
|
||||||
self.currentOperator, self.operatorState = None, None
|
self.currentOperator, self.operatorState = None, None
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -27,40 +27,21 @@ class RoarCanvasCommandsTools():
|
|||||||
@GuiSelectDecorator(8, "Text", "&Text", ["toolText.png"], [wx.MOD_NONE, wx.WXK_F7], False)
|
@GuiSelectDecorator(8, "Text", "&Text", ["toolText.png"], [wx.MOD_NONE, wx.WXK_F7], False)
|
||||||
def canvasTool(self, f, idx):
|
def canvasTool(self, f, idx):
|
||||||
def canvasTool_(event):
|
def canvasTool_(event):
|
||||||
if (self.currentTool.__class__ == ToolObject) \
|
if (self.currentTool.__class__ == ToolObject) \
|
||||||
and (self.currentTool.toolState > self.currentTool.TS_NONE) \
|
and (self.currentTool.toolState > self.currentTool.TS_NONE) \
|
||||||
and self.currentTool.external:
|
and self.currentTool.external:
|
||||||
self.parentCanvas.dropTarget.done()
|
self.parentCanvas.dropTarget.done()
|
||||||
self.lastTool, self.currentTool = self.currentTool, [ToolCircle, None, ToolErase, ToolFill, ToolLine, ToolObject, ToolPickColour, ToolRect, ToolText][idx]
|
self.lastTool, self.currentTool = self.currentTool, [ToolCircle, None, ToolErase, ToolFill, ToolLine, ToolObject, ToolPickColour, ToolRect, ToolText][idx]
|
||||||
if self.currentTool != None:
|
if self.currentTool != None:
|
||||||
self.currentTool = self.currentTool()
|
self.currentTool = self.currentTool()
|
||||||
self.currentOperator, self.operatorState = None, None
|
self.currentOperator, self.operatorState = None, None
|
||||||
self.parentFrame.menuItemsById[self.canvasTool.attrList[idx]["id"]].Check(True)
|
self.update(currentTool=self.currentTool, currentToolIdx=idx, operator=None)
|
||||||
if self.currentTool.__class__ == ToolObject:
|
self.parentCanvas.applyTool(None, True, None, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, None, force=True)
|
||||||
self.parentFrame.menuItemsById[self.canvasOperator.attrList[4]["id"]].Enable(True)
|
|
||||||
else:
|
|
||||||
self.parentFrame.menuItemsById[self.canvasOperator.attrList[4]["id"]].Enable(False)
|
|
||||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasTool.attrList[idx]["id"]][0]
|
|
||||||
toolBar.ToggleTool(self.canvasTool.attrList[idx]["id"], True); toolBar.Refresh();
|
|
||||||
if self.currentTool != None:
|
|
||||||
self.update(operator=None, toolName=self.currentTool.name)
|
|
||||||
else:
|
|
||||||
self.update(operator=None, toolName="Cursor")
|
|
||||||
viewRect = self.parentCanvas.GetViewStart()
|
|
||||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas, viewRect)
|
|
||||||
self.parentCanvas.applyTool(eventDc, True, None, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, viewRect, force=True)
|
|
||||||
setattr(canvasTool_, "attrDict", f.attrList[idx])
|
setattr(canvasTool_, "attrDict", f.attrList[idx])
|
||||||
setattr(canvasTool_, "isSelect", True)
|
setattr(canvasTool_, "isSelect", True)
|
||||||
return canvasTool_
|
return canvasTool_
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.accels = ()
|
|
||||||
self.menus = (
|
|
||||||
("&Tools",
|
|
||||||
self.canvasTool(self.canvasTool, 1), self.canvasTool(self.canvasTool, 7), self.canvasTool(self.canvasTool, 0), self.canvasTool(self.canvasTool, 3), self.canvasTool(self.canvasTool, 4), self.canvasTool(self.canvasTool, 8), self.canvasTool(self.canvasTool, 5), self.canvasTool(self.canvasTool, 2), self.canvasTool(self.canvasTool, 6),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
self.toolBars = ()
|
|
||||||
self.currentTool, self.lastTool = None, None
|
self.currentTool, self.lastTool = None, None
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||||
|
@ -9,7 +9,7 @@ from Rtl import natural_sort
|
|||||||
from RtlPlatform import getLocalConfPathName
|
from RtlPlatform import getLocalConfPathName
|
||||||
from ToolObject import ToolObject
|
from ToolObject import ToolObject
|
||||||
from ToolText import ToolText
|
from ToolText import ToolText
|
||||||
import copy, hashlib, json, os, re, time, wx, sys
|
import copy, hashlib, json, os, pdb, re, time, wx, sys
|
||||||
|
|
||||||
class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
||||||
def done(self):
|
def done(self):
|
||||||
@ -27,8 +27,8 @@ class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
|||||||
viewRect = self.parent.GetViewStart(); mapPoint = [m + n for m, n in zip((mapX, mapY), viewRect)];
|
viewRect = self.parent.GetViewStart(); mapPoint = [m + n for m, n in zip((mapX, mapY), viewRect)];
|
||||||
self.parent.commands.lastTool, self.parent.commands.currentTool = self.parent.commands.currentTool, ToolObject()
|
self.parent.commands.lastTool, self.parent.commands.currentTool = self.parent.commands.currentTool, ToolObject()
|
||||||
self.parent.commands.currentTool.setRegion(self.parent.canvas, mapPoint, dropMap, dropSize, external=True)
|
self.parent.commands.currentTool.setRegion(self.parent.canvas, mapPoint, dropMap, dropSize, external=True)
|
||||||
self.parent.parentFrame.menuItemsById[self.parent.commands.canvasOperator.attrList[4]["id"]].Enable(True)
|
self.parent.parent.menuItemsById[self.parent.commands.canvasOperator.attrList[4]["id"]].Enable(True)
|
||||||
self.parent.commands.update(toolName=self.parent.commands.currentTool.name)
|
self.parent.commands.update(currentTool=self.parent.commands.currentTool, currentToolIdx=5)
|
||||||
eventDc = self.parent.backend.getDeviceContext(self.parent.GetClientSize(), self.parent, viewRect)
|
eventDc = self.parent.backend.getDeviceContext(self.parent.GetClientSize(), self.parent, viewRect)
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||||
self.parent.applyTool(eventDc, True, None, None, None, self.parent.brushPos, False, False, False, self.parent.commands.currentTool, viewRect)
|
self.parent.applyTool(eventDc, True, None, None, None, self.parent.brushPos, False, False, False, self.parent.commands.currentTool, viewRect)
|
||||||
@ -43,45 +43,34 @@ class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
|||||||
super().__init__(); self.inProgress, self.parent = False, parent;
|
super().__init__(); self.inProgress, self.parent = False, parent;
|
||||||
|
|
||||||
class RoarCanvasWindow(GuiWindow):
|
class RoarCanvasWindow(GuiWindow):
|
||||||
def _applyPatches(self, eventDc, patches, patchesCursor, rc):
|
def _applyPatches(self, eventDc, patches, patchesCursor, rc, commitUndo=True, dirty=True, eventDcResetOrigin=True, hideCursor=True):
|
||||||
if rc:
|
if rc:
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
if eventDc == None:
|
||||||
if ((patches != None) and (len(patches) > 0)) \
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
||||||
or ((patchesCursor != None) and (len(patchesCursor) > 0)):
|
if eventDcResetOrigin:
|
||||||
self.backend.drawCursorMaskWithJournal(self.canvas, self.canvas.journal, eventDc)
|
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||||
|
if hideCursor and (((patches != None) and (len(patches) > 0)) or ((patchesCursor != None) and (len(patchesCursor) > 0))):
|
||||||
|
self.cursorHide(eventDc, False, True)
|
||||||
if (patches != None) and (len(patches) > 0):
|
if (patches != None) and (len(patches) > 0):
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
||||||
self.dirty = True if not self.dirty else self.dirty;
|
if dirty and not self.dirty:
|
||||||
self.canvas.journal.begin()
|
self.dirty = True
|
||||||
|
if commitUndo:
|
||||||
|
self.canvas.begin()
|
||||||
for patch in patches if patches != None else []:
|
for patch in patches if patches != None else []:
|
||||||
self.canvas.applyPatch(patch, commitUndo=True)
|
self.canvas.applyPatch(patch, commitUndo=commitUndo)
|
||||||
self.canvas.journal.end()
|
if commitUndo:
|
||||||
if patchesCursor != None:
|
self.canvas.end()
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patchesCursor, isCursor=True)
|
if hideCursor and (patchesCursor != None):
|
||||||
if len(patchesCursor) > 0:
|
self.cursorShow(eventDc, False, patchesCursor=patchesCursor)
|
||||||
self.canvas.journal.pushCursor(patchesCursor)
|
if eventDcResetOrigin:
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
self.commands.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
|
self.commands.update(cellPos=self.brushPos, dirty=self.dirty, undoLevel=self.canvas.patchesUndoLevel)
|
||||||
|
return eventDc
|
||||||
def _eraseBackground(self, eventDc):
|
|
||||||
viewRect = self.GetViewStart()
|
|
||||||
canvasSize, panelSize = [a * b for a, b in zip(self.backend.canvasSize, self.backend.cellSize)], self.GetSize()
|
|
||||||
if viewRect != (0, 0):
|
|
||||||
viewRect = [a * b for a, b in zip(self.backend.cellSize, viewRect)]
|
|
||||||
canvasSize = [a - b for a, b in zip(canvasSize, viewRect)]
|
|
||||||
rectangles, pens, brushes = [], [], []
|
|
||||||
if panelSize[0] > canvasSize[0]:
|
|
||||||
brushes += [self.bgBrush]; pens += [self.bgPen];
|
|
||||||
rectangles += [[canvasSize[0], 0, panelSize[0] - canvasSize[0], panelSize[1]]]
|
|
||||||
if panelSize[1] > canvasSize[1]:
|
|
||||||
brushes += [self.bgBrush]; pens += [self.bgPen];
|
|
||||||
rectangles += [[0, canvasSize[1], panelSize[0], panelSize[1] - canvasSize[1]]]
|
|
||||||
if len(rectangles) > 0:
|
|
||||||
eventDc.DrawRectangleList(rectangles, pens, brushes)
|
|
||||||
|
|
||||||
def _snapshotsReset(self):
|
def _snapshotsReset(self):
|
||||||
self._snapshotFiles, self._snapshotsUpdateLast = [], time.time()
|
self._snapshotFiles, self._snapshotsUpdateLast = [], time.time()
|
||||||
self.commands._resetSnapshots()
|
self.commands._snapshotsReset()
|
||||||
if self.commands.canvasPathName != None:
|
if self.commands.canvasPathName != None:
|
||||||
canvasPathName = os.path.abspath(self.commands.canvasPathName)
|
canvasPathName = os.path.abspath(self.commands.canvasPathName)
|
||||||
canvasFileName = os.path.basename(canvasPathName)
|
canvasFileName = os.path.basename(canvasPathName)
|
||||||
@ -90,7 +79,7 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
if os.path.exists(self._snapshotsDirName):
|
if os.path.exists(self._snapshotsDirName):
|
||||||
for snapshotFile in natural_sort([f for f in os.listdir(self._snapshotsDirName) \
|
for snapshotFile in natural_sort([f for f in os.listdir(self._snapshotsDirName) \
|
||||||
if (re.match(r'snapshot\d+\.txt$', f)) and os.path.isfile(os.path.join(self._snapshotsDirName, f))]):
|
if (re.match(r'snapshot\d+\.txt$', f)) and os.path.isfile(os.path.join(self._snapshotsDirName, f))]):
|
||||||
self.commands._pushSnapshot(os.path.join(self._snapshotsDirName, snapshotFile))
|
self.commands._snapshotsPush(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||||
else:
|
else:
|
||||||
self._snapshotsDirName = None
|
self._snapshotsDirName = None
|
||||||
|
|
||||||
@ -115,14 +104,30 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
self.SetCursor(wx.Cursor(wx.NullCursor))
|
self.SetCursor(wx.Cursor(wx.NullCursor))
|
||||||
self.commands.update(snapshotStatus=False); self._snapshotsUpdateLast = time.time();
|
self.commands.update(snapshotStatus=False); self._snapshotsUpdateLast = time.time();
|
||||||
self._snapshotFiles += [os.path.basename(snapshotPathName)];
|
self._snapshotFiles += [os.path.basename(snapshotPathName)];
|
||||||
self.commands._pushSnapshot(snapshotPathName)
|
self.commands._snapshotsPush(snapshotPathName)
|
||||||
if len(self._snapshotFiles) > 72:
|
if len(self._snapshotFiles) > 72:
|
||||||
for snapshotFile in self._snapshotFiles[:len(self._snapshotFiles) - 8]:
|
for snapshotFile in self._snapshotFiles[:len(self._snapshotFiles) - 8]:
|
||||||
self.commands._popSnapshot(os.path.join(self._snapshotsDirName, snapshotFile))
|
self.commands._snapshotsPop(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||||
os.remove(os.path.join(self._snapshotsDirName, snapshotFile)); snapshotsCount -= 1;
|
os.remove(os.path.join(self._snapshotsDirName, snapshotFile)); snapshotsCount -= 1;
|
||||||
except:
|
except:
|
||||||
print("Exception during _snapshotsUpdate(): {}".format(sys.exc_info()[1]))
|
print("Exception during _snapshotsUpdate(): {}".format(sys.exc_info()[1]))
|
||||||
|
|
||||||
|
def _windowEraseBackground(self, eventDc):
|
||||||
|
viewRect = self.GetViewStart()
|
||||||
|
canvasSize, panelSize = [a * b for a, b in zip(self.backend.canvasSize, self.backend.cellSize)], self.GetSize()
|
||||||
|
if viewRect != (0, 0):
|
||||||
|
viewRect = [a * b for a, b in zip(self.backend.cellSize, viewRect)]
|
||||||
|
canvasSize = [a - b for a, b in zip(canvasSize, viewRect)]
|
||||||
|
rectangles, pens, brushes = [], [], []
|
||||||
|
if panelSize[0] > canvasSize[0]:
|
||||||
|
brushes += [self.bgBrush]; pens += [self.bgPen];
|
||||||
|
rectangles += [[canvasSize[0], 0, panelSize[0] - canvasSize[0], panelSize[1]]]
|
||||||
|
if panelSize[1] > canvasSize[1]:
|
||||||
|
brushes += [self.bgBrush]; pens += [self.bgPen];
|
||||||
|
rectangles += [[0, canvasSize[1], panelSize[0], panelSize[1] - canvasSize[1]]]
|
||||||
|
if len(rectangles) > 0:
|
||||||
|
eventDc.DrawRectangleList(rectangles, pens, brushes)
|
||||||
|
|
||||||
def applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect):
|
def applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect):
|
||||||
eventDc, patches, patchesCursor, rc = self.backend.getDeviceContext(self.GetClientSize(), self), None, None, True
|
eventDc, patches, patchesCursor, rc = self.backend.getDeviceContext(self.GetClientSize(), self), None, None, True
|
||||||
if (currentTool.__class__ == ToolObject) and (currentTool.toolState >= currentTool.TS_SELECT):
|
if (currentTool.__class__ == ToolObject) and (currentTool.toolState >= currentTool.TS_SELECT):
|
||||||
@ -157,6 +162,10 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
|
|
||||||
def applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect, force=False):
|
def applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect, force=False):
|
||||||
patches, patchesCursor, rc = None, None, False
|
patches, patchesCursor, rc = None, None, False
|
||||||
|
if viewRect == None:
|
||||||
|
viewRect = self.GetViewStart()
|
||||||
|
if eventDc == None:
|
||||||
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect)
|
||||||
if eventMouse:
|
if eventMouse:
|
||||||
self.lastCellState = None if force else self.lastCellState
|
self.lastCellState = None if force else self.lastCellState
|
||||||
if ((mapPoint[0] < self.canvas.size[0]) and (mapPoint[1] < self.canvas.size[1])) \
|
if ((mapPoint[0] < self.canvas.size[0]) and (mapPoint[1] < self.canvas.size[1])) \
|
||||||
@ -173,75 +182,80 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
elif mapPoint != None:
|
elif mapPoint != None:
|
||||||
rc, patches, patchesCursor = True, None, [[*mapPoint, self.brushColours[0], self.brushColours[0], 0, " "]]
|
rc, patches, patchesCursor = True, None, [[*mapPoint, self.brushColours[0], self.brushColours[0], 0, " "]]
|
||||||
if rc:
|
if rc:
|
||||||
|
for patch in patches if patches != None else []:
|
||||||
|
if ((patch[2] == -1) and (patch[3] == -1)) \
|
||||||
|
and (patch[0] < self.canvas.size[0]) \
|
||||||
|
and (patch[1] < self.canvas.size[1]):
|
||||||
|
patch[2:] = self.canvas.map[patch[1]][patch[0]]
|
||||||
self._applyPatches(eventDc, patches, patchesCursor, rc)
|
self._applyPatches(eventDc, patches, patchesCursor, rc)
|
||||||
if tool.__class__ == ToolObject:
|
if (tool.__class__ == ToolObject) and (tool.external, tool.toolState) == (True, tool.TS_NONE):
|
||||||
if tool.toolState > tool.TS_NONE:
|
self.dropTarget.done(); self.commands.currentTool, self.commands.lastTool = self.commands.lastTool, self.commands.currentTool;
|
||||||
self.commands.update(undoInhibit=True)
|
self.commands.update(currentTool=self.commands.currentTool)
|
||||||
elif tool.toolState == tool.TS_NONE:
|
|
||||||
if tool.external:
|
|
||||||
self.dropTarget.done(); self.commands.currentTool, self.commands.lastTool = self.commands.lastTool, self.commands.currentTool;
|
|
||||||
newToolName = "Cursor" if self.commands.currentTool == None else self.commands.currentTool.name
|
|
||||||
self.commands.update(toolName=newToolName, undoInhibit=False)
|
|
||||||
else:
|
|
||||||
self.commands.update(undoInhibit=False)
|
|
||||||
if (patches != None) and (len(patches) > 0):
|
if (patches != None) and (len(patches) > 0):
|
||||||
self._snapshotsUpdate()
|
self._snapshotsUpdate()
|
||||||
return rc
|
return rc
|
||||||
|
|
||||||
def onKeyboardInput(self, event):
|
def cursorHide(self, eventDc=None, eventDcResetOrigin=True, reset=False):
|
||||||
keyCode, keyModifiers = event.GetKeyCode(), event.GetModifiers()
|
if eventDc == None:
|
||||||
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||||
if (keyCode == wx.WXK_PAUSE) \
|
if eventDcResetOrigin:
|
||||||
and (keyModifiers == wx.MOD_SHIFT):
|
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||||
import pdb; pdb.set_trace()
|
patchesCursor = self.canvas.popCursor(reset=reset); patchesCursor_ = [];
|
||||||
elif keyCode in (wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP):
|
for cursorCell in [p[:2] for p in patchesCursor]:
|
||||||
if keyCode == wx.WXK_DOWN:
|
if (cursorCell[0] < self.canvas.size[0]) and (cursorCell[1] < self.canvas.size[1]):
|
||||||
if self.brushPos[1] < (self.canvas.size[1] - 1):
|
patchesCursor_ += [[*cursorCell, *self.canvas.map[cursorCell[1]][cursorCell[0]]]]
|
||||||
self.brushPos = [self.brushPos[0], self.brushPos[1] + 1]
|
if len(patchesCursor_) > 0:
|
||||||
else:
|
self.backend.drawPatches(self.canvas, eventDc, patchesCursor_, False)
|
||||||
self.brushPos = [self.brushPos[0], 0]
|
if eventDcResetOrigin:
|
||||||
elif keyCode == wx.WXK_LEFT:
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
if self.brushPos[0] > 0:
|
return eventDc
|
||||||
self.brushPos = [self.brushPos[0] - 1, self.brushPos[1]]
|
|
||||||
else:
|
def cursorShow(self, eventDc=None, eventDcResetOrigin=True, patchesCursor=None):
|
||||||
self.brushPos = [self.canvas.size[0] - 1, self.brushPos[1]]
|
if eventDc == None:
|
||||||
elif keyCode == wx.WXK_RIGHT:
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||||
if self.brushPos[0] < (self.canvas.size[0] - 1):
|
if eventDcResetOrigin:
|
||||||
self.brushPos = [self.brushPos[0] + 1, self.brushPos[1]]
|
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||||
else:
|
if patchesCursor == None:
|
||||||
self.brushPos = [0, self.brushPos[1]]
|
patchesCursor = self.canvas.popCursor(reset=False)
|
||||||
elif keyCode == wx.WXK_UP:
|
elif len(patchesCursor) > 0:
|
||||||
if self.brushPos[1] > 0:
|
self.canvas.pushCursor(patchesCursor)
|
||||||
self.brushPos = [self.brushPos[0], self.brushPos[1] - 1]
|
if (patchesCursor != None) and (len(patchesCursor) > 0):
|
||||||
else:
|
self.backend.drawPatches(self.canvas, eventDc, patchesCursor, isCursor=True)
|
||||||
self.brushPos = [self.brushPos[0], self.canvas.size[1] - 1]
|
if eventDcResetOrigin:
|
||||||
self.commands.update(cellPos=self.brushPos)
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
self.applyTool(eventDc, True, None, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
|
|
||||||
elif (chr(event.GetUnicodeKey()) == " ") \
|
|
||||||
and (self.commands.currentTool.__class__ != ToolText):
|
|
||||||
if not self.applyTool(eventDc, True, None, None, event.GetModifiers(), self.brushPos, False, True, False, self.commands.currentTool, viewRect):
|
|
||||||
event.Skip()
|
|
||||||
else:
|
|
||||||
if self.brushPos[0] < (self.canvas.size[0] - 1):
|
|
||||||
self.brushPos = [self.brushPos[0] + 1, self.brushPos[1]]
|
|
||||||
else:
|
|
||||||
self.brushPos = [0, self.brushPos[1]]
|
|
||||||
self.commands.update(cellPos=self.brushPos)
|
|
||||||
self.applyTool(eventDc, True, None, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
|
|
||||||
else:
|
|
||||||
if not self.applyTool(eventDc, False, chr(event.GetUnicodeKey()), keyCode, keyModifiers, None, None, None, None, self.commands.currentTool, viewRect):
|
|
||||||
event.Skip()
|
|
||||||
|
|
||||||
def onEnterWindow(self, event):
|
def onEnterWindow(self, event):
|
||||||
self.lastCellState = None
|
self.lastCellState = None
|
||||||
|
|
||||||
def onErase(self, event):
|
def onKeyboardInput(self, event):
|
||||||
pass
|
keyCode, keyModifiers = event.GetKeyCode(), event.GetModifiers()
|
||||||
|
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
|
||||||
|
if (keyCode, keyModifiers,) == (wx.WXK_PAUSE, wx.MOD_SHIFT,):
|
||||||
|
pdb.set_trace()
|
||||||
|
elif keyCode in (wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP):
|
||||||
|
if keyCode == wx.WXK_DOWN:
|
||||||
|
self.brushPos[1] = (self.brushPos[1] + 1) % self.canvas.size[1]
|
||||||
|
elif keyCode == wx.WXK_LEFT:
|
||||||
|
self.brushPos[0] = (self.brushPos[0] - 1) if (self.brushPos[0] > 0) else (self.canvas.size[0] - 1)
|
||||||
|
elif keyCode == wx.WXK_RIGHT:
|
||||||
|
self.brushPos[0] = (self.brushPos[0] + 1) % self.canvas.size[0]
|
||||||
|
elif keyCode == wx.WXK_UP:
|
||||||
|
self.brushPos[1] = (self.brushPos[1] - 1) if (self.brushPos[1] > 0) else (self.canvas.size[1] - 1)
|
||||||
|
self.commands.update(cellPos=self.brushPos)
|
||||||
|
self.applyTool(eventDc, True, None, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
|
||||||
|
elif (chr(event.GetUnicodeKey()) == " ") and (self.commands.currentTool.__class__ != ToolText):
|
||||||
|
if not self.applyTool(eventDc, True, None, None, event.GetModifiers(), self.brushPos, False, True, False, self.commands.currentTool, viewRect):
|
||||||
|
event.Skip()
|
||||||
|
else:
|
||||||
|
self.brushPos[0] = (self.brushPos[0] + 1) if (self.brushPos[0] < (self.canvas.size[0] - 1)) else 0
|
||||||
|
self.commands.update(cellPos=self.brushPos)
|
||||||
|
self.applyTool(eventDc, True, None, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
|
||||||
|
elif not self.applyTool(eventDc, False, chr(event.GetUnicodeKey()), keyCode, keyModifiers, None, None, None, None, self.commands.currentTool, viewRect):
|
||||||
|
event.Skip()
|
||||||
|
|
||||||
def onLeaveWindow(self, event):
|
def onLeaveWindow(self, event):
|
||||||
if False:
|
if False:
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
self.cursorHide()
|
||||||
self.backend.drawCursorMaskWithJournal(self.canvas, self.canvas.journal, eventDc)
|
|
||||||
self.lastCellState = None
|
self.lastCellState = None
|
||||||
|
|
||||||
def onMouseInput(self, event):
|
def onMouseInput(self, event):
|
||||||
@ -266,18 +280,19 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
newFontSize = self.backend.fontSize + delta
|
newFontSize = self.backend.fontSize + delta
|
||||||
if newFontSize > 0:
|
if newFontSize > 0:
|
||||||
self.Freeze()
|
self.Freeze()
|
||||||
self.backend.fontSize = newFontSize
|
self.backend.fontSize = newFontSize; self.backend.resize(self.canvas.size); self.scrollStep = self.backend.cellSize;
|
||||||
self.backend.resize(self.canvas.size); self.scrollStep = self.backend.cellSize;
|
|
||||||
super().resize([a * b for a, b in zip(self.canvas.size, self.backend.cellSize)])
|
super().resize([a * b for a, b in zip(self.canvas.size, self.backend.cellSize)])
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
patches = []
|
patches = []
|
||||||
for numRow in range(self.canvas.size[1]):
|
for numRow in range(self.canvas.size[1]):
|
||||||
for numCol in range(len(self.canvas.map[numRow])):
|
for numCol in range(len(self.canvas.map[numRow])):
|
||||||
patches += [[numCol, numRow, *self.canvas.map[numRow][numCol]]]
|
patches += [[numCol, numRow, *self.canvas.map[numRow][numCol]]]
|
||||||
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
||||||
|
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||||
|
self.cursorHide(eventDc, False, False)
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
||||||
|
self.cursorShow(eventDc, False)
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||||
self.Thaw(); del eventDc; self._eraseBackground(wx.ClientDC(self));
|
self.Thaw(); self._windowEraseBackground(wx.ClientDC(self));
|
||||||
elif modifiers == (wx.MOD_CONTROL | wx.MOD_SHIFT):
|
elif modifiers == (wx.MOD_CONTROL | wx.MOD_SHIFT):
|
||||||
self.commands.canvasCanvasSize(self.commands.canvasCanvasSize, 2, 1 if delta > 0 else 0)(None)
|
self.commands.canvasCanvasSize(self.commands.canvasCanvasSize, 2, 1 if delta > 0 else 0)(None)
|
||||||
elif modifiers == wx.MOD_CONTROL:
|
elif modifiers == wx.MOD_CONTROL:
|
||||||
@ -289,7 +304,7 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
viewRect = self.GetViewStart()
|
viewRect = self.GetViewStart()
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||||
self.backend.onPaint(self.GetClientSize(), self, viewRect)
|
self.backend.onPaint(self.GetClientSize(), self, viewRect)
|
||||||
del eventDc; self._eraseBackground(wx.PaintDC(self));
|
del eventDc; self._windowEraseBackground(wx.PaintDC(self));
|
||||||
|
|
||||||
def resize(self, newSize, commitUndo=True, dirty=True, freeze=True):
|
def resize(self, newSize, commitUndo=True, dirty=True, freeze=True):
|
||||||
if freeze:
|
if freeze:
|
||||||
@ -297,76 +312,50 @@ class RoarCanvasWindow(GuiWindow):
|
|||||||
viewRect = self.GetViewStart()
|
viewRect = self.GetViewStart()
|
||||||
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):
|
rc, newCells = self.canvas.resize(self.brushColours, newSize, commitUndo)
|
||||||
|
if rc:
|
||||||
self.backend.resize(newSize); self.scrollStep = self.backend.cellSize;
|
self.backend.resize(newSize); self.scrollStep = self.backend.cellSize;
|
||||||
super().resize([a * b for a, b in zip(newSize, self.backend.cellSize)])
|
super().resize([a * b for a, b in zip(newSize, self.backend.cellSize)])
|
||||||
|
self._applyPatches(None, newCells, None, True, commitUndo=False, dirty=True, hideCursor=False)
|
||||||
self.Scroll(*viewRect); self.dirty = dirty;
|
self.Scroll(*viewRect); self.dirty = dirty;
|
||||||
self.commands.update(dirty=self.dirty, size=newSize, undoLevel=self.canvas.journal.patchesUndoLevel)
|
self.commands.update(dirty=self.dirty, size=newSize, undoLevel=self.canvas.patchesUndoLevel)
|
||||||
if commitUndo:
|
if commitUndo:
|
||||||
self._snapshotsUpdate()
|
self._snapshotsUpdate()
|
||||||
if freeze:
|
if freeze:
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
self.cursorShow(); self.Thaw(); self._windowEraseBackground(wx.ClientDC(self));
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
cursorPatches = self.canvas.journal.popCursor(reset=False)
|
|
||||||
if len(cursorPatches) > 0:
|
|
||||||
self.backend.drawPatches(self.canvas, eventDc, cursorPatches, isCursor=True)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
del eventDc; self.Thaw(); self._eraseBackground(wx.ClientDC(self));
|
|
||||||
|
|
||||||
def undo(self, redo=False):
|
def undo(self, redo=False):
|
||||||
freezeFlag = False
|
freezeFlag, patches, patchesDelta = False, [], self.canvas.popUndo(redo)
|
||||||
deltaPatches = self.canvas.journal.popUndo() if not redo else self.canvas.journal.popRedo()
|
for patch in [p for p in patchesDelta if p != None]:
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
if patch[0] == "resize":
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
patchesCursor = self.backend.drawCursorMaskWithJournal(self.canvas, self.canvas.journal, eventDc, reset=False)
|
|
||||||
patches = []
|
|
||||||
for patch in deltaPatches:
|
|
||||||
if patch == None:
|
|
||||||
continue
|
|
||||||
elif patch[0] == "resize":
|
|
||||||
if not freezeFlag:
|
if not freezeFlag:
|
||||||
self.Freeze(); freezeFlag = True;
|
self.Freeze(); freezeFlag = True;
|
||||||
eventDc = None; self.resize(patch[1:], False, freeze=False);
|
self.resize(patch[1:], False, freeze=False)
|
||||||
else:
|
else:
|
||||||
self.canvas._commitPatch(patch); patches += [patch];
|
patches += [patch]
|
||||||
if eventDc == None:
|
eventDc = self._applyPatches(None, patches, None, True, commitUndo=False, hideCursor=False)
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
self.cursorShow(eventDc, True, None)
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
|
||||||
if len(patchesCursor):
|
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patchesCursor, isCursor=True)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
if freezeFlag:
|
if freezeFlag:
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
self.Thaw(); self._windowEraseBackground(wx.ClientDC(self));
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
|
||||||
cursorPatches = self.canvas.journal.popCursor(reset=False)
|
|
||||||
if len(cursorPatches) > 0:
|
|
||||||
self.backend.drawPatches(self.canvas, eventDc, cursorPatches, isCursor=True)
|
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
del eventDc; self.Thaw(); self._eraseBackground(wx.ClientDC(self));
|
|
||||||
|
|
||||||
def update(self, newSize, commitUndo=True, newCanvas=None, dirty=True):
|
def update(self, newSize, commitUndo=True, newCanvas=None, dirty=True):
|
||||||
self.resize(newSize, commitUndo, dirty)
|
self.resize(newSize, commitUndo, dirty); self.canvas.update(newSize, newCanvas);
|
||||||
self.canvas.update(newSize, newCanvas)
|
patches = []
|
||||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
|
||||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); patches = [];
|
|
||||||
for numRow in range(newSize[1]):
|
for numRow in range(newSize[1]):
|
||||||
for numCol in range(newSize[0]):
|
for numCol in range(newSize[0]):
|
||||||
patches += [[numCol, numRow, *self.canvas.map[numRow][numCol]]]
|
patches += [[numCol, numRow, *self.canvas.map[numRow][numCol]]]
|
||||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
self._applyPatches(None, patches, None, True, dirty=False)
|
||||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
|
||||||
|
|
||||||
def __init__(self, backend, canvas, commands, parent, pos, size):
|
def __init__(self, backend, canvas, commands, parent, pos, size):
|
||||||
super().__init__(parent, pos)
|
super().__init__(parent, pos); self.parent, self.size = parent, size;
|
||||||
self.lastMouseState, self.size = [False, False, False], size
|
self.backend, self.canvas, self.commands = backend(self.size), canvas, commands(self, parent)
|
||||||
self.backend, self.canvas, self.commands, self.parentFrame = backend(self.size), canvas, commands(self, parent), parent
|
|
||||||
self.brushColours, self.brushPos, self.brushSize, self.dirty, self.lastCellState = [3, 9], [0, 0], [1, 1], False, None
|
|
||||||
self.popupEventDc = None
|
|
||||||
self.dropTarget = RoarCanvasWindowDropTarget(self)
|
|
||||||
self.SetDropTarget(self.dropTarget)
|
|
||||||
self.bgBrush, self.bgPen = wx.Brush(self.GetBackgroundColour(), wx.BRUSHSTYLE_SOLID), wx.Pen(self.GetBackgroundColour(), 1)
|
self.bgBrush, self.bgPen = wx.Brush(self.GetBackgroundColour(), wx.BRUSHSTYLE_SOLID), wx.Pen(self.GetBackgroundColour(), 1)
|
||||||
self.Bind(wx.EVT_ERASE_BACKGROUND, self.onErase)
|
self.brushColours, self.brushPos, self.brushSize, = [3, -1], [0, 0], [1, 1]
|
||||||
self.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
|
self.dirty, self.lastCellState, self.lastMouseState = False, None, [False, False, False]
|
||||||
|
self.dropTarget, self.popupEventDc = RoarCanvasWindowDropTarget(self), None
|
||||||
|
for event, handler in ((wx.EVT_ERASE_BACKGROUND, lambda event: None,), (wx.EVT_MOUSEWHEEL, self.onMouseWheel,),):
|
||||||
|
self.Bind(event, handler)
|
||||||
|
self.SetDropTarget(self.dropTarget)
|
||||||
self._snapshotsReset()
|
self._snapshotsReset()
|
||||||
|
|
||||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
||||||
|
@ -14,6 +14,7 @@ class RoarWindowAbout(wx.Dialog):
|
|||||||
def __init__(self, parent, minSize=(320, 300), title="About roar"):
|
def __init__(self, parent, minSize=(320, 300), title="About roar"):
|
||||||
super().__init__(parent, size=minSize, title=title)
|
super().__init__(parent, size=minSize, title=title)
|
||||||
self.panel, self.sizer, self.sizerV = wx.Panel(self), wx.FlexGridSizer(2, 2, 4, 4), wx.BoxSizer(wx.VERTICAL)
|
self.panel, self.sizer, self.sizerV = wx.Panel(self), wx.FlexGridSizer(2, 2, 4, 4), wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.panel.SetBackgroundColour(wx.Colour(0, 0, 0)); self.panel.SetForegroundColour(wx.Colour(0, 187, 0));
|
||||||
|
|
||||||
logoPathNames = glob(os.path.join("assets", "images", "logo*.bmp"))
|
logoPathNames = glob(os.path.join("assets", "images", "logo*.bmp"))
|
||||||
logoPathName = logoPathNames[random.randint(0, len(logoPathNames) - 1)]
|
logoPathName = logoPathNames[random.randint(0, len(logoPathNames) - 1)]
|
||||||
|
@ -13,6 +13,7 @@ class RoarWindowMelp(wx.Dialog):
|
|||||||
def __init__(self, parent, minSize=(320, 300), title="melp?"):
|
def __init__(self, parent, minSize=(320, 300), title="melp?"):
|
||||||
super().__init__(parent, size=minSize, title=title)
|
super().__init__(parent, size=minSize, title=title)
|
||||||
self.panel, self.sizer = wx.Panel(self), wx.BoxSizer(wx.VERTICAL)
|
self.panel, self.sizer = wx.Panel(self), wx.BoxSizer(wx.VERTICAL)
|
||||||
|
self.panel.SetBackgroundColour(wx.Colour(0, 0, 0)); self.panel.SetForegroundColour(wx.Colour(0, 187, 0));
|
||||||
|
|
||||||
with open(os.path.join("assets", "text", "melp.txt"), "r") as fileObject:
|
with open(os.path.join("assets", "text", "melp.txt"), "r") as fileObject:
|
||||||
helpLabel = "".join(fileObject.readlines())
|
helpLabel = "".join(fileObject.readlines())
|
||||||
|
@ -34,12 +34,6 @@ class ToolCircle(Tool):
|
|||||||
elif ((numRow > 0) and (cells[numRow][numCol][0] > cells[numRow - 1][-1][0])) \
|
elif ((numRow > 0) and (cells[numRow][numCol][0] > cells[numRow - 1][-1][0])) \
|
||||||
or ((numRow < len(cells)) and (cells[numRow][numCol][0] > cells[numRow + 1][-1][0])):
|
or ((numRow < len(cells)) and (cells[numRow][numCol][0] > cells[numRow + 1][-1][0])):
|
||||||
patch = [*cells[numRow][numCol], brushColours[0], brushColours[0], 0, " "]
|
patch = [*cells[numRow][numCol], brushColours[0], brushColours[0], 0, " "]
|
||||||
elif brushColours[1] == -1:
|
|
||||||
if (cells[numRow][numCol][0] < canvas.size[0]) \
|
|
||||||
and (cells[numRow][numCol][1] < canvas.size[1]):
|
|
||||||
patch = [cells[numRow][numCol][0], cells[numRow][numCol][1], *canvas.map[cells[numRow][numCol][1]][cells[numRow][numCol][0]]]
|
|
||||||
else:
|
|
||||||
patch = [*cells[numRow][numCol], brushColours[1], brushColours[1], 0, " "]
|
|
||||||
else:
|
else:
|
||||||
patch = [*cells[numRow][numCol], brushColours[1], brushColours[1], 0, " "]
|
patch = [*cells[numRow][numCol], brushColours[1], brushColours[1], 0, " "]
|
||||||
patches += [patch]
|
patches += [patch]
|
||||||
|
@ -18,17 +18,9 @@ class ToolRect(Tool):
|
|||||||
for brushCol in range((rect[2] - rect[0]) + 1):
|
for brushCol in range((rect[2] - rect[0]) + 1):
|
||||||
if (brushCol in [0, (rect[2] - rect[0])]) or (brushRow in [0, (rect[3] - rect[1])]):
|
if (brushCol in [0, (rect[2] - rect[0])]) or (brushRow in [0, (rect[3] - rect[1])]):
|
||||||
patchColours = [brushColours[0]] * 2
|
patchColours = [brushColours[0]] * 2
|
||||||
patch = [rect[0] + brushCol, rect[1] + brushRow, *patchColours, 0, " "]
|
|
||||||
elif brushColours[1] == -1:
|
|
||||||
if ((rect[0] + brushCol) < canvas.size[0]) \
|
|
||||||
and ((rect[1] + brushRow) < canvas.size[1]):
|
|
||||||
patch = [rect[0] + brushCol, rect[1] + brushRow, *canvas.map[rect[1] + brushRow][rect[0] + brushCol]]
|
|
||||||
else:
|
|
||||||
patch = [rect[0] + brushCol, rect[1] + brushRow, -1, -1, 0, " "]
|
|
||||||
else:
|
else:
|
||||||
patchColours = [brushColours[1]] * 2
|
patchColours = [brushColours[1]] * 2
|
||||||
patch = [rect[0] + brushCol, rect[1] + brushRow, *patchColours, 0, " "]
|
patches += [[rect[0] + brushCol, rect[1] + brushRow, *patchColours, 0, " "]]
|
||||||
patches += [patch]
|
|
||||||
return patches
|
return patches
|
||||||
|
|
||||||
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown):
|
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown):
|
||||||
|
@ -70,12 +70,17 @@ class ToolText(Tool):
|
|||||||
rc = True
|
rc = True
|
||||||
elif keyCode == wx.WXK_CONTROL_V:
|
elif keyCode == wx.WXK_CONTROL_V:
|
||||||
rc = True
|
rc = True
|
||||||
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)) \
|
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)) and wx.TheClipboard.Open():
|
||||||
and wx.TheClipboard.Open():
|
|
||||||
inBuffer = wx.TextDataObject()
|
inBuffer = wx.TextDataObject()
|
||||||
if wx.TheClipboard.GetData(inBuffer):
|
if wx.TheClipboard.GetData(inBuffer):
|
||||||
|
brushPosOriginX = brushPos[0]
|
||||||
for inBufferChar in list(inBuffer.GetText()):
|
for inBufferChar in list(inBuffer.GetText()):
|
||||||
if not re.match(self.arabicCombiningRegEx, inBufferChar):
|
if inBufferChar in set("\r\n"):
|
||||||
|
if brushPos[1] < (canvas.size[1] - 1):
|
||||||
|
brushPos[0], brushPos[1] = brushPosOriginX, brushPos[1] + 1
|
||||||
|
else:
|
||||||
|
brushPos[0], brushPos[1] = brushPosOriginX, 0
|
||||||
|
elif not re.match(self.arabicCombiningRegEx, inBufferChar):
|
||||||
rc_, patches_ = self._processKeyChar(brushColours, brushPos, canvas, inBufferChar, 0)
|
rc_, patches_ = self._processKeyChar(brushColours, brushPos, canvas, inBufferChar, 0)
|
||||||
patches += patches_
|
patches += patches_
|
||||||
rc = True if rc_ else rc
|
rc = True if rc_ else rc
|
||||||
|
4
roar.py
4
roar.py
@ -20,7 +20,7 @@ def main(*argv):
|
|||||||
os.makedirs(localConfirName)
|
os.makedirs(localConfirName)
|
||||||
wxApp, roarClient = wx.App(False), RoarClient(None)
|
wxApp, roarClient = wx.App(False), RoarClient(None)
|
||||||
argv0, argv = argv[0], argv[1:]
|
argv0, argv = argv[0], argv[1:]
|
||||||
roarClient.canvasPanel.commands._loadLastDir(); roarClient.canvasPanel.commands._loadRecent();
|
roarClient.canvasPanel.commands._recentDirLoad(); roarClient.canvasPanel.commands._recentLoad();
|
||||||
if len(argv) >= 1:
|
if len(argv) >= 1:
|
||||||
if (len(argv) >= 2) and (argv[1].endswith(".lst")):
|
if (len(argv) >= 2) and (argv[1].endswith(".lst")):
|
||||||
roarClient.assetsWindow._load_list(argv[1])
|
roarClient.assetsWindow._load_list(argv[1])
|
||||||
@ -30,7 +30,7 @@ def main(*argv):
|
|||||||
if rc:
|
if rc:
|
||||||
roarClient.canvasPanel.update(roarClient.canvasPanel.canvas.importStore.inSize, False, roarClient.canvasPanel.canvas.importStore.outMap, dirty=False)
|
roarClient.canvasPanel.update(roarClient.canvasPanel.canvas.importStore.inSize, False, roarClient.canvasPanel.canvas.importStore.outMap, dirty=False)
|
||||||
roarClient.canvasPanel.commands.update(pathName=argv[0], undoLevel=-1)
|
roarClient.canvasPanel.commands.update(pathName=argv[0], undoLevel=-1)
|
||||||
roarClient.canvasPanel.commands._pushRecent(argv[0])
|
roarClient.canvasPanel.commands._recentPush(argv[0])
|
||||||
roarClient.canvasPanel.commands.canvasTool(roarClient.canvasPanel.commands.canvasTool, 1)(None)
|
roarClient.canvasPanel.commands.canvasTool(roarClient.canvasPanel.commands.canvasTool, 1)(None)
|
||||||
else:
|
else:
|
||||||
print("error: {}".format(error), file=sys.stderr)
|
print("error: {}".format(error), file=sys.stderr)
|
||||||
|
Loading…
Reference in New Issue
Block a user