mirror of https://github.com/lalbornoz/roar.git
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
|
@ -6,7 +6,7 @@
|
|||
{
|
||||
"label": "Build libgui/GuiCanvasWxBackendFast.pyd",
|
||||
"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": [
|
||||
"$msCompile"
|
||||
]
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
# 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`
|
||||
* 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](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}
|
||||
3) GUI: implement GuiCanvasWxBackendFast.c{,c}
|
||||
4) GUI: select all
|
||||
|
@ -6,8 +6,10 @@
|
|||
6) Operators: copy, cut, delete, insert from, paste
|
||||
7) Operators: crop, scale, shift, slice operators
|
||||
8) Tools: measure, triangle, unicode block elements tool
|
||||
9) Tools: object tool: reimplement cloning correctly outside of object tool
|
||||
10) Tools: text tool: finish Arabic/RTL text implementation
|
||||
11) Tools: text tool: implicitly draw (text) w/ bg -1, toggle drawing actual brushColours[1] mode w/ RMB
|
||||
9) Tools: object tool: allow application of arbitrary tool to selection before setting
|
||||
10) Tools: object tool: reimplement cloning correctly outside of object tool
|
||||
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
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
3,6▟6,3▝
|
||||
3,6▟6,3▜▛3,6▟6,3▝
|
||||
3,6▟6,3▝▜3,6▟6,3▝▜▛3,6▟6,3▝
|
||||
3,6▟6,3▝3,8/\3,6▟6,3▜▛3,6▟6,3▝3,8/\3,6▟6,3▝
|
||||
9,1/\ 9,1/ 6,3▝▜▛3,6▟6,3▝8,8 3,6▟6,3▝▜▛3,6▟6,3▝
|
||||
6,1(0o9 6) 6,1( 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▝
|
||||
6,1|(__)/ 3,6▟6,3▝▜▛8,8 6\_/6,3▜▛3,6▟6,3▝
|
||||
1,3\\ 1,3.'0s3 6▜▛3,6▟6,3▝
|
||||
1,6\\ 1,6/6 0p6 1\ \ 6,3▜▛
|
||||
1,3\\/3 0o3 1\3 1\ \6▜
|
||||
1,6\6 0k6 1/)___|_|6,3▛
|
||||
1,3(_0e1__/__))) )))6▛
|
||||
12,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲
|
||||
12,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱
|
||||
2,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱
|
||||
2,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲
|
||||
3,6▟6,3▝15
|
||||
3,6▟6,3▜▛3,6▟6,3▝15
|
||||
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▝15
|
||||
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)15 6,1(15 6,3▜▛3,6▟6,3▝8,8 3o _ o8 3,6▟6,3▝▜▛3,6▟
|
||||
9,1( \15 9,1)15 6,3▝▜▛▜8,8 6(_3Y6_)6,3▛▝▛3,6▟6,3▝15
|
||||
6,1|(__)/15 3,6▟6,3▝▜▛8,8 6\_/6,3▜▛3,6▟6,3▝15
|
||||
1,3\\15 1,3.'0s3 6▜▛3,6▟6,3▝15
|
||||
1,6\\15 1,6/6 0p6 1\ \ 6,3▜▛15
|
||||
1,3\\/3 0o3 1\3 1\ \6▜15
|
||||
1,6\6 0k6 1/)___|_|6,3▛15
|
||||
1,3(_0e1__/__))) )))6▛15
|
||||
12,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲15
|
||||
12,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱15
|
||||
2,1╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱15
|
||||
2,1╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲╲15
|
||||
|
|
|
@ -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 './librtl/ImgurApiKey.py' \
|
||||
-not -name '*.exp' \
|
||||
-not -name '*.lib' \
|
||||
-not -name '*.obj' \
|
||||
-not -name '*.sw*' \
|
||||
-not -name "${0##*/}" |\
|
||||
cpio --quiet -dLmp "${_release_dname}";
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
from CanvasExportStore import CanvasExportStore
|
||||
from CanvasImportStore import CanvasImportStore
|
||||
from CanvasJournal import CanvasJournal
|
||||
|
||||
class Canvas():
|
||||
def _commitPatch(self, patch):
|
||||
|
@ -18,11 +17,51 @@ class Canvas():
|
|||
else:
|
||||
patchDeltaCell = self.map[patch[1]][patch[0]]; patchDelta = [*patch[0:2], *patchDeltaCell];
|
||||
if commitUndo:
|
||||
self.journal.updateCurrentDeltas(patch, patchDelta)
|
||||
self.updateCurrentDeltas(patch, patchDelta)
|
||||
self._commitPatch(patch)
|
||||
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 self.map == None:
|
||||
self.map, oldSize = [], [0, 0]
|
||||
|
@ -30,41 +69,43 @@ class Canvas():
|
|||
oldSize = self.size
|
||||
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
||||
if commitUndo:
|
||||
self.journal.begin()
|
||||
self.begin()
|
||||
undoPatches, redoPatches = ["resize", *oldSize], ["resize", *newSize]
|
||||
self.journal.updateCurrentDeltas(redoPatches, undoPatches)
|
||||
self.updateCurrentDeltas(redoPatches, undoPatches)
|
||||
if deltaSize[0] < 0:
|
||||
for numRow in range(oldSize[1]):
|
||||
if commitUndo:
|
||||
for numCol in range((oldSize[0] + deltaSize[0]), oldSize[0]):
|
||||
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]
|
||||
else:
|
||||
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]):
|
||||
if commitUndo:
|
||||
self.journal.updateCurrentDeltas([numNewCol, numRow, 1, 1, 0, " "], None)
|
||||
self.applyPatch([numNewCol, numRow, 1, 1, 0, " "], False)
|
||||
self.updateCurrentDeltas([numNewCol, numRow, *brushColours, 0, " "], None)
|
||||
newCells += [[numNewCol, numRow, *brushColours, 0, " "]]
|
||||
self.applyPatch([numNewCol, numRow, *brushColours, 0, " "], False)
|
||||
if deltaSize[1] < 0:
|
||||
if commitUndo:
|
||||
for numRow in range((oldSize[1] + deltaSize[1]), oldSize[1]):
|
||||
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]
|
||||
else:
|
||||
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]):
|
||||
if commitUndo:
|
||||
self.journal.updateCurrentDeltas([numNewCol, numNewRow, 1, 1, 0, " "], None)
|
||||
self.applyPatch([numNewCol, numNewRow, 1, 1, 0, " "], False)
|
||||
self.updateCurrentDeltas([numNewCol, numNewRow, *brushColours, 0, " "], None)
|
||||
newCells += [[numNewCol, numNewRow, *brushColours, 0, " "]]
|
||||
self.applyPatch([numNewCol, numNewRow, *brushColours, 0, " "], False)
|
||||
self.size = newSize
|
||||
if commitUndo:
|
||||
self.journal.end()
|
||||
return True
|
||||
self.end()
|
||||
return True, newCells
|
||||
else:
|
||||
return False
|
||||
return False, newCells
|
||||
|
||||
def update(self, newSize, newCanvas=None):
|
||||
for numRow in range(self.size[1]):
|
||||
|
@ -73,7 +114,15 @@ class Canvas():
|
|||
and (numRow < len(newCanvas)) and (numCol < len(newCanvas[numRow])):
|
||||
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):
|
||||
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
|
||||
|
|
|
@ -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>
|
||||
#
|
||||
|
||||
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
|
||||
import GuiCanvasWxBackendFast
|
||||
import math, os, platform, wx
|
||||
import math, os, platform, Rtl, wx
|
||||
|
||||
class GuiBufferedDC(wx.MemoryDC):
|
||||
def __del__(self):
|
||||
|
@ -143,20 +147,7 @@ class GuiCanvasWxBackend():
|
|||
brush, pen = self._brushesBlend[bg][14], self._pensBlend[bg][14]
|
||||
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):
|
||||
GuiCanvasWxBackendFast.drawPatches()
|
||||
patchesRender = []
|
||||
for patch in patches:
|
||||
point = patch[:2]
|
||||
|
@ -166,6 +157,8 @@ class GuiCanvasWxBackend():
|
|||
patchesRender += [patchReshaped]
|
||||
else:
|
||||
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)
|
||||
rectangles, pens, brushes = [None] * len(patchesRender), [None] * len(patchesRender), [None] * len(patchesRender)
|
||||
textList, coords, foregrounds, backgrounds = [], [], [], []
|
||||
|
@ -173,10 +166,10 @@ class GuiCanvasWxBackend():
|
|||
for patchRender in patchesRender:
|
||||
if (patchRender[5] == " ") and (patchRender[3] == -1):
|
||||
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:]]
|
||||
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:]]
|
||||
text, textFg = "_", wx.Colour(self._blendColours(canvas.map[patchRender[1]][patchRender[0]][0], patchRender[3]))
|
||||
elif patchRender[5] != " ":
|
||||
|
@ -228,9 +221,11 @@ class GuiCanvasWxBackend():
|
|||
oldDc = wx.MemoryDC(); oldDc.SelectObject(self.canvasBitmap);
|
||||
newDc = wx.MemoryDC(); newBitmap = wx.Bitmap(winSize); newDc.SelectObject(newBitmap);
|
||||
newDc.Blit(0, 0, *self.canvasBitmap.GetSize(), oldDc, 0, 0)
|
||||
oldDc.SelectObject(wx.NullBitmap)
|
||||
oldDc.SelectObject(wx.NullBitmap); newDc.SelectObject(wx.NullBitmap);
|
||||
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):
|
||||
eventPoint = event.GetLogicalPosition(eventDc)
|
||||
|
@ -244,6 +239,8 @@ class GuiCanvasWxBackend():
|
|||
self._finiBrushesAndPens()
|
||||
|
||||
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.canvasBitmap, self.cellSize, self.fontName, self.fontPathName, self.fontSize = None, None, fontName, fontPathName, fontSize
|
||||
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);
|
||||
}
|
|
@ -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):
|
||||
oldSize = [0, 0] if canvas.map == None else canvas.size
|
||||
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)]
|
||||
self.panelCanvas.SetMinSize(panelSize); self.panelCanvas.SetSize(wx.DefaultCoord, wx.DefaultCoord, *panelSize);
|
||||
curWindow = self.panelCanvas
|
||||
|
@ -228,6 +228,7 @@ class RoarAssetsWindow(GuiMiniFrame):
|
|||
id = +1 if keyCode == wx.WXK_DOWN else -1
|
||||
self.currentIndex = (self.currentIndex + id) % len(self.canvasList)
|
||||
self.listView.Select(self.currentIndex, on=1)
|
||||
self.listView.EnsureVisible(self.currentIndex)
|
||||
else:
|
||||
index, rc = self.listView.GetFirstSelected(), False
|
||||
if index != -1:
|
||||
|
@ -304,6 +305,8 @@ class RoarAssetsWindow(GuiMiniFrame):
|
|||
break
|
||||
while len(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):
|
||||
rc = True
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
#
|
||||
|
||||
from GuiCanvasColours import Colours
|
||||
from GuiFrame import NID_TOOLBAR_HSEP
|
||||
from GuiFrame import NID_MENU_SEP, NID_TOOLBAR_HSEP
|
||||
from RoarCanvasCommandsEdit import RoarCanvasCommandsEdit
|
||||
from RoarCanvasCommandsFile import RoarCanvasCommandsFile
|
||||
from RoarCanvasCommandsHelp import RoarCanvasCommandsHelp
|
||||
from RoarCanvasCommandsOperators import RoarCanvasCommandsOperators
|
||||
from RoarCanvasCommandsTools import RoarCanvasCommandsTools
|
||||
from ToolObject import ToolObject
|
||||
import os, wx
|
||||
|
||||
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.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):
|
||||
self.lastPanelState.update(kwargs); textItems = [];
|
||||
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]
|
||||
toolBarBg = self.parentFrame.toolBarItemsById[self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"]][0]
|
||||
if self.lastPanelState["colours"][0] != -1:
|
||||
toolBar.ToggleTool(self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"], True)
|
||||
toolBar.Refresh()
|
||||
toolBar.ToggleTool(self.canvasColour(self.canvasColour, self.lastPanelState["colours"][0]).attrDict["id"], True); toolBar.Refresh()
|
||||
else:
|
||||
toolBar.ToggleTool(self.canvasColourAlpha(self.canvasColourAlpha, 0).attrDict["id"], True)
|
||||
toolBar.Refresh()
|
||||
toolBar.ToggleTool(self.canvasColourAlpha(self.canvasColourAlpha, 0).attrDict["id"], True); toolBar.Refresh()
|
||||
if self.lastPanelState["colours"][1] != -1:
|
||||
toolBarBg.ToggleTool(self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"], True)
|
||||
toolBarBg.Refresh()
|
||||
toolBarBg.ToggleTool(self.canvasColourBackground(self.canvasColourBackground, self.lastPanelState["colours"][1]).attrDict["id"], True); toolBarBg.Refresh()
|
||||
else:
|
||||
toolBarBg.ToggleTool(self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0).attrDict["id"], True)
|
||||
toolBarBg.Refresh()
|
||||
toolBarBg.ToggleTool(self.canvasColourAlphaBackground(self.canvasColourAlphaBackground, 0).attrDict["id"], True); toolBarBg.Refresh()
|
||||
if "pathName" in self.lastPanelState:
|
||||
if self.lastPanelState["pathName"] != None:
|
||||
basePathName = os.path.basename(self.lastPanelState["pathName"])
|
||||
|
@ -71,27 +127,25 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
|||
self.parentFrame.SetTitle("{} - roar".format(basePathName))
|
||||
else:
|
||||
self.parentFrame.SetTitle("roar")
|
||||
if "toolName" in self.lastPanelState:
|
||||
textItems.append("T: {}".format(self.lastPanelState["toolName"]))
|
||||
if ("operator" in self.lastPanelState) \
|
||||
and (self.lastPanelState["operator"] != None):
|
||||
if "currentTool" in self.lastPanelState:
|
||||
self.parentFrame.menuItemsById[self.canvasTool.attrList[self.lastPanelState["currentToolIdx"]]["id"]].Check(True)
|
||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasTool.attrList[self.lastPanelState["currentToolIdx"]]["id"]][0]
|
||||
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"]))
|
||||
if "dirty" in self.lastPanelState \
|
||||
and self.lastPanelState["dirty"]:
|
||||
if ("dirty" in self.lastPanelState) and self.lastPanelState["dirty"]:
|
||||
textItems.append("*")
|
||||
if "backupStatus" in self.lastPanelState \
|
||||
and self.lastPanelState["backupStatus"] == True:
|
||||
if ("backupStatus" in self.lastPanelState) and (self.lastPanelState["backupStatus"] == True):
|
||||
textItems.append("Saving backup...")
|
||||
self.parentFrame.statusBar.SetStatusText(" | ".join(textItems))
|
||||
if ("undoInhibit" 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 "undoLevel" in self.lastPanelState:
|
||||
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)
|
||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasUndo.attrDict["id"]][0]
|
||||
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();
|
||||
|
||||
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
|
||||
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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
# 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
|
||||
|
||||
class RoarCanvasCommandsEdit():
|
||||
|
@ -194,31 +194,10 @@ class RoarCanvasCommandsEdit():
|
|||
|
||||
@GuiCommandDecorator("Redo", "&Redo", ["", wx.ART_REDO], [wx.ACCEL_CTRL, ord("Y")], False)
|
||||
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)
|
||||
def canvasUndo(self, event):
|
||||
self.parentCanvas.undo(); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.journal.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 = ()
|
||||
self.parentCanvas.undo(); self.update(size=self.parentCanvas.canvas.size, undoLevel=self.parentCanvas.canvas.patchesUndoLevel);
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
#
|
||||
|
||||
try:
|
||||
from ImgurApiKey import ImgurApiKey
|
||||
haveImgurApiKey = True
|
||||
from ImgurApiKey import ImgurApiKey; haveImgurApiKey = True;
|
||||
except ImportError:
|
||||
haveImgurApiKey = False
|
||||
|
||||
try:
|
||||
import base64, json, requests, urllib.request
|
||||
haveUrllib = True
|
||||
import base64, json, requests, urllib.request; haveUrllib = True;
|
||||
except ImportError:
|
||||
haveUrllib = False
|
||||
|
||||
|
@ -35,8 +33,7 @@ class RoarCanvasCommandsFile():
|
|||
self.canvasPathName = None
|
||||
self.parentCanvas._snapshotsReset()
|
||||
self.update(dirty=self.parentCanvas.dirty, pathName=self.canvasPathName, undoLevel=-1)
|
||||
self.parentCanvas.canvas.journal.resetCursor()
|
||||
self.parentCanvas.canvas.journal.resetUndo()
|
||||
self.parentCanvas.canvas.resetCursor(); self.parentCanvas.canvas.resetUndo();
|
||||
except FileNotFoundError as e:
|
||||
rc, error, newMap, newPathName, newSize = False, str(e), None, None, None
|
||||
if not rc:
|
||||
|
@ -52,28 +49,10 @@ class RoarCanvasCommandsFile():
|
|||
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||
return False, None
|
||||
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 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):
|
||||
if self.parentCanvas.dirty:
|
||||
message = "Do you want to save changes to {}?".format(self.canvasPathName if self.canvasPathName != None else "(Untitled)")
|
||||
|
@ -90,7 +69,25 @@ class RoarCanvasCommandsFile():
|
|||
else:
|
||||
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()
|
||||
if not pathName in [l["pathName"] for l in self.lastFiles]:
|
||||
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.lastFiles += [{"menuItemId":menuItemId, "menuItemWindow":menuItemWindow, "pathName":pathName}]
|
||||
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()
|
||||
if not (pathName in self.snapshots.keys()):
|
||||
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.snapshots[pathName] = {"menuItemId":menuItemId, "menuItemWindow":menuItemWindow}
|
||||
|
||||
def _resetSnapshots(self):
|
||||
def _snapshotsReset(self):
|
||||
for pathName in list(self.snapshots.keys()):
|
||||
self._popSnapshot(pathName)
|
||||
self._snapshotsPop(pathName)
|
||||
if self.canvasRestore.attrDict["id"] in self.parentFrame.menuItemsById:
|
||||
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)
|
||||
def canvasClearRecent(self, event):
|
||||
if self.lastFiles != None:
|
||||
|
@ -155,7 +152,7 @@ class RoarCanvasCommandsFile():
|
|||
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||
return False
|
||||
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))
|
||||
with open(outPathName, "w", encoding="utf-8") as 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:
|
||||
return False
|
||||
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))
|
||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
||||
self.parentCanvas.backend.drawCursorMaskWithJournal(self.parentCanvas.canvas, self.parentCanvas.canvas.journal, eventDc, reset=False)
|
||||
self.parentCanvas.cursorHide()
|
||||
self.parentCanvas.canvas.exportStore.exportBitmapToPngFile(self.parentCanvas.backend.canvasBitmap, outPathName, wx.BITMAP_TYPE_PNG)
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
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.cursorShow()
|
||||
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
||||
return True
|
||||
|
||||
@GuiCommandDecorator("Export to Imgur...", "Export to I&mgur...", None, None, haveImgurApiKey and haveUrllib)
|
||||
def canvasExportImgur(self, event):
|
||||
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
|
||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
||||
self.parentCanvas.backend.drawCursorMaskWithJournal(self.parentCanvas.canvas, self.parentCanvas.canvas.journal, eventDc, reset=False)
|
||||
self.parentCanvas.cursorHide()
|
||||
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);
|
||||
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.cursorShow()
|
||||
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
|
||||
if rc:
|
||||
if not wx.TheClipboard.IsOpened():
|
||||
|
@ -261,7 +248,7 @@ class RoarCanvasCommandsFile():
|
|||
nonlocal newCanvasSize
|
||||
if newCanvasSize == None:
|
||||
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)
|
||||
if self._promptSaveChanges():
|
||||
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)
|
||||
rc, newPathName = self._importFile(canvasImportmIRC, False, "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*")
|
||||
if rc:
|
||||
self._pushRecent(newPathName)
|
||||
self._recentPush(newPathName)
|
||||
|
||||
@GuiSubMenuDecorator("Open Recent", "Open &Recent", None, None, False)
|
||||
def canvasOpenRecent(self, event, pathName=None):
|
||||
|
@ -285,7 +272,7 @@ class RoarCanvasCommandsFile():
|
|||
if not rc:
|
||||
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._saveRecent()
|
||||
self._recentSave()
|
||||
|
||||
@GuiSubMenuDecorator("Restore Snapshot", "Res&tore Snapshot", None, None, False)
|
||||
def canvasRestore(self, event, pathName=None):
|
||||
|
@ -328,27 +315,16 @@ class RoarCanvasCommandsFile():
|
|||
if dialog.ShowModal() == wx.ID_CANCEL:
|
||||
return False
|
||||
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):
|
||||
self.update(pathName=self.canvasPathName)
|
||||
self._pushRecent(self.canvasPathName)
|
||||
self._recentPush(self.canvasPathName)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __init__(self):
|
||||
self.imgurApiKey, self.lastFiles, self.lastDir, self.snapshots = ImgurApiKey.imgurApiKey if haveImgurApiKey else None, [], None, {}
|
||||
self.accels = ()
|
||||
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
|
||||
self.exiting, self.lastFiles, self.lastDir, self.snapshots = False, [], None, {}
|
||||
self.imgurApiKey = ImgurApiKey.imgurApiKey if haveImgurApiKey else None
|
||||
|
||||
# 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>
|
||||
#
|
||||
|
||||
from GuiFrame import GuiCommandDecorator, NID_MENU_SEP
|
||||
from GuiFrame import GuiCommandDecorator
|
||||
from RoarWindowAbout import RoarWindowAbout
|
||||
from RoarWindowMelp import RoarWindowMelp
|
||||
import webbrowser, wx
|
||||
|
@ -26,8 +26,4 @@ class RoarCanvasCommandsHelp():
|
|||
def canvasVisitGitHub(self, event):
|
||||
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
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||
#
|
||||
|
||||
from GuiFrame import GuiCommandListDecorator
|
||||
from OperatorFlipHorizontal import OperatorFlipHorizontal
|
||||
from OperatorFlipVertical import OperatorFlipVertical
|
||||
from OperatorInvert import OperatorInvert
|
||||
from OperatorRotate import OperatorRotate
|
||||
from OperatorTile import OperatorTile
|
||||
from GuiFrame import GuiCommandListDecorator
|
||||
from ToolObject import ToolObject
|
||||
import copy, wx
|
||||
|
||||
class RoarCanvasCommandsOperators():
|
||||
@GuiCommandListDecorator(0, "Flip", "&Flip", None, None, None)
|
||||
|
@ -28,13 +27,6 @@ class RoarCanvasCommandsOperators():
|
|||
return canvasOperator_
|
||||
|
||||
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
|
||||
|
||||
# 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)
|
||||
def canvasTool(self, f, idx):
|
||||
def canvasTool_(event):
|
||||
if (self.currentTool.__class__ == ToolObject) \
|
||||
and (self.currentTool.toolState > self.currentTool.TS_NONE) \
|
||||
if (self.currentTool.__class__ == ToolObject) \
|
||||
and (self.currentTool.toolState > self.currentTool.TS_NONE) \
|
||||
and self.currentTool.external:
|
||||
self.parentCanvas.dropTarget.done()
|
||||
self.lastTool, self.currentTool = self.currentTool, [ToolCircle, None, ToolErase, ToolFill, ToolLine, ToolObject, ToolPickColour, ToolRect, ToolText][idx]
|
||||
if self.currentTool != None:
|
||||
self.currentTool = self.currentTool()
|
||||
self.currentOperator, self.operatorState = None, None
|
||||
self.parentFrame.menuItemsById[self.canvasTool.attrList[idx]["id"]].Check(True)
|
||||
if self.currentTool.__class__ == ToolObject:
|
||||
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)
|
||||
self.update(currentTool=self.currentTool, currentToolIdx=idx, operator=None)
|
||||
self.parentCanvas.applyTool(None, True, None, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, None, force=True)
|
||||
setattr(canvasTool_, "attrDict", f.attrList[idx])
|
||||
setattr(canvasTool_, "isSelect", True)
|
||||
return canvasTool_
|
||||
|
||||
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
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||
|
|
|
@ -9,7 +9,7 @@ from Rtl import natural_sort
|
|||
from RtlPlatform import getLocalConfPathName
|
||||
from ToolObject import ToolObject
|
||||
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):
|
||||
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)];
|
||||
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.parentFrame.menuItemsById[self.parent.commands.canvasOperator.attrList[4]["id"]].Enable(True)
|
||||
self.parent.commands.update(toolName=self.parent.commands.currentTool.name)
|
||||
self.parent.parent.menuItemsById[self.parent.commands.canvasOperator.attrList[4]["id"]].Enable(True)
|
||||
self.parent.commands.update(currentTool=self.parent.commands.currentTool, currentToolIdx=5)
|
||||
eventDc = self.parent.backend.getDeviceContext(self.parent.GetClientSize(), self.parent, viewRect)
|
||||
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)
|
||||
|
@ -43,45 +43,34 @@ class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
|||
super().__init__(); self.inProgress, self.parent = False, parent;
|
||||
|
||||
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:
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
if ((patches != None) and (len(patches) > 0)) \
|
||||
or ((patchesCursor != None) and (len(patchesCursor) > 0)):
|
||||
self.backend.drawCursorMaskWithJournal(self.canvas, self.canvas.journal, eventDc)
|
||||
if eventDc == None:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
||||
if eventDcResetOrigin:
|
||||
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):
|
||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
||||
self.dirty = True if not self.dirty else self.dirty;
|
||||
self.canvas.journal.begin()
|
||||
if dirty and not self.dirty:
|
||||
self.dirty = True
|
||||
if commitUndo:
|
||||
self.canvas.begin()
|
||||
for patch in patches if patches != None else []:
|
||||
self.canvas.applyPatch(patch, commitUndo=True)
|
||||
self.canvas.journal.end()
|
||||
if patchesCursor != None:
|
||||
self.backend.drawPatches(self.canvas, eventDc, patchesCursor, isCursor=True)
|
||||
if len(patchesCursor) > 0:
|
||||
self.canvas.journal.pushCursor(patchesCursor)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
self.commands.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
|
||||
|
||||
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)
|
||||
self.canvas.applyPatch(patch, commitUndo=commitUndo)
|
||||
if commitUndo:
|
||||
self.canvas.end()
|
||||
if hideCursor and (patchesCursor != None):
|
||||
self.cursorShow(eventDc, False, patchesCursor=patchesCursor)
|
||||
if eventDcResetOrigin:
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
self.commands.update(cellPos=self.brushPos, dirty=self.dirty, undoLevel=self.canvas.patchesUndoLevel)
|
||||
return eventDc
|
||||
|
||||
def _snapshotsReset(self):
|
||||
self._snapshotFiles, self._snapshotsUpdateLast = [], time.time()
|
||||
self.commands._resetSnapshots()
|
||||
self.commands._snapshotsReset()
|
||||
if self.commands.canvasPathName != None:
|
||||
canvasPathName = os.path.abspath(self.commands.canvasPathName)
|
||||
canvasFileName = os.path.basename(canvasPathName)
|
||||
|
@ -90,7 +79,7 @@ class RoarCanvasWindow(GuiWindow):
|
|||
if os.path.exists(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))]):
|
||||
self.commands._pushSnapshot(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||
self.commands._snapshotsPush(os.path.join(self._snapshotsDirName, snapshotFile))
|
||||
else:
|
||||
self._snapshotsDirName = None
|
||||
|
||||
|
@ -115,14 +104,30 @@ class RoarCanvasWindow(GuiWindow):
|
|||
self.SetCursor(wx.Cursor(wx.NullCursor))
|
||||
self.commands.update(snapshotStatus=False); self._snapshotsUpdateLast = time.time();
|
||||
self._snapshotFiles += [os.path.basename(snapshotPathName)];
|
||||
self.commands._pushSnapshot(snapshotPathName)
|
||||
self.commands._snapshotsPush(snapshotPathName)
|
||||
if len(self._snapshotFiles) > 72:
|
||||
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;
|
||||
except:
|
||||
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):
|
||||
eventDc, patches, patchesCursor, rc = self.backend.getDeviceContext(self.GetClientSize(), self), None, None, True
|
||||
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):
|
||||
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:
|
||||
self.lastCellState = None if force else self.lastCellState
|
||||
if ((mapPoint[0] < self.canvas.size[0]) and (mapPoint[1] < self.canvas.size[1])) \
|
||||
|
@ -173,75 +182,80 @@ class RoarCanvasWindow(GuiWindow):
|
|||
elif mapPoint != None:
|
||||
rc, patches, patchesCursor = True, None, [[*mapPoint, self.brushColours[0], self.brushColours[0], 0, " "]]
|
||||
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)
|
||||
if tool.__class__ == ToolObject:
|
||||
if tool.toolState > tool.TS_NONE:
|
||||
self.commands.update(undoInhibit=True)
|
||||
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 (tool.__class__ == ToolObject) and (tool.external, tool.toolState) == (True, tool.TS_NONE):
|
||||
self.dropTarget.done(); self.commands.currentTool, self.commands.lastTool = self.commands.lastTool, self.commands.currentTool;
|
||||
self.commands.update(currentTool=self.commands.currentTool)
|
||||
if (patches != None) and (len(patches) > 0):
|
||||
self._snapshotsUpdate()
|
||||
return rc
|
||||
|
||||
def onKeyboardInput(self, event):
|
||||
keyCode, keyModifiers = event.GetKeyCode(), event.GetModifiers()
|
||||
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
|
||||
if (keyCode == wx.WXK_PAUSE) \
|
||||
and (keyModifiers == wx.MOD_SHIFT):
|
||||
import pdb; pdb.set_trace()
|
||||
elif keyCode in (wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP):
|
||||
if keyCode == wx.WXK_DOWN:
|
||||
if self.brushPos[1] < (self.canvas.size[1] - 1):
|
||||
self.brushPos = [self.brushPos[0], self.brushPos[1] + 1]
|
||||
else:
|
||||
self.brushPos = [self.brushPos[0], 0]
|
||||
elif keyCode == wx.WXK_LEFT:
|
||||
if self.brushPos[0] > 0:
|
||||
self.brushPos = [self.brushPos[0] - 1, self.brushPos[1]]
|
||||
else:
|
||||
self.brushPos = [self.canvas.size[0] - 1, self.brushPos[1]]
|
||||
elif keyCode == wx.WXK_RIGHT:
|
||||
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]]
|
||||
elif keyCode == wx.WXK_UP:
|
||||
if self.brushPos[1] > 0:
|
||||
self.brushPos = [self.brushPos[0], self.brushPos[1] - 1]
|
||||
else:
|
||||
self.brushPos = [self.brushPos[0], 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:
|
||||
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 cursorHide(self, eventDc=None, eventDcResetOrigin=True, reset=False):
|
||||
if eventDc == None:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
if eventDcResetOrigin:
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
patchesCursor = self.canvas.popCursor(reset=reset); patchesCursor_ = [];
|
||||
for cursorCell in [p[:2] for p in patchesCursor]:
|
||||
if (cursorCell[0] < self.canvas.size[0]) and (cursorCell[1] < self.canvas.size[1]):
|
||||
patchesCursor_ += [[*cursorCell, *self.canvas.map[cursorCell[1]][cursorCell[0]]]]
|
||||
if len(patchesCursor_) > 0:
|
||||
self.backend.drawPatches(self.canvas, eventDc, patchesCursor_, False)
|
||||
if eventDcResetOrigin:
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
return eventDc
|
||||
|
||||
def cursorShow(self, eventDc=None, eventDcResetOrigin=True, patchesCursor=None):
|
||||
if eventDc == None:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
if eventDcResetOrigin:
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
if patchesCursor == None:
|
||||
patchesCursor = self.canvas.popCursor(reset=False)
|
||||
elif len(patchesCursor) > 0:
|
||||
self.canvas.pushCursor(patchesCursor)
|
||||
if (patchesCursor != None) and (len(patchesCursor) > 0):
|
||||
self.backend.drawPatches(self.canvas, eventDc, patchesCursor, isCursor=True)
|
||||
if eventDcResetOrigin:
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
|
||||
def onEnterWindow(self, event):
|
||||
self.lastCellState = None
|
||||
|
||||
def onErase(self, event):
|
||||
pass
|
||||
def onKeyboardInput(self, event):
|
||||
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):
|
||||
if False:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
||||
self.backend.drawCursorMaskWithJournal(self.canvas, self.canvas.journal, eventDc)
|
||||
self.cursorHide()
|
||||
self.lastCellState = None
|
||||
|
||||
def onMouseInput(self, event):
|
||||
|
@ -266,18 +280,19 @@ class RoarCanvasWindow(GuiWindow):
|
|||
newFontSize = self.backend.fontSize + delta
|
||||
if newFontSize > 0:
|
||||
self.Freeze()
|
||||
self.backend.fontSize = newFontSize
|
||||
self.backend.resize(self.canvas.size); self.scrollStep = self.backend.cellSize;
|
||||
self.backend.fontSize = newFontSize; 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)])
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
patches = []
|
||||
for numRow in range(self.canvas.size[1]):
|
||||
for numCol in range(len(self.canvas.map[numRow])):
|
||||
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.cursorShow(eventDc, False)
|
||||
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):
|
||||
self.commands.canvasCanvasSize(self.commands.canvasCanvasSize, 2, 1 if delta > 0 else 0)(None)
|
||||
elif modifiers == wx.MOD_CONTROL:
|
||||
|
@ -289,7 +304,7 @@ class RoarCanvasWindow(GuiWindow):
|
|||
viewRect = self.GetViewStart()
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
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):
|
||||
if freeze:
|
||||
|
@ -297,76 +312,50 @@ class RoarCanvasWindow(GuiWindow):
|
|||
viewRect = self.GetViewStart()
|
||||
oldSize = [0, 0] if self.canvas.map == None else self.canvas.size
|
||||
deltaSize = [b - a for a, b in zip(oldSize, newSize)]
|
||||
if self.canvas.resize(newSize, commitUndo):
|
||||
rc, newCells = self.canvas.resize(self.brushColours, newSize, commitUndo)
|
||||
if rc:
|
||||
self.backend.resize(newSize); self.scrollStep = 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.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:
|
||||
self._snapshotsUpdate()
|
||||
if freeze:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), 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));
|
||||
self.cursorShow(); self.Thaw(); self._windowEraseBackground(wx.ClientDC(self));
|
||||
|
||||
def undo(self, redo=False):
|
||||
freezeFlag = False
|
||||
deltaPatches = self.canvas.journal.popUndo() if not redo else self.canvas.journal.popRedo()
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
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":
|
||||
freezeFlag, patches, patchesDelta = False, [], self.canvas.popUndo(redo)
|
||||
for patch in [p for p in patchesDelta if p != None]:
|
||||
if patch[0] == "resize":
|
||||
if not freezeFlag:
|
||||
self.Freeze(); freezeFlag = True;
|
||||
eventDc = None; self.resize(patch[1:], False, freeze=False);
|
||||
self.resize(patch[1:], False, freeze=False)
|
||||
else:
|
||||
self.canvas._commitPatch(patch); patches += [patch];
|
||||
if eventDc == None:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self)
|
||||
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)
|
||||
patches += [patch]
|
||||
eventDc = self._applyPatches(None, patches, None, True, commitUndo=False, hideCursor=False)
|
||||
self.cursorShow(eventDc, True, None)
|
||||
if freezeFlag:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), 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));
|
||||
self.Thaw(); self._windowEraseBackground(wx.ClientDC(self));
|
||||
|
||||
def update(self, newSize, commitUndo=True, newCanvas=None, dirty=True):
|
||||
self.resize(newSize, commitUndo, dirty)
|
||||
self.canvas.update(newSize, newCanvas)
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart())
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0); patches = [];
|
||||
self.resize(newSize, commitUndo, dirty); self.canvas.update(newSize, newCanvas);
|
||||
patches = []
|
||||
for numRow in range(newSize[1]):
|
||||
for numCol in range(newSize[0]):
|
||||
patches += [[numCol, numRow, *self.canvas.map[numRow][numCol]]]
|
||||
self.backend.drawPatches(self.canvas, eventDc, patches, isCursor=False)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
self._applyPatches(None, patches, None, True, dirty=False)
|
||||
|
||||
def __init__(self, backend, canvas, commands, parent, pos, size):
|
||||
super().__init__(parent, pos)
|
||||
self.lastMouseState, self.size = [False, False, False], size
|
||||
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)
|
||||
super().__init__(parent, pos); self.parent, self.size = parent, size;
|
||||
self.backend, self.canvas, self.commands = backend(self.size), canvas, commands(self, parent)
|
||||
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.Bind(wx.EVT_MOUSEWHEEL, self.onMouseWheel)
|
||||
self.brushColours, self.brushPos, self.brushSize, = [3, -1], [0, 0], [1, 1]
|
||||
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()
|
||||
|
||||
# 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"):
|
||||
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.SetBackgroundColour(wx.Colour(0, 0, 0)); self.panel.SetForegroundColour(wx.Colour(0, 187, 0));
|
||||
|
||||
logoPathNames = glob(os.path.join("assets", "images", "logo*.bmp"))
|
||||
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?"):
|
||||
super().__init__(parent, size=minSize, title=title)
|
||||
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:
|
||||
helpLabel = "".join(fileObject.readlines())
|
||||
|
|
|
@ -10,9 +10,9 @@ import re
|
|||
def flatten(l):
|
||||
return [li for l_ in l for li in l_]
|
||||
|
||||
def natural_sort(l):
|
||||
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
||||
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
||||
def natural_sort(l):
|
||||
convert = lambda text: int(text) if text.isdigit() else text.lower()
|
||||
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
|
||||
return sorted(l, key=alphanum_key)
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
||||
|
|
|
@ -34,12 +34,6 @@ class ToolCircle(Tool):
|
|||
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])):
|
||||
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:
|
||||
patch = [*cells[numRow][numCol], brushColours[1], brushColours[1], 0, " "]
|
||||
patches += [patch]
|
||||
|
|
|
@ -18,17 +18,9 @@ class ToolRect(Tool):
|
|||
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])]):
|
||||
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:
|
||||
patchColours = [brushColours[1]] * 2
|
||||
patch = [rect[0] + brushCol, rect[1] + brushRow, *patchColours, 0, " "]
|
||||
patches += [patch]
|
||||
patches += [[rect[0] + brushCol, rect[1] + brushRow, *patchColours, 0, " "]]
|
||||
return patches
|
||||
|
||||
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown):
|
||||
|
|
|
@ -70,12 +70,17 @@ class ToolText(Tool):
|
|||
rc = True
|
||||
elif keyCode == wx.WXK_CONTROL_V:
|
||||
rc = True
|
||||
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)) \
|
||||
and wx.TheClipboard.Open():
|
||||
if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)) and wx.TheClipboard.Open():
|
||||
inBuffer = wx.TextDataObject()
|
||||
if wx.TheClipboard.GetData(inBuffer):
|
||||
brushPosOriginX = brushPos[0]
|
||||
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)
|
||||
patches += patches_
|
||||
rc = True if rc_ else rc
|
||||
|
|
4
roar.py
4
roar.py
|
@ -20,7 +20,7 @@ def main(*argv):
|
|||
os.makedirs(localConfirName)
|
||||
wxApp, roarClient = wx.App(False), RoarClient(None)
|
||||
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) >= 2) and (argv[1].endswith(".lst")):
|
||||
roarClient.assetsWindow._load_list(argv[1])
|
||||
|
@ -30,7 +30,7 @@ def main(*argv):
|
|||
if rc:
|
||||
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._pushRecent(argv[0])
|
||||
roarClient.canvasPanel.commands._recentPush(argv[0])
|
||||
roarClient.canvasPanel.commands.canvasTool(roarClient.canvasPanel.commands.canvasTool, 1)(None)
|
||||
else:
|
||||
print("error: {}".format(error), file=sys.stderr)
|
||||
|
|
Loading…
Reference in New Issue