Implements importing from {ANSI,SAUCE} and exporting to ANSI files.

assets/tools/{MiRCARTTo{Ansi,PngFile},SAUCETo{Ansi,MiRCART}}.py: reimplemented using Canvas{Ex,Im}portStore.
libcanvas/Canvas.py: minor cleanup.
libcanvas/CanvasExportStore.py:export{Ansi,Png}File(): merged from assets/tools/MiRCARTTo{Ansi,PngFile}.py.
libcanvas/CanvasImportStore.py:import{Ansi,Sauce}File(): merged from assets/tools/SAUCETo{Ansi,MiRCART}.py.
libcanvas/Colours.py:{AnsiBgToMiRCARTColours,AnsiFgToMiRCARTColours,AnsiFgBoldToMiRCARTColours}{}: merged from assets/tools/SAUCEToMiRCART.py.
libcanvas/Colours.py:{ColourMap{Bold,Normal}}[]: merged from assets/tools/MiRCARTToPngFile.py.
libcanvas/Colours.py: minor cleanup.
libgui/GuiCanvasInterface.py:canvas{ExportAsAnsi,Import{Ansi,Sauce}}(): implemented.
libgui/GuiFrame.py: adds CID_{EXPORT_AS_{ANSI,SAUCE},IMPORT_{ANSI,SAUCE}}.
assets/text/TODO: updated.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-05 16:55:07 +02:00
parent da8384f3bb
commit 045b7a24ed
11 changed files with 537 additions and 432 deletions

View File

@ -1,15 +1,14 @@
1) General {cleanup,refactor} 1) General {cleanup,refactor}
2) Incremental auto{load,save} & {backup,restore} 2) Implement ANSI CSI CU[BDPU] sequences
3) Open and toggle a reference image in the background 3) Incremental auto{load,save} & {backup,restore}
4) Client-Server or Peer-to-Peer realtime collaboration 4) Open and toggle a reference image in the background
5) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.) 5) Client-Server or Peer-to-Peer realtime collaboration
6) Hotkey & graphical interfaces to {composed,parametrised} tools 6) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.)
7) Layer, layout (e.g. for comics, zines, etc.) & {re,un}do canvas traits 7) Hotkey & graphical interfaces to {composed,parametrised} tools
8) GUI: a) scrollbar b) switch from wxPython to GTK c) revisit About dialogue 8) GUI: a) scrollbar b) switch from wxPython to GTK c) revisit About dialogue
9) {Insert,{ex,im}port}ing from/to ANSI, Blender, GIF, HTML, mIRC, printer, SAUCE, WEBM, etc. {clipboard,file} 9) Layers, layout (e.g. for comics, zines, etc.) & asset management (e.g. kade, lion, etc.) & traits w/ {inserting,merging,linking}
10) Asset management (e.g. kade, lion, etc.) & traits w/ simple linking & synchronised editing respecting layers 10) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...)
11) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...) 11) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools:
12) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools:
a) geometric primitives (arrow, circle, cloud/speech bubble, curve, heart, hexagon, line, pentagon, polygon, rhombus, triangle, square, star) a) geometric primitives (arrow, circle, cloud/speech bubble, curve, heart, hexagon, line, pentagon, polygon, rhombus, triangle, square, star)
b) regions (crop, duplicate, erase, fill, invert, measure, pick, rotate, scale, select, shift, slice, tile, translate) b) regions (crop, duplicate, erase, fill, invert, measure, pick, rotate, scale, select, shift, slice, tile, translate)
c) text (edit, Unicode sets) c) text (edit, Unicode sets)

View File

@ -8,59 +8,20 @@
import os, sys import os, sys
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]] [sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
from CanvasExportStore import CanvasExportStore
from CanvasImportStore import CanvasImportStore from CanvasImportStore import CanvasImportStore
MiRCARTToAnsiColours = [
97, # Bright White
30, # Black
94, # Light Blue
32, # Green
91, # Red
31, # Light Red
35, # Pink
33, # Yellow
93, # Light Yellow
92, # Light Green
36, # Cyan
96, # Light Cyan
34, # Blue
95, # Light Pink
90, # Grey
37, # Light Grey
];
def ToAnsi(inPathName):
canvasStore = CanvasImportStore(inPathName)
inMap = canvasStore.outMap.copy(); del canvasStore;
with open(inPathName, "w+") as outFile:
for inCurRow in range(len(inMap)):
lastAttribs = CanvasImportStore._CellState.CS_NONE
lastColours = None
for inCurCol in range(len(inMap[inCurRow])):
inCurCell = inMap[inCurRow][inCurCol]
if lastAttribs != inCurCell[2]:
if inCurCell[2] & CanvasImportStore._CellState.CS_BOLD:
print("\u001b[1m", end="", file=outFile)
if inCurCell[2] & CanvasImportStore._CellState.CS_UNDERLINE:
print("\u001b[4m", end="", file=outFile)
lastAttribs = inCurCell[2]
if lastColours == None or lastColours != inCurCell[:2]:
ansiBg = MiRCARTToAnsiColours[int(inCurCell[1])] + 10
ansiFg = MiRCARTToAnsiColours[int(inCurCell[0])]
print("\u001b[{:02d}m\u001b[{:02d}m{}".format(ansiBg, ansiFg, inCurCell[3]), end="", file=outFile)
lastColours = inCurCell[:2]
else:
print(inCurCell[3], end="", file=outFile)
print("\u001b[0m\n", end="", file=outFile)
# #
# Entry point # Entry point
def main(*argv): def main(*argv):
ToAnsi(argv[1])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 1: if (len(sys.argv) - 1) != 1:
print("usage: {} <MiRCART input file pathname>".format(sys.argv[0]), file=sys.stderr) print("usage: {} <MiRCART input file pathname>".format(sys.argv[0]), file=sys.stderr)
else: else:
canvasImportStore = CanvasImportStore()
canvasImportStore.importAnsiFile(argv[1])
canvasExportStore = CanvasExportStore()
canvasExportStore.exportAnsiFile(canvasImportStore.outMap, canvasImportStore.inSize, sys.stdout)
if __name__ == "__main__":
main(*sys.argv) main(*sys.argv)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -6,122 +6,11 @@
# #
import os, sys import os, sys
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl", "libtools"]] [sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
from CanvasExportStore import CanvasExportStore
from CanvasImportStore import CanvasImportStore from CanvasImportStore import CanvasImportStore
from getopt import getopt, GetoptError from getopt import getopt, GetoptError
from PIL import Image, ImageDraw, ImageFont
class MiRCARTToPngFile:
"""XXX"""
inFile = inFromTextFile = None
outFontFilePath = outFontSize = None
# {{{ _ColourMapBold: mIRC colour number to RGBA map given ^B (bold)
_ColourMapBold = [
[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
]
# }}}
# {{{ _ColourMapNormal: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline)
_ColourMapNormal = [
[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
]
# }}}
# {{{ _drawUnderline(self, curPos, fontSize, imgDraw, fillColour): XXX
def _drawUnderLine(self, curPos, fontSize, imgDraw, fillColour):
imgDraw.line( \
xy=(curPos[0], curPos[1] + (fontSize[1] - 2), \
curPos[0] + fontSize[0], curPos[1] + (fontSize[1] - 2)), \
fill=fillColour)
# }}}
# {{{ export(self, outFilePath): XXX
def export(self, outFilePath):
inSize = (len(self.inCanvasMap[0]), len(self.inCanvasMap))
outSize = [a*b for a,b in zip(inSize, self.outImgFontSize)]
outCurPos = [0, 0]
outImg = Image.new("RGBA", outSize, (*self._ColourMapNormal[1], 255))
outImgDraw = ImageDraw.Draw(outImg)
outImgDraw.fontmode = "1"
for inCurRow in range(len(self.inCanvasMap)):
for inCurCol in range(len(self.inCanvasMap[inCurRow])):
inCurCell = self.inCanvasMap[inCurRow][inCurCol]
outColours = [0, 0]
if inCurCell[2] & CanvasImportStore._CellState.CS_BOLD:
if inCurCell[3] != " ":
if inCurCell[3] == "":
outColours[1] = self._ColourMapNormal[inCurCell[0]]
else:
outColours[0] = self._ColourMapBold[inCurCell[0]]
outColours[1] = self._ColourMapNormal[inCurCell[1]]
else:
outColours[1] = self._ColourMapNormal[inCurCell[1]]
else:
if inCurCell[3] != " ":
if inCurCell[3] == "":
outColours[1] = self._ColourMapNormal[inCurCell[0]]
else:
outColours[0] = self._ColourMapNormal[inCurCell[0]]
outColours[1] = self._ColourMapNormal[inCurCell[1]]
else:
outColours[1] = self._ColourMapNormal[inCurCell[1]]
outImgDraw.rectangle((*outCurPos, \
outCurPos[0] + self.outImgFontSize[0], \
outCurPos[1] + self.outImgFontSize[1]), \
fill=(*outColours[1], 255))
if not inCurCell[3] in "" \
and outColours[0] != outColours[1]:
# XXX implement italic
outImgDraw.text(outCurPos, \
inCurCell[3], (*outColours[0], 255), self.outImgFont)
if inCurCell[2] & CanvasImportStore._CellState.CS_UNDERLINE:
outColours[0] = self._ColourMapNormal[inCurCell[0]]
self._drawUnderLine(outCurPos, \
self.outImgFontSize, \
outImgDraw, (*outColours[0], 255))
outCurPos[0] += self.outImgFontSize[0];
outCurPos[0] = 0
outCurPos[1] += self.outImgFontSize[1]
outImg.save(outFilePath);
# }}}
#
# __init__(self, inCanvasMap, fontFilePath, fontSize): initialisation method
def __init__(self, inCanvasMap, fontFilePath, fontSize):
self.inCanvasMap = inCanvasMap
self.outFontFilePath, self.outFontSize = fontFilePath, fontSize
self.outImgFont = ImageFont.truetype(self.outFontFilePath, self.outFontSize)
self.outImgFontSize = [*self.outImgFont.getsize(" ")]
self.outImgFontSize[1] += 3
# #
# Entry point # Entry point
@ -137,8 +26,10 @@ def main(*argv):
optdict["-f"] = os.path.join("..", "fonts", "DejaVuSansMono.ttf") optdict["-f"] = os.path.join("..", "fonts", "DejaVuSansMono.ttf")
optdict["-s"] = 11 if not "-s" in optdict else int(optdict["-s"]) optdict["-s"] = 11 if not "-s" in optdict else int(optdict["-s"])
for inFile in argv: for inFile in argv:
canvasStore, outFile = CanvasImportStore(inFile=inFile), os.path.splitext(inFile)[0] + ".png" canvasImportStore = CanvasImportStore()
MiRCARTToPngFile(canvasStore.outMap, fontFilePath=optdict["-f"], fontSize=optdict["-s"]).export(outFile) canvasImportStore.importTextFile(inFile)
canvasExportStore = CanvasExportStore()
canvasExportStore.exportPngFile(canvasImportStore.outMap, os.path.splitext(inFile)[0] + ".png", optdict["-f"], optdict["-s"])
if __name__ == "__main__": if __name__ == "__main__":
main(*sys.argv) main(*sys.argv)

View File

@ -5,52 +5,24 @@
# This project is licensed under the terms of the MIT licence. # This project is licensed under the terms of the MIT licence.
# #
import os, re, struct, sys import os, sys
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
def SAUCEToAnsi(inPathName, outPathName): from CanvasExportStore import CanvasExportStore
with open(inPathName, "rb") as inFile: from CanvasImportStore import CanvasImportStore
inFileStat = os.stat(inPathName)
inFile.seek(inFileStat.st_size - 128, 0)
inFile.seek(5 + 2 + 35 + 20 + 20 + 8 + 4, 1)
if (inFile.read(1) != b'\x01') \
or (inFile.read(1) != b'\x01'):
print("error: only character based ANSi SAUCE files are supported.", file=sys.stderr)
return 1
else:
width, height = struct.unpack("H", inFile.read(2))[0], struct.unpack("H", inFile.read(2))[0]
with open(outPathName, "w+") as outFile:
inFile.seek(0, 0)
inFileData, row, rowChars = inFile.read(inFileStat.st_size - 128).decode("cp437"), "", 0
inFileChar, inFileCharMax = 0, len(inFileData)
while True:
if inFileChar >= inFileCharMax:
break
else:
m = re.match('\x1b\[((?:\d{1,3};?)+)m', inFileData[inFileChar:])
if m:
row += m[0]; inFileChar += len(m[0]);
else:
m = re.match('\x1b\[(\d+)C', inFileData[inFileChar:])
if m:
row += m[0]; inFileChar += len(m[0]); rowChars += int(m[1]);
elif inFileData[inFileChar:inFileChar+2] == "\r\n":
inFileChar += 2; rowChars = width;
elif inFileData[inFileChar] == "\r" \
or inFileData[inFileChar] == "\n":
inFileChar += 1; rowChars = width;
else:
row += inFileData[inFileChar]; inFileChar += 1; rowChars += 1;
if rowChars >= width:
print(row, file=outFile); row = ""; rowChars = 0;
# #
# Entry point # Entry point
def main(*argv): def main(*argv):
SAUCEToAnsi(argv[1], argv[2])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 2: if (len(sys.argv) - 1) != 2:
print("usage: {} <SAUCE input file pathname> <ANSI output file pathname>".format(sys.argv[0]), file=sys.stderr) print("usage: {} <SAUCE input file pathname> <ANSI output file pathname>".format(sys.argv[0]), file=sys.stderr)
else: else:
canvasImportStore = CanvasImportStore()
canvasImportStore.importSauceFile(argv[1])
canvasExportStore = CanvasExportStore()
with open(argv[2], "w", encoding="utf-8") as outFile:
canvasExportStore.exportAnsiFile(canvasImportStore.outMap, canvasImportStore.inSize, outFile)
if __name__ == "__main__":
main(*sys.argv) main(*sys.argv)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -5,146 +5,24 @@
# This project is licensed under the terms of the MIT licence. # This project is licensed under the terms of the MIT licence.
# #
import os, re, struct, sys import os, sys
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
AnsiBgToMiRCARTColours = { from CanvasExportStore import CanvasExportStore
107: 0, # Bright White from CanvasImportStore import CanvasImportStore
40: 1, # Black
104: 2, # Blue
42: 3, # Green
101: 4, # Red
41: 5, # Light Red
45: 6, # Pink
43: 7, # Yellow
103: 8, # Light Yellow
102: 9, # Light Green
46: 10, # Cyan
106: 11, # Light Cyan
44: 12, # Light Blue
105: 13, # Light Pink
100: 14, # Grey
47: 15, # Light Grey
};
AnsiFgToMiRCARTColours = {
97: 0, # Bright White
30: 1, # Black
94: 2, # Blue
32: 3, # Green
91: 4, # Red
31: 5, # Light Red
35: 6, # Pink
33: 7, # Yellow
93: 8, # Light Yellow
92: 9, # Light Green
36: 10, # Cyan
96: 11, # Light Cyan
34: 12, # Light Blue
95: 13, # Light Pink
90: 14, # Grey
37: 15, # Light Grey
};
AnsiFgBoldToMiRCARTColours = {
97: 0, # Bright White
30: 14, # Grey
94: 12, # Light Blue
32: 9, # Light Green
91: 4, # Light Red
31: 4, # Light Red
35: 13, # Light Pink
33: 8, # Light Yellow
93: 8, # Light Yellow
92: 9, # Light Green
36: 11, # Light Cyan
96: 11, # Light Cyan
34: 12, # Light Blue
95: 13, # Light Pink
90: 14, # Grey
37: 0, # Bright White
};
def SAUCEToMiRCART(inPathName, outPathName):
with open(inPathName, "rb") as inFile:
inFileStat = os.stat(inPathName)
inFile.seek(inFileStat.st_size - 128, 0)
inFile.seek(5 + 2 + 35 + 20 + 20 + 8 + 4, 1)
if (inFile.read(1) != b'\x01') \
or (inFile.read(1) != b'\x01'):
print("error: only character based ANSi SAUCE files are supported.", file=sys.stderr)
return 1
else:
width, height = struct.unpack("H", inFile.read(2))[0], struct.unpack("H", inFile.read(2))[0]
with open(outPathName, "w+") as outFile:
inFile.seek(0, 0)
inFileData, row, rowChars = inFile.read(inFileStat.st_size - 128).decode("cp437"), "", 0
inFileChar, inFileCharMax = 0, len(inFileData)
curBg, curFg = 1, 15; curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37;
while True:
if inFileChar >= inFileCharMax:
break
else:
m = re.match('\x1b\[((?:\d{1,3};?)+)m', inFileData[inFileChar:])
if m:
newBg, newFg = -1, -1
for ansiCode in m[1].split(";"):
ansiCode = int(ansiCode)
if ansiCode == 0:
curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37; newBg, newFg = 1, 15;
elif ansiCode == 1:
curBoldAnsi, newFg = True, AnsiFgBoldToMiRCARTColours[curFgAnsi]
elif ansiCode == 2:
curBoldAnsi, newFg = False, AnsiFgToMiRCARTColours[curFgAnsi]
elif ansiCode == 7:
newBg, newFg = curFg, curBg; curBgAnsi, curFgAnsi = curFgAnsi, curBgAnsi;
elif ansiCode in AnsiBgToMiRCARTColours:
curBgAnsi, newBg = ansiCode, AnsiBgToMiRCARTColours[ansiCode]
elif ansiCode in AnsiFgToMiRCARTColours:
if curBoldAnsi:
newFg = AnsiFgBoldToMiRCARTColours[ansiCode]
else:
newFg = AnsiFgToMiRCARTColours[ansiCode]
curFgAnsi = ansiCode
elif ansiCode in AnsiFgBoldToMiRCARTColours:
curFgAnsi, newFg = ansiCode, AnsiFgBoldToMiRCARTColours[ansiCode]
if ((newBg != -1) and (newFg != -1)) \
and ((newBg == curFg) and (newFg == curBg)):
row += "\u0016"; curBg, curFg = newBg, newFg;
elif ((newBg != -1) and (newFg != -1)) \
and ((newBg != curBg) and (newFg != curFg)):
row += "\u0003{},{}".format(newFg, newBg); curBg, curFg = newBg, newFg;
elif (newBg != -1) and (newBg != curBg):
row += "\u0003{},{}".format(curFg, newBg); curBg = newBg;
elif (newFg != -1) and (newFg != curFg):
row += "\u0003{}".format(newFg); curFg = newFg;
inFileChar += len(m[0])
else:
m = re.match('\x1b\[(\d+)C', inFileData[inFileChar:])
if m:
row += m[0]; inFileChar += len(m[0]); rowChars += int(m[1]);
elif inFileData[inFileChar:inFileChar+2] == "\r\n":
inFileChar += 2; rowChars = width;
elif inFileData[inFileChar] == "\r" \
or inFileData[inFileChar] == "\n":
inFileChar += 1; rowChars = width;
else:
row += inFileData[inFileChar]; inFileChar += 1; rowChars += 1;
if rowChars >= width:
print(row, file=outFile); row = ""; rowChars = 0;
if (curBg != 1) and (curFg != 15):
row += "\u0003{},{}".format(curFg, curBg);
elif curBg != 1:
row += "\u0003{},{}".format(curFg, curBg);
elif curFg != 1:
row += "\u0003{}".format(curFg);
# #
# Entry point # Entry point
def main(*argv): def main(*argv):
SAUCEToMiRCART(argv[1], argv[2])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 2: if (len(sys.argv) - 1) != 2:
print("usage: {} <SAUCE input file pathname> <mIRC art output file pathname>".format(sys.argv[0]), file=sys.stderr) print("usage: {} <SAUCE input file pathname> <mIRC art output file pathname>".format(sys.argv[0]), file=sys.stderr)
else: else:
canvasImportStore = CanvasImportStore()
canvasImportStore.importSauceFile(argv[1])
canvasExportStore = CanvasExportStore()
with open(argv[2], "w", encoding="utf-8") as outFile:
canvasExportStore.exportTextFile(canvasImportStore.outMap, canvasImportStore.inSize, outFile)
if __name__ == "__main__":
main(*sys.argv) main(*sys.argv)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -6,7 +6,7 @@
from CanvasBackend import CanvasBackend from CanvasBackend import CanvasBackend
from CanvasJournal import CanvasJournal from CanvasJournal import CanvasJournal
from CanvasExportStore import CanvasExportStore, haveToPngFile, haveUrllib from CanvasExportStore import CanvasExportStore, havePIL, haveUrllib
from CanvasImportStore import CanvasImportStore from CanvasImportStore import CanvasImportStore
from ImgurApiKey import ImgurApiKey from ImgurApiKey import ImgurApiKey
import wx import wx
@ -183,7 +183,7 @@ class Canvas(wx.Panel):
self.canvasBackend = CanvasBackend(defaultCanvasSize, defaultCellSize) self.canvasBackend = CanvasBackend(defaultCanvasSize, defaultCellSize)
self.canvasJournal = CanvasJournal() self.canvasJournal = CanvasJournal()
self.canvasExportStore = CanvasExportStore(parentCanvas=self) self.canvasExportStore = CanvasExportStore()
self.canvasImportStore = CanvasImportStore(parentCanvas=self) self.canvasImportStore = CanvasImportStore(parentCanvas=self)
self.canvasInterface = canvasInterface(self, parentFrame) self.canvasInterface = canvasInterface(self, parentFrame)

View File

@ -4,13 +4,14 @@
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de> # Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
# #
from Colours import ColourMapBold, ColourMapNormal, MiRCARTToAnsiColours
import io, os, tempfile import io, os, tempfile
try: try:
from ToPngFile import ToPngFile from PIL import Image, ImageDraw, ImageFont
haveToPngFile = True havePIL = True
except ImportError: except ImportError:
haveToPngFile = False havePIL = False
try: try:
import base64, json, requests, urllib.request import base64, json, requests, urllib.request
@ -20,9 +21,23 @@ except ImportError:
class CanvasExportStore(): class CanvasExportStore():
"""XXX""" """XXX"""
# {{{ _CellState(): Cell state
class _CellState():
CS_NONE = 0x00
CS_BOLD = 0x01
CS_ITALIC = 0x02
CS_UNDERLINE = 0x04
# }}}
ImgurUploadUrl = "https://api.imgur.com/3/upload.json" ImgurUploadUrl = "https://api.imgur.com/3/upload.json"
PastebinPostUrl = "https://pastebin.com/api/api_post.php" PastebinPostUrl = "https://pastebin.com/api/api_post.php"
# {{{ _drawUnderline(self, curPos, fontSize, imgDraw, fillColour): XXX
def _drawUnderLine(self, curPos, fontSize, imgDraw, fillColour):
imgDraw.line( \
xy=(curPos[0], curPos[1] + (fontSize[1] - 2), \
curPos[0] + fontSize[0], curPos[1] + (fontSize[1] - 2)), \
fill=fillColour)
# }}}
# {{{ _exportFileToImgur(self, apiKey, imgName, imgTitle, pathName): upload single PNG file to Imgur # {{{ _exportFileToImgur(self, apiKey, imgName, imgTitle, pathName): upload single PNG file to Imgur
def _exportFileToImgur(self, apiKey, imgName, imgTitle, pathName): def _exportFileToImgur(self, apiKey, imgName, imgTitle, pathName):
with open(pathName, "rb") as requestImage: with open(pathName, "rb") as requestImage:
@ -42,6 +57,30 @@ class CanvasExportStore():
return [responseHttp.status_code, ""] return [responseHttp.status_code, ""]
# }}} # }}}
# {{{ exportAnsiFile(self, canvasMap, canvasSize, outFile): XXX
def exportAnsiFile(self, canvasMap, canvasSize, outFile):
outBuffer = ""
for inCurRow in range(len(canvasMap)):
lastAttribs = self._CellState.CS_NONE
lastColours = None
for inCurCol in range(len(canvasMap[inCurRow])):
inCurCell = canvasMap[inCurRow][inCurCol]
if lastAttribs != inCurCell[2]:
if inCurCell[2] & self._CellState.CS_BOLD:
outBuffer += "\u001b[1m"
if inCurCell[2] & self._CellState.CS_UNDERLINE:
outBuffer += "\u001b[4m"
lastAttribs = inCurCell[2]
if lastColours == None or lastColours != inCurCell[:2]:
ansiBg = MiRCARTToAnsiColours[int(inCurCell[1])] + 10
ansiFg = MiRCARTToAnsiColours[int(inCurCell[0])]
outBuffer += "\u001b[{:02d}m\u001b[{:02d}m{}".format(ansiBg, ansiFg, inCurCell[3])
lastColours = inCurCell[:2]
else:
outBuffer += inCurCell[3]
outBuffer += "\u001b[0m\n"
outFile.write(outBuffer)
# }}}
# {{{ exportBitmapToImgur(self, apiKey, canvasBitmap, imgName, imgTitle, imgType): XXX # {{{ exportBitmapToImgur(self, apiKey, canvasBitmap, imgName, imgTitle, imgType): XXX
def exportBitmapToImgur(self, apiKey, canvasBitmap, imgName, imgTitle, imgType): def exportBitmapToImgur(self, apiKey, canvasBitmap, imgName, imgTitle, imgType):
tmpPathName = tempfile.mkstemp() tmpPathName = tempfile.mkstemp()
@ -77,10 +116,53 @@ class CanvasExportStore():
else: else:
return (False, "missing requests and/or urllib3 module(s)") return (False, "missing requests and/or urllib3 module(s)")
# }}} # }}}
# {{{ exportPngFile(self, canvasMap, outPathName): XXX # {{{ exportPngFile(self, canvasMap, outPathName, fontFilePath, fontSize): XXX
def exportPngFile(self, canvasMap, outPathName): def exportPngFile(self, canvasMap, outPathName, fontFilePath, fontSize):
if haveToPngFile: if havePIL:
ToPngFile(canvasMap).export(outPathName) outFontFilePath, outFontSize = fontFilePath, fontSize
outImgFont = ImageFont.truetype(outFontFilePath, outFontSize)
outImgFontSize = [*outImgFont.getsize(" ")]
outImgFontSize[1] += 3
inSize = (len(canvasMap[0]), len(canvasMap))
outSize = [a*b for a,b in zip(inSize, outImgFontSize)]
outCurPos = [0, 0]
outImg = Image.new("RGBA", outSize, (*ColourMapNormal[1], 255))
outImgDraw = ImageDraw.Draw(outImg)
outImgDraw.fontmode = "1"
for inCurRow in range(len(canvasMap)):
for inCurCol in range(len(canvasMap[inCurRow])):
inCurCell = canvasMap[inCurRow][inCurCol]
outColours = [0, 0]
if inCurCell[2] & self._CellState.CS_BOLD:
if inCurCell[3] != " ":
if inCurCell[3] == "":
outColours[1] = ColourMapNormal[inCurCell[0]]
else:
outColours[0] = ColourMapBold[inCurCell[0]]
outColours[1] = ColourMapNormal[inCurCell[1]]
else:
outColours[1] = ColourMapNormal[inCurCell[1]]
else:
if inCurCell[3] != " ":
if inCurCell[3] == "":
outColours[1] = ColourMapNormal[inCurCell[0]]
else:
outColours[0] = ColourMapNormal[inCurCell[0]]
outColours[1] = ColourMapNormal[inCurCell[1]]
else:
outColours[1] = ColourMapNormal[inCurCell[1]]
outImgDraw.rectangle((*outCurPos, outCurPos[0] + outImgFontSize[0], outCurPos[1] + outImgFontSize[1]), fill=(*outColours[1], 255))
if not inCurCell[3] in "" \
and outColours[0] != outColours[1]:
# XXX implement italic
outImgDraw.text(outCurPos, inCurCell[3], (*outColours[0], 255), outImgFont)
if inCurCell[2] & self._CellState.CS_UNDERLINE:
outColours[0] = ColourMapNormal[inCurCell[0]]
self._drawUnderLine(outCurPos, outImgFontSize, outImgDraw, (*outColours[0], 255))
outCurPos[0] += outImgFontSize[0];
outCurPos[0] = 0
outCurPos[1] += outImgFontSize[1]
outImg.save(outPathName);
return True return True
else: else:
return False return False
@ -117,9 +199,4 @@ class CanvasExportStore():
outFile.write(outBuffer) outFile.write(outBuffer)
# }}} # }}}
#
# __init__(self, parentCanvas): initialisation method
def __init__(self, parentCanvas):
self.parentCanvas = parentCanvas
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -5,23 +5,24 @@
# This project is licensed under the terms of the MIT licence. # This project is licensed under the terms of the MIT licence.
# #
from Colours import AnsiBgToMiRCARTColours, AnsiFgToMiRCARTColours, AnsiFgBoldToMiRCARTColours
import os, re, struct, sys
class CanvasImportStore(): class CanvasImportStore():
"""XXX""" """XXX"""
# {{{ _CellState(): Cell state
#
# _CellState(): Cell state
class _CellState(): class _CellState():
CS_NONE = 0x00 CS_NONE = 0x00
CS_BOLD = 0x01 CS_BOLD = 0x01
CS_ITALIC = 0x02 CS_ITALIC = 0x02
CS_UNDERLINE = 0x04 CS_UNDERLINE = 0x04
# }}}
# # {{{ _ParseState(): Parsing loop state
# _ParseState(): Parsing loop state
class _ParseState(): class _ParseState():
PS_CHAR = 1 PS_CHAR = 1
PS_COLOUR_DIGIT0 = 2 PS_COLOUR_DIGIT0 = 2
PS_COLOUR_DIGIT1 = 3 PS_COLOUR_DIGIT1 = 3
# }}}
# {{{ _flipCellStateBit(self, cellState, bit): XXX # {{{ _flipCellStateBit(self, cellState, bit): XXX
def _flipCellStateBit(self, cellState, bit): def _flipCellStateBit(self, cellState, bit):
@ -41,6 +42,77 @@ class CanvasImportStore():
return (15, 1) return (15, 1)
# }}} # }}}
# {{{ importAnsiFile(self, inPathName, encoding="cp437"): XXX
def importAnsiFile(self, inPathName, encoding="cp437"):
return self.importAnsiFileBuffer(open(inPathName, "rb"), encoding)
# }}}
# {{{ importAnsiFileBuffer(self, inFile, encoding="cp437"): XXX
def importAnsiFileBuffer(self, inFile, encoding="cp437"):
self.inSize, self.outMap = None, None; inMaxCols, inSize, outMap = 0, [0, 0], [[]];
inFileData, row, rowChars = inFile.read().decode(encoding), "", 0
inFileChar, inFileCharMax = 0, len(inFileData)
curBg, curFg, done, inCurRow = 1, 15, False, 0; curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37;
while True:
if inFileChar >= inFileCharMax:
break
else:
m = re.match('\x1b\[((?:\d{1,3};?)+)m', inFileData[inFileChar:])
if m:
newBg, newFg = -1, -1
for ansiCode in m[1].split(";"):
ansiCode = int(ansiCode)
if ansiCode == 0:
curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37; newBg, newFg = 1, 15;
elif ansiCode == 1:
curBoldAnsi, newFg = True, AnsiFgBoldToMiRCARTColours[curFgAnsi]
elif ansiCode == 2:
curBoldAnsi, newFg = False, AnsiFgToMiRCARTColours[curFgAnsi]
elif ansiCode == 7:
newBg, newFg = curFg, curBg; curBgAnsi, curFgAnsi = curFgAnsi, curBgAnsi;
elif ansiCode in AnsiBgToMiRCARTColours:
curBgAnsi, newBg = ansiCode, AnsiBgToMiRCARTColours[ansiCode]
elif ansiCode in AnsiFgToMiRCARTColours:
if curBoldAnsi:
newFg = AnsiFgBoldToMiRCARTColours[ansiCode]
else:
newFg = AnsiFgToMiRCARTColours[ansiCode]
curFgAnsi = ansiCode
elif ansiCode in AnsiFgBoldToMiRCARTColours:
curFgAnsi, newFg = ansiCode, AnsiFgBoldToMiRCARTColours[ansiCode]
if ((newBg != -1) and (newFg != -1)) \
and ((newBg == curFg) and (newFg == curBg)):
curBg, curFg = newBg, newFg
elif ((newBg != -1) and (newFg != -1)) \
and ((newBg != curBg) and (newFg != curFg)):
curBg, curFg = newBg, newFg
elif (newBg != -1) and (newBg != curBg):
curBg = newBg
elif (newFg != -1) and (newFg != curFg):
curFg = newFg
inFileChar += len(m[0])
else:
m = re.match('\x1b\[(\d+)C', inFileData[inFileChar:])
if m:
for numRepeat in range(int(m[1])):
outMap[inCurRow].append([curFg, curBg, self._CellState.CS_NONE, " "])
inFileChar += len(m[0])
elif inFileData[inFileChar:inFileChar+2] == "\r\n":
inFileChar += 2; done = True;
elif inFileData[inFileChar] == "\r" \
or inFileData[inFileChar] == "\n":
inFileChar += 1; done = True;
else:
outMap[inCurRow].append([curFg, curBg, self._CellState.CS_NONE, inFileData[inFileChar]])
inFileChar += 1; rowChars += 1;
if done:
inMaxCols = max(inMaxCols, len(outMap[inCurRow])); inSize[1] += 1;
done = False; rowChars = 0; inCurRow += 1; outMap.append([]);
inSize[0] = inMaxCols
for numRow in range(inSize[1]):
for numCol in range(len(outMap[numRow]), inSize[0]):
outMap[numRow].append([curFg, curBg, self._CellState.CS_NONE, " "])
self.inSize, self.outMap = inSize, outMap
# }}}
# {{{ importIntoPanel(self): XXX # {{{ importIntoPanel(self): XXX
def importIntoPanel(self): def importIntoPanel(self):
self.parentCanvas.onStoreUpdate(self.inSize, self.outMap) self.parentCanvas.onStoreUpdate(self.inSize, self.outMap)
@ -52,6 +124,81 @@ class CanvasImportStore():
for y in range(newCanvasSize[1])] for y in range(newCanvasSize[1])]
self.parentCanvas.onStoreUpdate(newCanvasSize, newMap) self.parentCanvas.onStoreUpdate(newCanvasSize, newMap)
# }}} # }}}
# {{{ importSauceFile(self, inPathName): XXX
def importSauceFile(self, inPathName):
with open(inPathName, "rb") as inFile:
self.inSize, self.outMap = None, None; inMaxCols, inSize, outMap = 0, [0, 0], [[]];
inFileStat = os.stat(inPathName)
inFile.seek(inFileStat.st_size - 128, 0)
inFile.seek(5 + 2 + 35 + 20 + 20 + 8 + 4, 1)
if (inFile.read(1) == b'\x01') \
and (inFile.read(1) == b'\x01'):
width, height = struct.unpack("H", inFile.read(2))[0], struct.unpack("H", inFile.read(2))[0]
inFile.seek(0, 0)
inFileData, row, rowChars = inFile.read(inFileStat.st_size - 128).decode("cp437"), "", 0
inFileChar, inFileCharMax = 0, len(inFileData)
curBg, curFg, inCurRow = 1, 15, 0; curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37;
while True:
if inFileChar >= inFileCharMax:
break
else:
m = re.match('\x1b\[((?:\d{1,3};?)+)m', inFileData[inFileChar:])
if m:
newBg, newFg = -1, -1
for ansiCode in m[1].split(";"):
ansiCode = int(ansiCode)
if ansiCode == 0:
curBgAnsi, curBoldAnsi, curFgAnsi = 30, False, 37; newBg, newFg = 1, 15;
elif ansiCode == 1:
curBoldAnsi, newFg = True, AnsiFgBoldToMiRCARTColours[curFgAnsi]
elif ansiCode == 2:
curBoldAnsi, newFg = False, AnsiFgToMiRCARTColours[curFgAnsi]
elif ansiCode == 7:
newBg, newFg = curFg, curBg; curBgAnsi, curFgAnsi = curFgAnsi, curBgAnsi;
elif ansiCode in AnsiBgToMiRCARTColours:
curBgAnsi, newBg = ansiCode, AnsiBgToMiRCARTColours[ansiCode]
elif ansiCode in AnsiFgToMiRCARTColours:
if curBoldAnsi:
newFg = AnsiFgBoldToMiRCARTColours[ansiCode]
else:
newFg = AnsiFgToMiRCARTColours[ansiCode]
curFgAnsi = ansiCode
elif ansiCode in AnsiFgBoldToMiRCARTColours:
curFgAnsi, newFg = ansiCode, AnsiFgBoldToMiRCARTColours[ansiCode]
if ((newBg != -1) and (newFg != -1)) \
and ((newBg == curFg) and (newFg == curBg)):
curBg, curFg = newBg, newFg
elif ((newBg != -1) and (newFg != -1)) \
and ((newBg != curBg) and (newFg != curFg)):
curBg, curFg = newBg, newFg
elif (newBg != -1) and (newBg != curBg):
curBg = newBg
elif (newFg != -1) and (newFg != curFg):
curFg = newFg
inFileChar += len(m[0])
else:
m = re.match('\x1b\[(\d+)C', inFileData[inFileChar:])
if m:
for numRepeat in range(int(m[1])):
outMap[inCurRow].append([curFg, curBg, self._CellState.CS_NONE, " "])
inFileChar += len(m[0])
elif inFileData[inFileChar:inFileChar+2] == "\r\n":
inFileChar += 2; rowChars = width;
elif inFileData[inFileChar] == "\r" \
or inFileData[inFileChar] == "\n":
inFileChar += 1; rowChars = width;
else:
outMap[inCurRow].append([curFg, curBg, self._CellState.CS_NONE, inFileData[inFileChar]])
inFileChar += 1; rowChars += 1;
if rowChars >= width:
inMaxCols = max(inMaxCols, len(outMap[inCurRow])); inSize[1] += 1;
rowChars = 0; inCurRow += 1; outMap.append([]);
inSize[0] = inMaxCols
for numRow in range(inSize[1]):
for numCol in range(len(outMap[numRow]), inSize[0]):
outMap[numRow].append([curFg, curBg, self._CellState.CS_NONE, " "])
self.inSize, self.outMap = inSize, outMap
# }}}
# {{{ importTextFile(self, pathName): XXX # {{{ importTextFile(self, pathName): XXX
def importTextFile(self, pathName): def importTextFile(self, pathName):
return self.importTextFileBuffer(open(pathName, "r", encoding="utf-8-sig")) return self.importTextFileBuffer(open(pathName, "r", encoding="utf-8-sig"))

View File

@ -4,9 +4,107 @@
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de> # Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
# #
# # {{{ AnsiBgToMiRCARTColours: XXX
# Colours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline], AnsiBgToMiRCARTColours = {
# 107: 0, # Bright White
40: 1, # Black
104: 2, # Blue
42: 3, # Green
101: 4, # Red
41: 5, # Light Red
45: 6, # Pink
43: 7, # Yellow
103: 8, # Light Yellow
102: 9, # Light Green
46: 10, # Cyan
106: 11, # Light Cyan
44: 12, # Light Blue
105: 13, # Light Pink
100: 14, # Grey
47: 15, # Light Grey
};
# }}}
# {{{ AnsiFgBoldToMiRCARTColours: XXX
AnsiFgBoldToMiRCARTColours = {
97: 0, # Bright White
30: 14, # Grey
94: 12, # Light Blue
32: 9, # Light Green
91: 4, # Light Red
31: 4, # Light Red
35: 13, # Light Pink
33: 8, # Light Yellow
93: 8, # Light Yellow
92: 9, # Light Green
36: 11, # Light Cyan
96: 11, # Light Cyan
34: 12, # Light Blue
95: 13, # Light Pink
90: 14, # Grey
37: 0, # Bright White
};
# }}}
# {{{ AnsiFgToMiRCARTColours: XXX
AnsiFgToMiRCARTColours = {
97: 0, # Bright White
30: 1, # Black
94: 2, # Blue
32: 3, # Green
91: 4, # Red
31: 5, # Light Red
35: 6, # Pink
33: 7, # Yellow
93: 8, # Light Yellow
92: 9, # Light Green
36: 10, # Cyan
96: 11, # Light Cyan
34: 12, # Light Blue
95: 13, # Light Pink
90: 14, # Grey
37: 15, # Light Grey
};
# }}}
# {{{ ColourMapBold: mIRC colour number to RGBA map given ^B (bold)
ColourMapBold = [
[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
]
# }}}
# {{{ ColourMapNormal: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline)
ColourMapNormal = [
[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
]
# }}}
# {{{ Colours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline],
Colours = [ Colours = [
[255, 255, 255, 255, "White"], [255, 255, 255, 255, "White"],
[0, 0, 0, 255, "Black"], [0, 0, 0, 255, "Black"],
@ -24,6 +122,27 @@ Colours = [
[255, 85, 255, 255, "Pink"], [255, 85, 255, 255, "Pink"],
[85, 85, 85, 255, "Grey"], [85, 85, 85, 255, "Grey"],
[187, 187, 187, 255, "Light Grey"], [187, 187, 187, 255, "Light Grey"],
] ];
# }}}
# {{{ MiRCARTToAnsiColours: XXX
MiRCARTToAnsiColours = [
97, # Bright White
30, # Black
94, # Light Blue
32, # Green
91, # Red
31, # Light Red
35, # Pink
33, # Yellow
93, # Light Yellow
92, # Light Green
36, # Cyan
96, # Light Cyan
34, # Blue
95, # Light Pink
90, # Grey
37, # Light Grey
];
# }}}
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -115,9 +115,22 @@ class GuiCanvasInterface():
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor)) self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
return True return True
# }}} # }}}
# {{{ canvasExportAsAnsi(self, event): XXX
def canvasExportAsAnsi(self, event):
with wx.FileDialog(self.parentFrame, "Save As...", os.getcwd(), "", "ANSI files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL:
return False
else:
outPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
with open(outPathName, "w", encoding="utf-8") as outFile:
self.parentCanvas.canvasExportStore.exportAnsiFile(self.parentCanvas.canvasMap, self.parentCanvas.canvasSize, outFile)
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
return True
# }}}
# {{{ canvasExportAsPng(self, event): XXX # {{{ canvasExportAsPng(self, event): XXX
def canvasExportAsPng(self, event): def canvasExportAsPng(self, event):
with wx.FileDialog(self.parentFrame, "Save As...", os.getcwd(), "", "*.png", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog: with wx.FileDialog(self.parentFrame, "Save As...", os.getcwd(), "", "PNG (*.png)|*.png|All Files (*.*)|*.*", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL: if dialog.ShowModal() == wx.ID_CANCEL:
return False return False
else: else:
@ -166,6 +179,29 @@ class GuiCanvasInterface():
wx.MessageBox("Failed to export to Pastebin: " + pasteResult, \ wx.MessageBox("Failed to export to Pastebin: " + pasteResult, \
"Export to Pastebin", wx.OK|wx.ICON_EXCLAMATION) "Export to Pastebin", wx.OK|wx.ICON_EXCLAMATION)
# }}} # }}}
# {{{ canvasImportAnsi(self, event): XXX
def canvasImportAnsi(self, event):
if self.canvasPathName != None:
saveChanges = self._dialogSaveChanges()
if saveChanges == wx.ID_CANCEL:
return
elif saveChanges == wx.ID_NO:
pass
elif saveChanges == wx.ID_YES:
self.canvasSave(event)
with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", "ANSI files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*", wx.FD_OPEN) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL:
return False
else:
self.canvasPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasImportStore.importAnsiFile(self.canvasPathName)
self.parentCanvas.canvasImportStore.importIntoPanel()
self.canvasPathName = "(Imported)"
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="(Imported)", undoLevel=-1)
return True
# }}}
# {{{ canvasImportFromClipboard(self, event): XXX # {{{ canvasImportFromClipboard(self, event): XXX
def canvasImportFromClipboard(self, event): def canvasImportFromClipboard(self, event):
rc = False rc = False
@ -193,6 +229,29 @@ class GuiCanvasInterface():
with wx.MessageDialog(self.parentCanvas, "Clipboard does not contain text data and/or cannot be opened", "", wx.ICON_QUESTION | wx.OK | wx.OK_DEFAULT) as dialog: with wx.MessageDialog(self.parentCanvas, "Clipboard does not contain text data and/or cannot be opened", "", wx.ICON_QUESTION | wx.OK | wx.OK_DEFAULT) as dialog:
dialog.ShowModal() dialog.ShowModal()
# }}} # }}}
# {{{ canvasImportSauce(self, event): XXX
def canvasImportSauce(self, event):
if self.canvasPathName != None:
saveChanges = self._dialogSaveChanges()
if saveChanges == wx.ID_CANCEL:
return
elif saveChanges == wx.ID_NO:
pass
elif saveChanges == wx.ID_YES:
self.canvasSave(event)
with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", "SAUCE files (*.ans;*.txt)|*.ans;*.txt|All Files (*.*)|*.*", wx.FD_OPEN) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL:
return False
else:
self.canvasPathName = dialog.GetPath()
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasImportStore.importSauceFile(self.canvasPathName)
self.parentCanvas.canvasImportStore.importIntoPanel()
self.canvasPathName = "(Imported)"
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
self.parentFrame.onCanvasUpdate(pathName="(Imported)", undoLevel=-1)
return True
# }}}
# {{{ canvasIncrBrushHeight(self, event): XXX # {{{ canvasIncrBrushHeight(self, event): XXX
def canvasIncrBrushHeight(self, event): def canvasIncrBrushHeight(self, event):
self.parentCanvas.brushSize[1] += 1 self.parentCanvas.brushSize[1] += 1
@ -253,12 +312,12 @@ class GuiCanvasInterface():
pass pass
elif saveChanges == wx.ID_YES: elif saveChanges == wx.ID_YES:
self.canvasSave(event) self.canvasSave(event)
with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", \ with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*", wx.FD_OPEN) as dialog:
"*.txt", wx.FD_OPEN) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL: if dialog.ShowModal() == wx.ID_CANCEL:
return False return False
else: else:
self.canvasPathName = dialog.GetPath() self.canvasPathName = dialog.GetPath()
print(self.canvasPathName)
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasImportStore.importTextFile(self.canvasPathName) self.parentCanvas.canvasImportStore.importTextFile(self.canvasPathName)
self.parentCanvas.canvasImportStore.importIntoPanel() self.parentCanvas.canvasImportStore.importIntoPanel()
@ -282,7 +341,7 @@ class GuiCanvasInterface():
if self.canvasSaveAs(event) == False: if self.canvasSaveAs(event) == False:
return return
try: try:
with open(self.canvasPathName, "w") as outFile: with open(self.canvasPathName, "w", encoding="utf-8") as outFile:
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT)) self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasExportStore.exportTextFile( \ self.parentCanvas.canvasExportStore.exportTextFile( \
self.parentCanvas.canvasMap, \ self.parentCanvas.canvasMap, \
@ -294,8 +353,7 @@ class GuiCanvasInterface():
# }}} # }}}
# {{{ canvasSaveAs(self, event): XXX # {{{ canvasSaveAs(self, event): XXX
def canvasSaveAs(self, event): def canvasSaveAs(self, event):
with wx.FileDialog(self.parentCanvas, "Save As", os.getcwd(), "", \ with wx.FileDialog(self.parentCanvas, "Save As", os.getcwd(), "", "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog:
"*.txt", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL: if dialog.ShowModal() == wx.ID_CANCEL:
return False return False
else: else:

View File

@ -26,11 +26,14 @@ class GuiFrame(GuiGeneralFrame):
CID_SAVE = [0x0102, TID_COMMAND, "Save", "&Save", ["", wx.ART_FILE_SAVE], [wx.ACCEL_CTRL, ord("S")], None, GuiCanvasInterface.canvasSave] CID_SAVE = [0x0102, TID_COMMAND, "Save", "&Save", ["", wx.ART_FILE_SAVE], [wx.ACCEL_CTRL, ord("S")], None, GuiCanvasInterface.canvasSave]
CID_SAVEAS = [0x0103, TID_COMMAND, "Save As...", "Save &As...", ["", wx.ART_FILE_SAVE_AS], None, None, GuiCanvasInterface.canvasSaveAs] CID_SAVEAS = [0x0103, TID_COMMAND, "Save As...", "Save &As...", ["", wx.ART_FILE_SAVE_AS], None, None, GuiCanvasInterface.canvasSaveAs]
CID_EXPORT_CLIPB = [0x0104, TID_COMMAND, "Export to clipboard", "&Export to clipboard", None, None, None, GuiCanvasInterface.canvasExportToClipboard] CID_EXPORT_CLIPB = [0x0104, TID_COMMAND, "Export to clipboard", "&Export to clipboard", None, None, None, GuiCanvasInterface.canvasExportToClipboard]
CID_EXPORT_AS_PNG = [0x0105, TID_COMMAND, "Export as PNG...", "Export as PN&G...", None, None, None, GuiCanvasInterface.canvasExportAsPng] CID_EXPORT_AS_ANSI = [0x0105, TID_COMMAND, "Export as ANSI...", "Export as ANSI...", None, None, None, GuiCanvasInterface.canvasExportAsAnsi]
CID_EXPORT_IMGUR = [0x0106, TID_COMMAND, "Export to Imgur...", "Export to I&mgur...", None, None, haveUrllib, GuiCanvasInterface.canvasExportImgur] CID_EXPORT_AS_PNG = [0x0106, TID_COMMAND, "Export as PNG...", "Export as PN&G...", None, None, None, GuiCanvasInterface.canvasExportAsPng]
CID_EXPORT_PASTEBIN = [0x0107, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", None, None, haveUrllib, GuiCanvasInterface.canvasExportPastebin] CID_EXPORT_IMGUR = [0x0107, TID_COMMAND, "Export to Imgur...", "Export to I&mgur...", None, None, haveUrllib, GuiCanvasInterface.canvasExportImgur]
CID_IMPORT_CLIPB = [0x0108, TID_COMMAND, "Import from clipboard", "&Import from clipboard", None, None, None, GuiCanvasInterface.canvasImportFromClipboard] CID_EXPORT_PASTEBIN = [0x0108, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", None, None, haveUrllib, GuiCanvasInterface.canvasExportPastebin]
CID_EXIT = [0x0109, TID_COMMAND, "Exit", "E&xit", None, [wx.ACCEL_CTRL, ord("X")], None, GuiCanvasInterface.canvasExit] CID_IMPORT_ANSI = [0x0109, TID_COMMAND, "Import ANSI...", "Import ANSI...", None, None, None, GuiCanvasInterface.canvasImportAnsi]
CID_IMPORT_CLIPB = [0x010a, TID_COMMAND, "Import from clipboard", "&Import from clipboard", None, None, None, GuiCanvasInterface.canvasImportFromClipboard]
CID_IMPORT_SAUCE = [0x010b, TID_COMMAND, "Import SAUCE...", "Import SAUCE...", None, None, None, GuiCanvasInterface.canvasImportSauce]
CID_EXIT = [0x010c, TID_COMMAND, "Exit", "E&xit", None, [wx.ACCEL_CTRL, ord("X")], None, GuiCanvasInterface.canvasExit]
# #
# MID_EDIT # MID_EDIT
@ -92,7 +95,7 @@ class GuiFrame(GuiGeneralFrame):
CID_ABOUT = [0x0500, TID_COMMAND, "About", "&About", None, None, True, GuiCanvasInterface.canvasAbout] CID_ABOUT = [0x0500, TID_COMMAND, "About", "&About", None, None, True, GuiCanvasInterface.canvasAbout]
# }}} # }}}
# {{{ Menus (0x1100-0x1fff) # {{{ Menus (0x1100-0x1fff)
MID_FILE = (0x1100, TID_MENU, "File", "&File", (CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_MENU_SEP, CID_EXPORT_CLIPB, CID_EXPORT_AS_PNG, CID_EXPORT_IMGUR, CID_EXPORT_PASTEBIN, NID_MENU_SEP, CID_IMPORT_CLIPB, NID_MENU_SEP, CID_EXIT)) MID_FILE = (0x1100, TID_MENU, "File", "&File", (CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_MENU_SEP, CID_EXPORT_AS_ANSI, CID_EXPORT_CLIPB, CID_EXPORT_IMGUR, CID_EXPORT_PASTEBIN, CID_EXPORT_AS_PNG, NID_MENU_SEP, CID_IMPORT_ANSI, CID_IMPORT_CLIPB, CID_IMPORT_SAUCE, NID_MENU_SEP, CID_EXIT))
MID_EDIT = (0x1101, TID_MENU, "Edit", "&Edit", (CID_UNDO, CID_REDO, NID_MENU_SEP, CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, CID_INCRW_CANVAS, CID_DECRW_CANVAS, CID_INCRH_CANVAS, CID_DECRH_CANVAS, NID_MENU_SEP, CID_INCRHW_CANVAS, CID_DECRHW_CANVAS, NID_MENU_SEP, CID_INCRW_BRUSH, CID_DECRW_BRUSH, CID_INCRH_BRUSH, CID_DECRH_BRUSH, NID_MENU_SEP, CID_INCRHW_BRUSH, CID_DECRHW_BRUSH, NID_MENU_SEP, CID_SOLID_BRUSH)) MID_EDIT = (0x1101, TID_MENU, "Edit", "&Edit", (CID_UNDO, CID_REDO, NID_MENU_SEP, CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, CID_INCRW_CANVAS, CID_DECRW_CANVAS, CID_INCRH_CANVAS, CID_DECRH_CANVAS, NID_MENU_SEP, CID_INCRHW_CANVAS, CID_DECRHW_CANVAS, NID_MENU_SEP, CID_INCRW_BRUSH, CID_DECRW_BRUSH, CID_INCRH_BRUSH, CID_DECRH_BRUSH, NID_MENU_SEP, CID_INCRHW_BRUSH, CID_DECRHW_BRUSH, NID_MENU_SEP, CID_SOLID_BRUSH))
MID_TOOLS = (0x1102, TID_MENU, "Tools", "&Tools", (CID_RECT, CID_CIRCLE, CID_FILL, CID_LINE, CID_TEXT, CID_CLONE_SELECT, CID_MOVE_SELECT)) MID_TOOLS = (0x1102, TID_MENU, "Tools", "&Tools", (CID_RECT, CID_CIRCLE, CID_FILL, CID_LINE, CID_TEXT, CID_CLONE_SELECT, CID_MOVE_SELECT))
MID_HELP = (0x1103, TID_MENU, "Help", "&Help", (CID_ABOUT,)) MID_HELP = (0x1103, TID_MENU, "Help", "&Help", (CID_ABOUT,))