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

View File

@ -8,59 +8,20 @@
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
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
def main(*argv):
ToAnsi(argv[1])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 1:
print("usage: {} <MiRCART input file pathname>".format(sys.argv[0]), file=sys.stderr)
else:
main(*sys.argv)
canvasImportStore = CanvasImportStore()
canvasImportStore.importAnsiFile(argv[1])
canvasExportStore = CanvasExportStore()
canvasExportStore.exportAnsiFile(canvasImportStore.outMap, canvasImportStore.inSize, sys.stdout)
if __name__ == "__main__":
main(*sys.argv)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

@ -6,122 +6,11 @@
#
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 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
@ -137,8 +26,10 @@ def main(*argv):
optdict["-f"] = os.path.join("..", "fonts", "DejaVuSansMono.ttf")
optdict["-s"] = 11 if not "-s" in optdict else int(optdict["-s"])
for inFile in argv:
canvasStore, outFile = CanvasImportStore(inFile=inFile), os.path.splitext(inFile)[0] + ".png"
MiRCARTToPngFile(canvasStore.outMap, fontFilePath=optdict["-f"], fontSize=optdict["-s"]).export(outFile)
canvasImportStore = CanvasImportStore()
canvasImportStore.importTextFile(inFile)
canvasExportStore = CanvasExportStore()
canvasExportStore.exportPngFile(canvasImportStore.outMap, os.path.splitext(inFile)[0] + ".png", optdict["-f"], optdict["-s"])
if __name__ == "__main__":
main(*sys.argv)

View File

@ -5,52 +5,24 @@
# 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):
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)
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;
from CanvasExportStore import CanvasExportStore
from CanvasImportStore import CanvasImportStore
#
# Entry point
def main(*argv):
SAUCEToAnsi(argv[1], argv[2])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 2:
print("usage: {} <SAUCE input file pathname> <ANSI output file pathname>".format(sys.argv[0]), file=sys.stderr)
else:
main(*sys.argv)
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)
# 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.
#
import os, re, struct, sys
import os, sys
[sys.path.append(os.path.join(os.getcwd(), "..", "..", path)) for path in ["libcanvas", "librtl"]]
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
};
from CanvasExportStore import CanvasExportStore
from CanvasImportStore import CanvasImportStore
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
def main(*argv):
SAUCEToMiRCART(argv[1], argv[2])
if __name__ == "__main__":
if (len(sys.argv) - 1) != 2:
print("usage: {} <SAUCE input file pathname> <mIRC art output file pathname>".format(sys.argv[0]), file=sys.stderr)
else:
main(*sys.argv)
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)
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120

View File

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

View File

@ -4,13 +4,14 @@
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
#
from Colours import ColourMapBold, ColourMapNormal, MiRCARTToAnsiColours
import io, os, tempfile
try:
from ToPngFile import ToPngFile
haveToPngFile = True
from PIL import Image, ImageDraw, ImageFont
havePIL = True
except ImportError:
haveToPngFile = False
havePIL = False
try:
import base64, json, requests, urllib.request
@ -20,9 +21,23 @@ except ImportError:
class CanvasExportStore():
"""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"
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
def _exportFileToImgur(self, apiKey, imgName, imgTitle, pathName):
with open(pathName, "rb") as requestImage:
@ -42,6 +57,30 @@ class CanvasExportStore():
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
def exportBitmapToImgur(self, apiKey, canvasBitmap, imgName, imgTitle, imgType):
tmpPathName = tempfile.mkstemp()
@ -77,10 +116,53 @@ class CanvasExportStore():
else:
return (False, "missing requests and/or urllib3 module(s)")
# }}}
# {{{ exportPngFile(self, canvasMap, outPathName): XXX
def exportPngFile(self, canvasMap, outPathName):
if haveToPngFile:
ToPngFile(canvasMap).export(outPathName)
# {{{ exportPngFile(self, canvasMap, outPathName, fontFilePath, fontSize): XXX
def exportPngFile(self, canvasMap, outPathName, fontFilePath, fontSize):
if havePIL:
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
else:
return False
@ -117,9 +199,4 @@ class CanvasExportStore():
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

View File

@ -5,23 +5,24 @@
# This project is licensed under the terms of the MIT licence.
#
from Colours import AnsiBgToMiRCARTColours, AnsiFgToMiRCARTColours, AnsiFgBoldToMiRCARTColours
import os, re, struct, sys
class CanvasImportStore():
"""XXX"""
#
# _CellState(): Cell state
# {{{ _CellState(): Cell state
class _CellState():
CS_NONE = 0x00
CS_BOLD = 0x01
CS_ITALIC = 0x02
CS_UNDERLINE = 0x04
#
# _ParseState(): Parsing loop state
# }}}
# {{{ _ParseState(): Parsing loop state
class _ParseState():
PS_CHAR = 1
PS_COLOUR_DIGIT0 = 2
PS_COLOUR_DIGIT1 = 3
# }}}
# {{{ _flipCellStateBit(self, cellState, bit): XXX
def _flipCellStateBit(self, cellState, bit):
@ -41,6 +42,77 @@ class CanvasImportStore():
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
def importIntoPanel(self):
self.parentCanvas.onStoreUpdate(self.inSize, self.outMap)
@ -52,6 +124,81 @@ class CanvasImportStore():
for y in range(newCanvasSize[1])]
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
def importTextFile(self, pathName):
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>
#
#
# Colours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline],
#
# {{{ AnsiBgToMiRCARTColours: XXX
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 = [
[255, 255, 255, 255, "White"],
[0, 0, 0, 255, "Black"],
@ -24,6 +122,27 @@ Colours = [
[255, 85, 255, 255, "Pink"],
[85, 85, 85, 255, "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

View File

@ -115,9 +115,22 @@ class GuiCanvasInterface():
self.parentCanvas.SetCursor(wx.Cursor(wx.NullCursor))
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
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:
return False
else:
@ -166,6 +179,29 @@ class GuiCanvasInterface():
wx.MessageBox("Failed to export to Pastebin: " + pasteResult, \
"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
def canvasImportFromClipboard(self, event):
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:
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
def canvasIncrBrushHeight(self, event):
self.parentCanvas.brushSize[1] += 1
@ -253,12 +312,12 @@ class GuiCanvasInterface():
pass
elif saveChanges == wx.ID_YES:
self.canvasSave(event)
with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", \
"*.txt", wx.FD_OPEN) as dialog:
with wx.FileDialog(self.parentCanvas, "Open", os.getcwd(), "", "mIRC art files (*.txt)|*.txt|All Files (*.*)|*.*", wx.FD_OPEN) as dialog:
if dialog.ShowModal() == wx.ID_CANCEL:
return False
else:
self.canvasPathName = dialog.GetPath()
print(self.canvasPathName)
self.parentCanvas.SetCursor(wx.Cursor(wx.CURSOR_WAIT))
self.parentCanvas.canvasImportStore.importTextFile(self.canvasPathName)
self.parentCanvas.canvasImportStore.importIntoPanel()
@ -282,7 +341,7 @@ class GuiCanvasInterface():
if self.canvasSaveAs(event) == False:
return
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.canvasExportStore.exportTextFile( \
self.parentCanvas.canvasMap, \
@ -294,8 +353,7 @@ class GuiCanvasInterface():
# }}}
# {{{ canvasSaveAs(self, event): XXX
def canvasSaveAs(self, event):
with wx.FileDialog(self.parentCanvas, "Save As", os.getcwd(), "", \
"*.txt", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog:
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:
if dialog.ShowModal() == wx.ID_CANCEL:
return False
else:

View File

@ -20,79 +20,82 @@ class GuiFrame(GuiGeneralFrame):
# {{{ Commands (0x0100-0x0fff)
#
# MID_FILE
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_NEW = [0x0100, TID_COMMAND, "New", "&New", ["", wx.ART_NEW], [wx.ACCEL_CTRL, ord("N")], None, GuiCanvasInterface.canvasNew]
CID_OPEN = [0x0101, TID_COMMAND, "Open", "&Open", ["", wx.ART_FILE_OPEN], [wx.ACCEL_CTRL, ord("O")], None, GuiCanvasInterface.canvasOpen]
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_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_IMGUR = [0x0106, TID_COMMAND, "Export to Imgur...", "Export to I&mgur...", None, None, haveUrllib, GuiCanvasInterface.canvasExportImgur]
CID_EXPORT_PASTEBIN = [0x0107, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", None, None, haveUrllib, GuiCanvasInterface.canvasExportPastebin]
CID_IMPORT_CLIPB = [0x0108, TID_COMMAND, "Import from clipboard", "&Import from clipboard", None, None, None, GuiCanvasInterface.canvasImportFromClipboard]
CID_EXIT = [0x0109, TID_COMMAND, "Exit", "E&xit", None, [wx.ACCEL_CTRL, ord("X")], None, GuiCanvasInterface.canvasExit]
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_NEW = [0x0100, TID_COMMAND, "New", "&New", ["", wx.ART_NEW], [wx.ACCEL_CTRL, ord("N")], None, GuiCanvasInterface.canvasNew]
CID_OPEN = [0x0101, TID_COMMAND, "Open", "&Open", ["", wx.ART_FILE_OPEN], [wx.ACCEL_CTRL, ord("O")], None, GuiCanvasInterface.canvasOpen]
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_EXPORT_CLIPB = [0x0104, TID_COMMAND, "Export to clipboard", "&Export to clipboard", None, None, None, GuiCanvasInterface.canvasExportToClipboard]
CID_EXPORT_AS_ANSI = [0x0105, TID_COMMAND, "Export as ANSI...", "Export as ANSI...", None, None, None, GuiCanvasInterface.canvasExportAsAnsi]
CID_EXPORT_AS_PNG = [0x0106, TID_COMMAND, "Export as PNG...", "Export as PN&G...", None, None, None, GuiCanvasInterface.canvasExportAsPng]
CID_EXPORT_IMGUR = [0x0107, TID_COMMAND, "Export to Imgur...", "Export to I&mgur...", None, None, haveUrllib, GuiCanvasInterface.canvasExportImgur]
CID_EXPORT_PASTEBIN = [0x0108, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", None, None, haveUrllib, GuiCanvasInterface.canvasExportPastebin]
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
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_UNDO = [0x0200, TID_COMMAND, "Undo", "&Undo", ["", wx.ART_UNDO], [wx.ACCEL_CTRL, ord("Z")], False, GuiCanvasInterface.canvasUndo]
CID_REDO = [0x0201, TID_COMMAND, "Redo", "&Redo", ["", wx.ART_REDO], [wx.ACCEL_CTRL, ord("Y")], False, GuiCanvasInterface.canvasRedo]
CID_CUT = [0x0202, TID_COMMAND, "Cut", "Cu&t", ["", wx.ART_CUT], None, False, GuiCanvasInterface.canvasCut]
CID_COPY = [0x0203, TID_COMMAND, "Copy", "&Copy", ["", wx.ART_COPY], None, False, GuiCanvasInterface.canvasCopy]
CID_PASTE = [0x0204, TID_COMMAND, "Paste", "&Paste", ["", wx.ART_PASTE], None, False, GuiCanvasInterface.canvasPaste]
CID_DELETE = [0x0205, TID_COMMAND, "Delete", "De&lete", ["", wx.ART_DELETE], None, False, GuiCanvasInterface.canvasDelete]
CID_INCRW_CANVAS = [0x0206, TID_COMMAND, "Increase canvas width", "Increase canvas width", ["toolIncrCanvasW.png"], None, None, GuiCanvasInterface.canvasIncrCanvasWidth]
CID_DECRW_CANVAS = [0x0207, TID_COMMAND, "Decrease canvas width", "Decrease canvas width", ["toolDecrCanvasW.png"], None, None, GuiCanvasInterface.canvasDecrCanvasWidth]
CID_INCRH_CANVAS = [0x0208, TID_COMMAND, "Increase canvas height", "Increase canvas height", ["toolIncrCanvasH.png"], None, None, GuiCanvasInterface.canvasIncrCanvasHeight]
CID_DECRH_CANVAS = [0x0209, TID_COMMAND, "Decrease canvas height", "Decrease canvas height", ["toolDecrCanvasH.png"], None, None, GuiCanvasInterface.canvasDecrCanvasHeight]
CID_INCRHW_CANVAS = [0x020a, TID_COMMAND, "Increase canvas size", "Increase canvas size", ["toolIncrCanvasHW.png"], None, None, GuiCanvasInterface.canvasIncrCanvasHeightWidth]
CID_DECRHW_CANVAS = [0x020b, TID_COMMAND, "Decrease canvas size", "Decrease canvas size", ["toolDecrCanvasHW.png"], None, None, GuiCanvasInterface.canvasDecrCanvasHeightWidth]
CID_INCRW_BRUSH = [0x020c, TID_COMMAND, "Increase brush width", "Increase brush width", ["toolIncrBrushW.png"], None, None, GuiCanvasInterface.canvasIncrBrushWidth]
CID_DECRW_BRUSH = [0x020d, TID_COMMAND, "Decrease brush width", "Decrease brush width", ["toolDecrBrushW.png"], None, None, GuiCanvasInterface.canvasDecrBrushWidth]
CID_INCRH_BRUSH = [0x020e, TID_COMMAND, "Increase brush height", "Increase brush height", ["toolIncrBrushH.png"], None, None, GuiCanvasInterface.canvasIncrBrushHeight]
CID_DECRH_BRUSH = [0x020f, TID_COMMAND, "Decrease brush height", "Decrease brush height", ["toolDecrBrushH.png"], None, None, GuiCanvasInterface.canvasDecrBrushHeight]
CID_INCRHW_BRUSH = [0x0210, TID_COMMAND, "Increase brush size", "Increase brush size", ["toolIncrBrushHW.png"], None, None, GuiCanvasInterface.canvasIncrBrushHeightWidth]
CID_DECRHW_BRUSH = [0x0211, TID_COMMAND, "Decrease brush size", "Decrease brush size", ["toolDecrBrushHW.png"], None, None, GuiCanvasInterface.canvasDecrBrushHeightWidth]
CID_SOLID_BRUSH = [0x0212, TID_SELECT, "Solid brush", "Solid brush", None, None, True, GuiCanvasInterface.canvasBrushSolid]
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_UNDO = [0x0200, TID_COMMAND, "Undo", "&Undo", ["", wx.ART_UNDO], [wx.ACCEL_CTRL, ord("Z")], False, GuiCanvasInterface.canvasUndo]
CID_REDO = [0x0201, TID_COMMAND, "Redo", "&Redo", ["", wx.ART_REDO], [wx.ACCEL_CTRL, ord("Y")], False, GuiCanvasInterface.canvasRedo]
CID_CUT = [0x0202, TID_COMMAND, "Cut", "Cu&t", ["", wx.ART_CUT], None, False, GuiCanvasInterface.canvasCut]
CID_COPY = [0x0203, TID_COMMAND, "Copy", "&Copy", ["", wx.ART_COPY], None, False, GuiCanvasInterface.canvasCopy]
CID_PASTE = [0x0204, TID_COMMAND, "Paste", "&Paste", ["", wx.ART_PASTE], None, False, GuiCanvasInterface.canvasPaste]
CID_DELETE = [0x0205, TID_COMMAND, "Delete", "De&lete", ["", wx.ART_DELETE], None, False, GuiCanvasInterface.canvasDelete]
CID_INCRW_CANVAS = [0x0206, TID_COMMAND, "Increase canvas width", "Increase canvas width", ["toolIncrCanvasW.png"], None, None, GuiCanvasInterface.canvasIncrCanvasWidth]
CID_DECRW_CANVAS = [0x0207, TID_COMMAND, "Decrease canvas width", "Decrease canvas width", ["toolDecrCanvasW.png"], None, None, GuiCanvasInterface.canvasDecrCanvasWidth]
CID_INCRH_CANVAS = [0x0208, TID_COMMAND, "Increase canvas height", "Increase canvas height", ["toolIncrCanvasH.png"], None, None, GuiCanvasInterface.canvasIncrCanvasHeight]
CID_DECRH_CANVAS = [0x0209, TID_COMMAND, "Decrease canvas height", "Decrease canvas height", ["toolDecrCanvasH.png"], None, None, GuiCanvasInterface.canvasDecrCanvasHeight]
CID_INCRHW_CANVAS = [0x020a, TID_COMMAND, "Increase canvas size", "Increase canvas size", ["toolIncrCanvasHW.png"], None, None, GuiCanvasInterface.canvasIncrCanvasHeightWidth]
CID_DECRHW_CANVAS = [0x020b, TID_COMMAND, "Decrease canvas size", "Decrease canvas size", ["toolDecrCanvasHW.png"], None, None, GuiCanvasInterface.canvasDecrCanvasHeightWidth]
CID_INCRW_BRUSH = [0x020c, TID_COMMAND, "Increase brush width", "Increase brush width", ["toolIncrBrushW.png"], None, None, GuiCanvasInterface.canvasIncrBrushWidth]
CID_DECRW_BRUSH = [0x020d, TID_COMMAND, "Decrease brush width", "Decrease brush width", ["toolDecrBrushW.png"], None, None, GuiCanvasInterface.canvasDecrBrushWidth]
CID_INCRH_BRUSH = [0x020e, TID_COMMAND, "Increase brush height", "Increase brush height", ["toolIncrBrushH.png"], None, None, GuiCanvasInterface.canvasIncrBrushHeight]
CID_DECRH_BRUSH = [0x020f, TID_COMMAND, "Decrease brush height", "Decrease brush height", ["toolDecrBrushH.png"], None, None, GuiCanvasInterface.canvasDecrBrushHeight]
CID_INCRHW_BRUSH = [0x0210, TID_COMMAND, "Increase brush size", "Increase brush size", ["toolIncrBrushHW.png"], None, None, GuiCanvasInterface.canvasIncrBrushHeightWidth]
CID_DECRHW_BRUSH = [0x0211, TID_COMMAND, "Decrease brush size", "Decrease brush size", ["toolDecrBrushHW.png"], None, None, GuiCanvasInterface.canvasDecrBrushHeightWidth]
CID_SOLID_BRUSH = [0x0212, TID_SELECT, "Solid brush", "Solid brush", None, None, True, GuiCanvasInterface.canvasBrushSolid]
#
# MID_TOOLS
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_RECT = [0x0300, TID_SELECT, "Rectangle", "&Rectangle", ["toolRect.png"], [wx.ACCEL_CTRL, ord("R")], True, GuiCanvasInterface.canvasToolRect]
CID_CIRCLE = [0x0301, TID_SELECT, "Circle", "&Circle", ["toolCircle.png"], [wx.ACCEL_CTRL, ord("C")], False, GuiCanvasInterface.canvasToolCircle]
CID_FILL = [0x0302, TID_SELECT, "Fill", "&Fill", ["toolFill.png"], [wx.ACCEL_CTRL, ord("F")], False, GuiCanvasInterface.canvasToolFill]
CID_LINE = [0x0303, TID_SELECT, "Line", "&Line", ["toolLine.png"], [wx.ACCEL_CTRL, ord("L")], False, GuiCanvasInterface.canvasToolLine]
CID_TEXT = [0x0304, TID_SELECT, "Text", "&Text", ["toolText.png"], [wx.ACCEL_CTRL, ord("T")], False, GuiCanvasInterface.canvasToolText]
CID_CLONE_SELECT = [0x0305, TID_SELECT, "Clone", "Cl&one", ["toolClone.png"], [wx.ACCEL_CTRL, ord("E")], False, GuiCanvasInterface.canvasToolSelectClone]
CID_MOVE_SELECT = [0x0306, TID_SELECT, "Move", "&Move", ["toolMove.png"], [wx.ACCEL_CTRL, ord("M")], False, GuiCanvasInterface.canvasToolSelectMove]
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_RECT = [0x0300, TID_SELECT, "Rectangle", "&Rectangle", ["toolRect.png"], [wx.ACCEL_CTRL, ord("R")], True, GuiCanvasInterface.canvasToolRect]
CID_CIRCLE = [0x0301, TID_SELECT, "Circle", "&Circle", ["toolCircle.png"], [wx.ACCEL_CTRL, ord("C")], False, GuiCanvasInterface.canvasToolCircle]
CID_FILL = [0x0302, TID_SELECT, "Fill", "&Fill", ["toolFill.png"], [wx.ACCEL_CTRL, ord("F")], False, GuiCanvasInterface.canvasToolFill]
CID_LINE = [0x0303, TID_SELECT, "Line", "&Line", ["toolLine.png"], [wx.ACCEL_CTRL, ord("L")], False, GuiCanvasInterface.canvasToolLine]
CID_TEXT = [0x0304, TID_SELECT, "Text", "&Text", ["toolText.png"], [wx.ACCEL_CTRL, ord("T")], False, GuiCanvasInterface.canvasToolText]
CID_CLONE_SELECT = [0x0305, TID_SELECT, "Clone", "Cl&one", ["toolClone.png"], [wx.ACCEL_CTRL, ord("E")], False, GuiCanvasInterface.canvasToolSelectClone]
CID_MOVE_SELECT = [0x0306, TID_SELECT, "Move", "&Move", ["toolMove.png"], [wx.ACCEL_CTRL, ord("M")], False, GuiCanvasInterface.canvasToolSelectMove]
#
# BID_TOOLBAR
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_COLOUR00 = [0x0400, TID_SELECT, "Colour #00", "Colour #00", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR01 = [0x0401, TID_SELECT, "Colour #01", "Colour #01", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR02 = [0x0402, TID_SELECT, "Colour #02", "Colour #02", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR03 = [0x0403, TID_SELECT, "Colour #03", "Colour #03", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR04 = [0x0404, TID_SELECT, "Colour #04", "Colour #04", None, None, True, GuiCanvasInterface.canvasColour]
CID_COLOUR05 = [0x0405, TID_SELECT, "Colour #05", "Colour #05", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR06 = [0x0406, TID_SELECT, "Colour #06", "Colour #06", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR07 = [0x0407, TID_SELECT, "Colour #07", "Colour #07", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR08 = [0x0408, TID_SELECT, "Colour #08", "Colour #08", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR09 = [0x0409, TID_SELECT, "Colour #09", "Colour #09", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR10 = [0x040a, TID_SELECT, "Colour #10", "Colour #10", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR11 = [0x040b, TID_SELECT, "Colour #11", "Colour #11", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR12 = [0x040c, TID_SELECT, "Colour #12", "Colour #12", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR13 = [0x040d, TID_SELECT, "Colour #13", "Colour #13", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR14 = [0x040e, TID_SELECT, "Colour #14", "Colour #14", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR15 = [0x040f, TID_SELECT, "Colour #15", "Colour #15", None, None, False, GuiCanvasInterface.canvasColour]
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_COLOUR00 = [0x0400, TID_SELECT, "Colour #00", "Colour #00", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR01 = [0x0401, TID_SELECT, "Colour #01", "Colour #01", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR02 = [0x0402, TID_SELECT, "Colour #02", "Colour #02", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR03 = [0x0403, TID_SELECT, "Colour #03", "Colour #03", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR04 = [0x0404, TID_SELECT, "Colour #04", "Colour #04", None, None, True, GuiCanvasInterface.canvasColour]
CID_COLOUR05 = [0x0405, TID_SELECT, "Colour #05", "Colour #05", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR06 = [0x0406, TID_SELECT, "Colour #06", "Colour #06", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR07 = [0x0407, TID_SELECT, "Colour #07", "Colour #07", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR08 = [0x0408, TID_SELECT, "Colour #08", "Colour #08", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR09 = [0x0409, TID_SELECT, "Colour #09", "Colour #09", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR10 = [0x040a, TID_SELECT, "Colour #10", "Colour #10", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR11 = [0x040b, TID_SELECT, "Colour #11", "Colour #11", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR12 = [0x040c, TID_SELECT, "Colour #12", "Colour #12", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR13 = [0x040d, TID_SELECT, "Colour #13", "Colour #13", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR14 = [0x040e, TID_SELECT, "Colour #14", "Colour #14", None, None, False, GuiCanvasInterface.canvasColour]
CID_COLOUR15 = [0x040f, TID_SELECT, "Colour #15", "Colour #15", None, None, False, GuiCanvasInterface.canvasColour]
#
# MID_ABOUT
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_ABOUT = [0x0500, TID_COMMAND, "About", "&About", None, None, True, GuiCanvasInterface.canvasAbout]
# Id Type Id Labels Icon bitmap Accelerator [Initial state]
CID_ABOUT = [0x0500, TID_COMMAND, "About", "&About", None, None, True, GuiCanvasInterface.canvasAbout]
# }}}
# {{{ 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_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,))