From 4abf68e168a07b9870633b5db0c8fd51c3e76ce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucio=20Andr=C3=A9s=20Illanes=20Albornoz?= Date: Sun, 7 Jan 2018 02:08:35 +0100 Subject: [PATCH] MiRCART.py: hand off to MiRCARTFrame(). MiRCARTCanvas.py: split from MiRCART.py. MiRCARTCanvasJournal.py: split from MiRCART.py. MiRCARTColours.py: split from MiRCART.py. MiRCARTFrame.py: split from MiRCART.py. MiRCARTFromTextFile.py: initial implementation. MiRCARTToPastebin.py: initial implementation. MiRCARTToPngFile.py, IrcMiRCARTBot.py: renamed MiRC2png to MiRCARTToPngFile. MiRCARTToTextFile.py: split from MiRCART.py. MiRCARTTool.py: split from MiRCART.py. MiRCARTToolRect.py: split from MiRCART.py. README.md: updated. --- IrcMiRCARTBot.py | 5 +- MiRC2png.py | 256 -------------------- MiRCART.py | 516 +--------------------------------------- MiRCARTCanvas.py | 157 ++++++++++++ MiRCARTCanvasJournal.py | 105 ++++++++ MiRCARTColours.py | 47 ++++ MiRCARTFrame.py | 375 +++++++++++++++++++++++++++++ MiRCARTFromTextFile.py | 147 ++++++++++++ MiRCARTToPastebin.py | 55 +++++ MiRCARTToPngFile.py | 145 +++++++++++ MiRCARTToTextFile.py | 47 ++++ MiRCARTTool.py | 39 +++ MiRCARTToolRect.py | 52 ++++ README.md | 2 +- 14 files changed, 1177 insertions(+), 771 deletions(-) delete mode 100755 MiRC2png.py create mode 100644 MiRCARTCanvas.py create mode 100644 MiRCARTCanvasJournal.py create mode 100755 MiRCARTColours.py create mode 100644 MiRCARTFrame.py create mode 100644 MiRCARTFromTextFile.py create mode 100644 MiRCARTToPastebin.py create mode 100755 MiRCARTToPngFile.py create mode 100644 MiRCARTToTextFile.py create mode 100644 MiRCARTTool.py create mode 100644 MiRCARTToolRect.py diff --git a/IrcMiRCARTBot.py b/IrcMiRCARTBot.py index 4b9b4ca..6d75554 100755 --- a/IrcMiRCARTBot.py +++ b/IrcMiRCARTBot.py @@ -25,8 +25,9 @@ import base64 import os, sys, time import json -import IrcClient, MiRC2png +import IrcClient import requests, urllib.request +from MiRCARTToPngFile import MiRCARTToPngFile class IrcMiRCARTBot(IrcClient.IrcClient): """IRC<->MiRC2png bot""" @@ -138,7 +139,7 @@ class IrcMiRCARTBot(IrcClient.IrcClient): self._log("Unknown URL type specified!") self.queue("PRIVMSG", message[2], "4/!\\ Unknown URL type specified!") return - MiRC2png.MiRC2png(asciiTmpFilePath, imgTmpFilePath, "DejaVuSansMono.ttf", 11) + MiRCARTToPngFile(asciiTmpFilePath, "DejaVuSansMono.ttf", 11).export(imgTmpFilePath) imgurResponse = self._uploadToImgur(imgTmpFilePath, "MiRCART image", "MiRCART image", "c9a6efb3d7932fd") if imgurResponse[0] == 200: self._log("Uploaded as: {}".format(imgurResponse[1])) diff --git a/MiRC2png.py b/MiRC2png.py deleted file mode 100755 index ec5ca9d..0000000 --- a/MiRC2png.py +++ /dev/null @@ -1,256 +0,0 @@ -#!/usr/bin/env python3 -# -# MiRC2png.py -- convert ASCII w/ mIRC control codes to monospaced PNG (for EFnet #MiRCART) -# Copyright (c) 2018 Lucio Andrés Illanes Albornoz -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# - -from enum import Enum -from PIL import Image, ImageDraw, ImageFont -import string, sys - -class MiRC2png: - """Abstraction over ASCIIs containing mIRC control codes""" - inFilePath = inFile = None; - inLines = inColsMax = inRows = None; - - outFontFilePath = outFontSize = None; - outImg = outImgDraw = outImgFont = None; - outCurColourBg = outCurColourFg = None; - outCurX = outCurY = None; - - inCurBold = inCurItalic = inCurUnderline = None; - inCurColourSpec = None; - state = None; - inCurCol = inCurDigits = None; - - # {{{ _ColourMapBold: mIRC colour number to RGBA map given ^B (bold) - _ColourMapBold = [ - (255, 255, 255, 255), # White - (85, 85, 85, 255), # Grey - (85, 85, 255, 255), # Light Blue - (85, 255, 85, 255), # Light Green - (255, 85, 85, 255), # Light Red - (255, 85, 85, 255), # Light Red - (255, 85, 255, 255), # Pink - (255, 255, 85, 255), # Light Yellow - (255, 255, 85, 255), # Light Yellow - (85, 255, 85, 255), # Light Green - (85, 255, 255, 255), # Light Cyan - (85, 255, 255, 255), # Light Cyan - (85, 85, 255, 255), # Light Blue - (255, 85, 255, 255), # Pink - (85, 85, 85, 255), # Grey - (255, 255, 255, 255), # White - ] - # }}} - # {{{ _ColourMapNormal: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline) - _ColourMapNormal = [ - (255, 255, 255, 255), # White - (0, 0, 0, 255), # Black - (0, 0, 187, 255), # Blue - (0, 187, 0, 255), # Green - (255, 85, 85, 255), # Light Red - (187, 0, 0, 255), # Red - (187, 0, 187, 255), # Purple - (187, 187, 0, 255), # Yellow - (255, 255, 85, 255), # Light Yellow - (85, 255, 85, 255), # Light Green - (0, 187, 187, 255), # Cyan - (85, 255, 255, 255), # Light Cyan - (85, 85, 255, 255), # Light Blue - (255, 85, 255, 255), # Pink - (85, 85, 85, 255), # Grey - (187, 187, 187, 255), # Light Grey - ] - # }}} - # {{{ _State(Enum): Parsing loop state - class _State(Enum): - STATE_CHAR = 1 - STATE_COLOUR_SPEC = 2 - STATE_CSPEC_DIGIT0 = 2 - STATE_CSPEC_DIGIT1 = 3 - # }}} - - # {{{ _countChar(self, char): XXX - def _countChar(self, char): - return True - # }}} - # {{{ _countColourSpecState(self, colourSpec): XXX - def _countColourSpecState(self, colourSpec): - return 0 - # }}} - # {{{ _render(self): XXX - def _render(self): - self.outCurX = 0; self.outCurY = 0; - for inCurRow in range(0, len(self.inLines)): - self.inCurBold = 0; self.inCurItalic = 0; self.inCurUnderline = 0; - self.inCurColourSpec = ""; self._State = self._State.STATE_CHAR; - self.inCurCol = 0; self.inCurDigits = 0; - while self.inCurCol < len(self.inLines[inCurRow]): - if self._State == self._State.STATE_CHAR: - self._parseAsChar( \ - self.inLines[inCurRow][self.inCurCol], \ - self._syncChar) - elif self._State == self._State.STATE_CSPEC_DIGIT0 \ - or self._State == self._State.STATE_CSPEC_DIGIT1: \ - self._parseAsColourSpec( \ - self.inLines[inCurRow][self.inCurCol], \ - self._syncColourSpecState) - self.outCurX = 0; self.outCurY += self.outImgFontSize[1]; - # }}} - # {{{ _getMaxCols(self, lines): Calculate widest row in lines, ignoring non-printable & mIRC control code sequences - def _getMaxCols(self, lines): - maxCols = 0; - for inCurRow in range(0, len(lines)): - self.inCurBold = 0; self.inCurItalic = 0; self.inCurUnderline = 0; - self.inCurColourSpec = ""; self._State = self._State.STATE_CHAR; - self.inCurCol = 0; self.inCurDigits = 0; curRowCols = 0; - while self.inCurCol < len(self.inLines[inCurRow]): - if self._State == self._State.STATE_CHAR: - if self._parseAsChar( \ - self.inLines[inCurRow][self.inCurCol], self._countChar): - curRowCols += 1 - elif self._State == self._State.STATE_CSPEC_DIGIT0 \ - or self._State == self._State.STATE_CSPEC_DIGIT1: - self._parseAsColourSpec( \ - self.inLines[inCurRow][self.inCurCol], \ - self._countColourSpecState) - maxCols = max(maxCols, curRowCols) - return maxCols - # }}} - # {{{ _parseAsChar(self, char, fn): Parse single character as regular character and mutate state - def _parseAsChar(self, char, fn): - if char == "": - self._State = self._State.STATE_CSPEC_DIGIT0; self.inCurCol += 1; - return False - else: - self.inCurCol += 1; return fn(char); - # }}} - # {{{ _parseAsColourSpec(self, char, fn): Parse single character as mIRC colour control code sequence and mutate state - def _parseAsColourSpec(self, char, fn): - if self._State == self._State.STATE_CSPEC_DIGIT0 \ - and char == ",": - self.inCurColourSpec += char; self.inCurCol += 1; - self._State = self._State.STATE_CSPEC_DIGIT1; - self.inCurDigits = 0 - return [False] - elif self._State == self._State.STATE_CSPEC_DIGIT0 \ - and char in set("0123456789") \ - and self.inCurDigits <= 1: - self.inCurColourSpec += char; self.inCurCol += 1; - self.inCurDigits += 1 - return [False] - elif self._State == self._State.STATE_CSPEC_DIGIT1 \ - and char in set("0123456789") \ - and self.inCurDigits <= 1: - self.inCurColourSpec += char; self.inCurCol += 1; - self.inCurDigits += 1 - return [False] - else: - result = fn(self.inCurColourSpec) - self.inCurColourSpec = ""; self._State = self._State.STATE_CHAR; - self.inCurDigits = 0 - return [True, result] - # }}} - # {{{ _syncChar(self, char): XXX - def _syncChar(self, char): - if char == "": - self.inCurBold = 0 if self.inCurBold else 1; - elif char == "": - self.inCurItalic = 0 if self.inCurItalic else 1; - elif char == "": - self.inCurBold = 0; self.inCurItalic = 0; self.inCurUnderline = 0; - self.inCurColourSpec = ""; - elif char == "": - self.outCurColourBg, self.outCurColourFg = self.outCurColourFg, self.outCurColourBg; - elif char == "": - self.inCurUnderline = 0 if self.inCurUnderline else 1; - elif char == " ": - if self.inCurBold: - colourBg = self._ColourMapBold[self.outCurColourBg] - else: - colourBg = self._ColourMapNormal[self.outCurColourBg] - self.outImgDraw.rectangle(((self.outCurX, self.outCurY), (self.outCurX + self.outImgFontSize[0], self.outCurY + self.outImgFontSize[1])), fill=colourBg) - if self.inCurUnderline: - self.outImgDraw.line((self.outCurX, self.outCurY + (self.outImgFontSize[1] - 2), self.outCurX + self.outImgFontSize[0], self.outCurY + (self.outImgFontSize[1] - 2)), fill=colourFg) - self.outCurX += self.outImgFontSize[0]; - else: - if self.inCurBold: - colourBg = self._ColourMapBold[self.outCurColourBg] - colourFg = self._ColourMapBold[self.outCurColourFg] - else: - colourBg = self._ColourMapNormal[self.outCurColourBg] - colourFg = self._ColourMapNormal[self.outCurColourFg] - self.outImgDraw.rectangle(((self.outCurX, self.outCurY), (self.outCurX + self.outImgFontSize[0], self.outCurY + self.outImgFontSize[1])), fill=colourBg) - # XXX implement italic - self.outImgDraw.text((self.outCurX, self.outCurY), char, colourFg, self.outImgFont) - if self.inCurUnderline: - self.outImgDraw.line((self.outCurX, self.outCurY + (self.outImgFontSize[1] - 2), self.outCurX + self.outImgFontSize[0], self.outCurY + (self.outImgFontSize[1] - 2)), fill=colourFg) - self.outCurX += self.outImgFontSize[0]; - return True - # }}} - # {{{ _syncColourSpecState(self, colourSpec): XXX - def _syncColourSpecState(self, colourSpec): - if len(colourSpec) > 0: - colourSpec = colourSpec.split(",") - if len(colourSpec) == 2: - self.outCurColourFg = int(colourSpec[0]) - self.outCurColourBg = int(colourSpec[1] or self.outCurColourBg) - elif len(colourSpec) == 1: - self.outCurColourFg = int(colourSpec[0]) - else: - self.outCurColourBg = 1; self.outCurColourFg = 15; - return True - # }}} - - # - # __init__(self, inFilePath, imgFilePath, fontFilePath="DejaVuSansMono.ttf", fontSize=11): initialisation method - def __init__(self, inFilePath, imgFilePath, fontFilePath="DejaVuSansMono.ttf", fontSize=11): - self.inFilePath = inFilePath; self.inFile = open(inFilePath, "r"); - self.inLines = self.inFile.readlines() - self.inColsMax = self._getMaxCols(self.inLines) - self.inRows = len(self.inLines) - self.outFontFilePath = fontFilePath; self.outFontSize = int(fontSize); - self.outImgFont = ImageFont.truetype(self.outFontFilePath, self.outFontSize) - self.outImgFontSize = list(self.outImgFont.getsize(" ")); self.outImgFontSize[1] += 3; - self.outImg = Image.new("RGBA", (self.inColsMax * self.outImgFontSize[0], self.inRows * self.outImgFontSize[1]), self._ColourMapNormal[1]) - self.outImgDraw = ImageDraw.Draw(self.outImg) - self.outCurColourBg = 1; self.outCurColourFg = 15; - self._render() - self.inFile.close(); - self.outImg.save(imgFilePath); - -# -# Entry point -def main(*argv): - MiRC2png(*argv[1:]) -if __name__ == "__main__": - if ((len(sys.argv) - 1) < 2)\ - or ((len(sys.argv) - 1) > 4): - print("usage: {} " \ - " " \ - " " \ - "[] " \ - "[]".format(sys.argv[0]), file=sys.stderr) - else: - main(*sys.argv) - -# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCART.py b/MiRCART.py index 9095dd7..28e9d36 100755 --- a/MiRCART.py +++ b/MiRCART.py @@ -22,523 +22,15 @@ # SOFTWARE. # -import enum -import wx -import os, sys - -# {{{ mircColours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline) -mircColours = [ - (255, 255, 255, 255), # White - (0, 0, 0, 255), # Black - (0, 0, 187, 255), # Blue - (0, 187, 0, 255), # Green - (255, 85, 85, 255), # Light Red - (187, 0, 0, 255), # Red - (187, 0, 187, 255), # Purple - (187, 187, 0, 255), # Yellow - (255, 255, 85, 255), # Light Yellow - (85, 255, 85, 255), # Light Green - (0, 187, 187, 255), # Cyan - (85, 255, 255, 255), # Light Cyan - (85, 85, 255, 255), # Light Blue - (255, 85, 255, 255), # Pink - (85, 85, 85, 255), # Grey - (187, 187, 187, 255), # Light Grey -] -# }}} - -class MiRCARTCanvasJournal(): - """XXX""" - parentCanvas = None - patchesTmp = patchesUndo = patchesUndoLevel = None - - # {{{ _popTmp(self, eventDc, tmpDc): XXX - def _popTmp(self, eventDc, tmpDc): - if self.patchesTmp: - for patch in self.patchesTmp: - patch[2:] = self.parentCanvas._getMapCell([patch[0], patch[1]]) - self.parentCanvas.onJournalUpdate(True, \ - (patch[0:2]), patch, eventDc, tmpDc, (0, 0)) - self.patchesTmp = [] - # }}} - # {{{ _pushTmp(self, atPoint, patch): XXX - def _pushTmp(self, absMapPoint): - self.patchesTmp.append([*absMapPoint, None, None, None]) - # }}} - # {{{ _pushUndo(self, atPoint, patch): XXX - def _pushUndo(self, atPoint, patch, mapItem): - if self.patchesUndoLevel > 0: - del self.patchesUndo[0:self.patchesUndoLevel] - self.patchesUndoLevel = 0 - absMapPoint = self._relMapPointToAbsMapPoint((patch[0], patch[1]), atPoint) - self.patchesUndo.insert(0, ( \ - (absMapPoint[0], absMapPoint[1], mapItem[0], mapItem[1], mapItem[2]), \ - (absMapPoint[0], absMapPoint[1], patch[2], patch[3], patch[4]))) - # }}} - # {{{ _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): XXX - def _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): - return (atPoint[0] + relMapPoint[0], atPoint[1] + relMapPoint[1]) - # }}} - # {{{ merge(self, mapPatches, eventDc, tmpDc, atPoint): XXX - def merge(self, mapPatches, eventDc, tmpDc, atPoint): - for mapPatch in mapPatches: - mapPatchTmp = mapPatch[0] - if mapPatchTmp: - self._popTmp(eventDc, tmpDc) - for patch in mapPatch[1]: - absMapPoint = self._relMapPointToAbsMapPoint(patch[0:2], atPoint) - mapItem = self.parentCanvas._getMapCell(absMapPoint) - if mapPatchTmp: - self._pushTmp(absMapPoint) - self.parentCanvas.onJournalUpdate(mapPatchTmp, \ - absMapPoint, patch, eventDc, tmpDc, atPoint) - elif mapItem != patch[2:5]: - self._pushUndo(atPoint, patch, mapItem) - self.parentCanvas.onJournalUpdate(mapPatchTmp, \ - absMapPoint, patch, eventDc, tmpDc, atPoint) - # }}} - # {{{ redo(self): XXX - def redo(self): - if self.patchesUndoLevel > 0: - self.patchesUndoLevel -= 1 - redoPatch = self.patchesUndo[self.patchesUndoLevel][1] - self.parentCanvas.onJournalUpdate(False, \ - (redoPatch[0:2]), redoPatch, None, None, (0, 0)) - return True - else: - return False - # }}} - # {{{ undo(self): XXX - def undo(self): - if self.patchesUndo[self.patchesUndoLevel] != None: - undoPatch = self.patchesUndo[self.patchesUndoLevel][0] - self.patchesUndoLevel += 1 - self.parentCanvas.onJournalUpdate(False, \ - (undoPatch[0:2]), undoPatch, None, None, (0, 0)) - return True - else: - return False - # }}} - # {{{ __init__(self, parentCanvas): initialisation method - def __init__(self, parentCanvas): - self.parentCanvas = parentCanvas - self.patchesTmp = [] - self.patchesUndo = [None]; self.patchesUndoLevel = 0; - # }}} - -class MiRCARTCanvas(wx.Panel): - """XXX""" - parentFrame = None - canvasPos = canvasSize = canvasWinSize = cellPos = cellSize = None - canvasBitmap = canvasMap = canvasTools = None - mircBg = mircFg = mircBrushes = mircPens = None - canvasJournal = None - - # {{{ _drawPatch(self, patch, eventDc, tmpDc, atPoint): XXX - def _drawPatch(self, patch, eventDc, tmpDc, atPoint): - absPoint = self._relMapPointToAbsPoint((patch[0], patch[1]), atPoint) - brushFg = self.mircBrushes[patch[2]]; brushBg = self.mircBrushes[patch[3]]; - pen = self.mircPens[patch[2]] - for dc in (eventDc, tmpDc): - dc.SetBrush(brushFg); dc.SetBackground(brushBg); dc.SetPen(pen); - dc.DrawRectangle(absPoint[0], absPoint[1], self.cellSize[0], self.cellSize[1]) - # }}} - # {{{ _eventPointToMapPoint(self, eventPoint): XXX - def _eventPointToMapPoint(self, eventPoint): - rectX = eventPoint.x - (eventPoint.x % self.cellSize[0]) - rectY = eventPoint.y - (eventPoint.y % self.cellSize[1]) - mapX = int(rectX / self.cellSize[0] if rectX else 0) - mapY = int(rectY / self.cellSize[1] if rectY else 0) - return (mapX, mapY) - # }}} - # {{{ _getMapCell(self, absMapPoint): XXX - def _getMapCell(self, absMapPoint): - return self.canvasMap[absMapPoint[1]][absMapPoint[0]] - # }}} - # {{{ _relMapPointToAbsPoint(self, relMapPoint, atPoint): XXX - def _relMapPointToAbsPoint(self, relMapPoint, atPoint): - absX = (atPoint[0] + relMapPoint[0]) * self.cellSize[0] - absY = (atPoint[1] + relMapPoint[1]) * self.cellSize[1] - return (absX, absY) - # }}} - # {{{ _setMapCell(self, absMapPoint, colourFg, colourBg, char): XXX - def _setMapCell(self, absMapPoint, colourFg, colourBg, char): - self.canvasMap[absMapPoint[1]][absMapPoint[0]] = [colourFg, colourBg, char] - # }}} - - # {{{ onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): - def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): - if eventDc == None: - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - if tmpDc == None: - tmpDc.SelectObject(self.canvasBitmap) - if isTmp == True: - self._drawPatch(patch, eventDc, tmpDc, atPoint) - else: - self._setMapCell(absMapPoint, *patch[2:5]) - self._drawPatch(patch, eventDc, tmpDc, atPoint) - self.parentFrame.onCanvasUpdate() - # }}} - # {{{ onMouseEvent(self, event): XXX - def onMouseEvent(self, event): - eventObject = event.GetEventObject() - eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.canvasBitmap) - eventPoint = event.GetLogicalPosition(eventDc) - mapPoint = self._eventPointToMapPoint(eventPoint) - for tool in self.canvasTools: - mapPatches = tool.onMouseEvent(event, mapPoint, event.Dragging(), \ - event.LeftIsDown(), event.RightIsDown()) - self.canvasJournal.merge(mapPatches, eventDc, tmpDc, mapPoint) - # }}} - # {{{ onPaint(self, event): XXX - def onPaint(self, event): - eventDc = wx.BufferedPaintDC(self, self.canvasBitmap) - # }}} - # {{{ redo(self): XXX - def redo(self): - return self.canvasJournal.redo() - # }}} - # {{{ undo(self): XXX - def undo(self): - return self.canvasJournal.undo() - # }}} - # {{{ __init__(self, parent, parentFrame, canvasPos, cellSize, canvasSize, canvasTools): Initialisation method - def __init__(self, parent, parentFrame, canvasPos, cellSize, canvasSize, canvasTools): - self.parentFrame = parentFrame - canvasWinSize = (cellSize[0] * canvasSize[0], cellSize[1] * canvasSize[1]) - super().__init__(parent, pos=canvasPos, size=canvasWinSize) - self.canvasPos = canvasPos; self.canvasSize = canvasSize; self.canvasWinSize = canvasWinSize; - self.cellPos = (0, 0); self.cellSize = cellSize; - - self.canvasBitmap = wx.Bitmap(canvasWinSize) - self.canvasMap = [[[1, 1, " "] for x in range(canvasSize[0])] for y in range(canvasSize[1])] - self.canvasTools = [] - for canvasTool in canvasTools: - self.canvasTools.append(canvasTool(self)) - - self.mircBg = 1; self.mircFg = 4; - self.mircBrushes = [None for x in range(len(mircColours))] - self.mircPens = [None for x in range(len(mircColours))] - for mircColour in range(0, len(mircColours)): - self.mircBrushes[mircColour] = wx.Brush( \ - wx.Colour(mircColours[mircColour]), wx.BRUSHSTYLE_SOLID) - self.mircPens[mircColour] = wx.Pen( \ - wx.Colour(mircColours[mircColour]), 1) - - self.canvasJournal = MiRCARTCanvasJournal(self) - - self.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) - self.Bind(wx.EVT_MOTION, self.onMouseEvent) - self.Bind(wx.EVT_PAINT, self.onPaint) - self.Bind(wx.EVT_RIGHT_DOWN, self.onMouseEvent) - # }}} - -class MiRCARTTool(): - """XXX""" - parentCanvas = None - - # {{{ onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX - def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): - pass - # }}} - # {{{ __init__(self, parentCanvas): initialisation method - def __init__(self, parentCanvas): - self.parentCanvas = parentCanvas - # }}} - -class MiRCARTToolRect(MiRCARTTool): - """XXX""" - - # {{{ onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX - def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): - if isLeftDown: - return [[False, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]], - [True, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]]] - elif isRightDown: - return [[False, [[0, 0, \ - self.parentCanvas.mircBg, \ - self.parentCanvas.mircBg, " "]]], \ - [True, [[0, 0, \ - self.parentCanvas.mircBg, \ - self.parentCanvas.mircBg, " "]]]] - else: - return [[True, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]]] - # }}} - -class MiRCARTFrame(wx.Frame): - """XXX""" - panelSkin = panelCanvas = None - menuItemsById = menuBar = toolBar = accelTable = statusBar = None - - # {{{ Types - TID_COMMAND = (0x001) - TID_NOTHING = (0x002) - TID_MENU = (0x003) - TID_TOOLBAR = (0x004) - TID_ACCELS = (0x005) - # }}} - # {{{ Commands - # Id Type Id Labels Icon bitmap Accelerator - CID_NEW = (0x100, TID_COMMAND, "New", "&New", [wx.ART_NEW], None) - CID_OPEN = (0x101, TID_COMMAND, "Open", "&Open", [wx.ART_FILE_OPEN], None) - CID_SAVE = (0x102, TID_COMMAND, "Save", "&Save", [wx.ART_FILE_SAVE], None) - CID_SAVEAS = (0x103, TID_COMMAND, "Save As...", "Save &As...", [wx.ART_FILE_SAVE_AS], None) - CID_EXPORT_PASTEBIN = (0x104, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", (), None) - CID_EXPORT_AS_PNG = (0x105, TID_COMMAND, "Export as PNG...", "Export as PN&G...", (), None) - CID_EXIT = (0x106, TID_COMMAND, "Exit", "E&xit", (), None) - CID_UNDO = (0x107, TID_COMMAND, "Undo", "&Undo", [wx.ART_UNDO], (wx.ACCEL_CTRL, ord("Z"))) - CID_REDO = (0x108, TID_COMMAND, "Redo", "&Redo", [wx.ART_REDO], (wx.ACCEL_CTRL, ord("Y"))) - CID_CUT = (0x109, TID_COMMAND, "Cut", "Cu&t", [wx.ART_CUT], None) - CID_COPY = (0x10a, TID_COMMAND, "Copy", "&Copy", [wx.ART_COPY], None) - CID_PASTE = (0x10b, TID_COMMAND, "Paste", "&Paste", [wx.ART_PASTE], None) - CID_DELETE = (0x10c, TID_COMMAND, "Delete", "De&lete", [wx.ART_DELETE], None) - CID_INCRBRUSH = (0x10d, TID_COMMAND, "Increase brush size", "&Increase brush size", [wx.ART_PLUS], None) - CID_DECRBRUSH = (0x10e, TID_COMMAND, "Decrease brush size", "&Decrease brush size", [wx.ART_MINUS], None) - CID_SOLIDBRUSH = (0x10f, TID_COMMAND, "Solid brush", "&Solid brush", [None], None) - CID_RECT = (0x110, TID_COMMAND, "Rectangle", "&Rectangle", [None], None) - CID_CIRCLE = (0x111, TID_COMMAND, "Circle", "&Circle", [None], None) - CID_LINE = (0x112, TID_COMMAND, "Line", "&Line", [None], None) - CID_COLOUR00 = (0x113, TID_COMMAND, "Colour #00", "Colour #00", mircColours[0], None) - CID_COLOUR01 = (0x114, TID_COMMAND, "Colour #01", "Colour #01", mircColours[1], None) - CID_COLOUR02 = (0x115, TID_COMMAND, "Colour #02", "Colour #02", mircColours[2], None) - CID_COLOUR03 = (0x116, TID_COMMAND, "Colour #03", "Colour #03", mircColours[3], None) - CID_COLOUR04 = (0x117, TID_COMMAND, "Colour #04", "Colour #04", mircColours[4], None) - CID_COLOUR05 = (0x118, TID_COMMAND, "Colour #05", "Colour #05", mircColours[5], None) - CID_COLOUR06 = (0x119, TID_COMMAND, "Colour #06", "Colour #06", mircColours[6], None) - CID_COLOUR07 = (0x11a, TID_COMMAND, "Colour #07", "Colour #07", mircColours[7], None) - CID_COLOUR08 = (0x11b, TID_COMMAND, "Colour #08", "Colour #08", mircColours[8], None) - CID_COLOUR09 = (0x11c, TID_COMMAND, "Colour #09", "Colour #09", mircColours[9], None) - CID_COLOUR10 = (0x11d, TID_COMMAND, "Colour #10", "Colour #10", mircColours[10], None) - CID_COLOUR11 = (0x11e, TID_COMMAND, "Colour #11", "Colour #11", mircColours[11], None) - CID_COLOUR12 = (0x11f, TID_COMMAND, "Colour #12", "Colour #12", mircColours[12], None) - CID_COLOUR13 = (0x120, TID_COMMAND, "Colour #13", "Colour #13", mircColours[13], None) - CID_COLOUR14 = (0x121, TID_COMMAND, "Colour #14", "Colour #14", mircColours[14], None) - CID_COLOUR15 = (0x122, TID_COMMAND, "Colour #15", "Colour #15", mircColours[15], None) - # }}} - # {{{ Non-items - NID_MENU_SEP = (0x200, TID_NOTHING) - NID_TOOLBAR_SEP = (0x201, TID_NOTHING) - # }}} - # {{{ Menus - MID_FILE = (0x300, TID_MENU, "File", "&File", ( \ - CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_MENU_SEP, \ - CID_EXPORT_PASTEBIN, CID_EXPORT_AS_PNG, NID_MENU_SEP, \ - CID_EXIT)) - MID_EDIT = (0x301, TID_MENU, "Edit", "&Edit", ( \ - CID_UNDO, CID_REDO, NID_MENU_SEP, \ - CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, \ - CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLIDBRUSH)) - MID_TOOLS = (0x302, TID_MENU, "Tools", "&Tools", ( \ - CID_RECT, CID_CIRCLE, CID_LINE)) - # }}} - # {{{ Toolbars - BID_TOOLBAR = (0x400, TID_TOOLBAR, ( \ - CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_TOOLBAR_SEP, \ - CID_UNDO, CID_REDO, NID_TOOLBAR_SEP, \ - CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_TOOLBAR_SEP, \ - CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLIDBRUSH, NID_TOOLBAR_SEP, \ - CID_RECT, CID_CIRCLE, CID_LINE, NID_TOOLBAR_SEP, \ - CID_COLOUR00, CID_COLOUR01, CID_COLOUR02, CID_COLOUR03, CID_COLOUR04, \ - CID_COLOUR05, CID_COLOUR06, CID_COLOUR07, CID_COLOUR08, CID_COLOUR09, \ - CID_COLOUR10, CID_COLOUR11, CID_COLOUR12, CID_COLOUR13, CID_COLOUR14, \ - CID_COLOUR15)) - # }}} - # {{{ Accelerators (hotkeys) - AID_EDIT = (0x500, TID_ACCELS, (CID_UNDO, CID_REDO)) - # }}} - - # {{{ _drawIcon(self, solidColour): XXX - def _drawIcon(self, solidColour): - iconBitmap = wx.Bitmap((16,16)) - iconDc = wx.MemoryDC(); iconDc.SelectObject(iconBitmap); - iconBrush = wx.Brush(wx.Colour(solidColour), wx.BRUSHSTYLE_SOLID) - iconDc.SetBrush(iconBrush); iconDc.SetBackground(iconBrush); - iconDc.SetPen(wx.Pen(wx.Colour(solidColour), 1)) - iconDc.DrawRectangle(0, 0, 16, 16) - return iconBitmap - # }}} - # {{{ _initAccelTable(self, accelsDescr, handler): XXX - def _initAccelTable(self, accelsDescr, handler): - accelTableEntries = [wx.AcceleratorEntry() for n in range(0, len(accelsDescr[2]))] - for numAccel in range(0, len(accelsDescr[2])): - accelDescr = accelsDescr[2][numAccel] - if accelDescr[5] != None: - accelTableEntries[numAccel].Set(accelDescr[5][0], accelDescr[5][1], accelDescr[0]) - self.Bind(wx.EVT_MENU, handler, id=accelDescr[0]) - return accelTableEntries - # }}} - # {{{ _initMenus(self, menuBar, menusDescr, handler): XXX - def _initMenus(self, menuBar, menusDescr, handler): - for menuDescr in menusDescr: - menuWindow = wx.Menu() - for menuItem in menuDescr[4]: - if menuItem == self.NID_MENU_SEP: - menuWindow.AppendSeparator() - else: - menuItemWindow = menuWindow.Append(menuItem[0], menuItem[3], menuItem[2]) - self.menuItemsById[menuItem[0]] = menuItemWindow - self.Bind(wx.EVT_MENU, handler, menuItemWindow) - menuBar.Append(menuWindow, menuDescr[3]) - # }}} - # {{{ _initToolBars(self, toolBar, toolBarsDescr, handler): XXX - def _initToolBars(self, toolBar, toolBarsDescr, handler): - for toolBarDescr in toolBarsDescr: - for toolBarItem in toolBarDescr[2]: - if toolBarItem == self.NID_TOOLBAR_SEP: - toolBar.AddSeparator() - else: - if len(toolBarItem[4]) == 4: - toolBarItemIcon = self._drawIcon(toolBarItem[4]) - elif len(toolBarItem[4]) == 1 \ - and toolBarItem[4][0] != None: - toolBarItemIcon = wx.ArtProvider.GetBitmap( \ - toolBarItem[4][0], wx.ART_TOOLBAR, (16,16)) - else: - toolBarItemIcon = wx.ArtProvider.GetBitmap( \ - wx.ART_HELP, wx.ART_TOOLBAR, (16,16)) - toolBarItemWindow = self.toolBar.AddTool( \ - toolBarItem[0], toolBarItem[2], toolBarItemIcon) - self.Bind(wx.EVT_TOOL, handler, toolBarItemWindow) - self.Bind(wx.EVT_TOOL_RCLICKED, handler, toolBarItemWindow) - # }}} - # {{{ _saveAs(self, pathName): XXX - def _saveAs(self, pathName): - try: - with open(pathName, "w") as file: - canvasMap = self.panelCanvas.canvasMap - canvasHeight = self.panelCanvas.canvasSize[1] - canvasWidth = self.panelCanvas.canvasSize[0] - for canvasRow in range(0, canvasHeight): - colourLastBg = colourLastFg = None; - for canvasCol in range(0, canvasWidth): - canvasColBg = canvasMap[canvasRow][canvasCol][0] - canvasColFg = canvasMap[canvasRow][canvasCol][1] - canvasColText = canvasMap[canvasRow][canvasCol][2] - if colourLastBg != canvasColBg \ - or colourLastFg != canvasColFg: - colourLastBg = canvasColBg; colourLastFg = canvasColFg; - file.write("" + str(canvasColFg) + "," + str(canvasColBg)) - file.write(canvasColText) - file.write("\n") - return [True] - except IOError as error: - return [False, error] - # }}} - # {{{ _updateStatusBar(self): XXX - def _updateStatusBar(self): - text = "Foreground colour:" - text += " " + str(self.panelCanvas.mircFg) - text += " | " - text += "Background colour:" - text += " " + str(self.panelCanvas.mircBg) - self.statusBar.SetStatusText(text) - # }}} - - # {{{ onCanvasUpdate(self): XXX - def onCanvasUpdate(self): - if self.panelCanvas.canvasJournal.patchesUndo[self.panelCanvas.canvasJournal.patchesUndoLevel] != None: - self.menuItemsById[self.CID_UNDO[0]].Enable(True) - else: - self.menuItemsById[self.CID_UNDO[0]].Enable(False) - if self.panelCanvas.canvasJournal.patchesUndoLevel > 0: - self.menuItemsById[self.CID_REDO[0]].Enable(True) - else: - self.menuItemsById[self.CID_REDO[0]].Enable(False) - # }}} - # {{{ onFrameCommand(self, event): XXX - def onFrameCommand(self, event): - cid = event.GetId() - if cid == self.CID_NEW[0]: - pass - elif cid == self.CID_OPEN[0]: - pass - elif cid == self.CID_SAVE[0]: - pass - elif cid == self.CID_SAVEAS[0]: - with wx.FileDialog(self, self.CID_SAVEAS[2], os.getcwd(), "", \ - "*.txt", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog: - if dialog.ShowModal() == wx.ID_CANCEL: - return - else: - self._saveAs(dialog.GetPath()) - elif cid == self.CID_EXPORT_PASTEBIN[0]: - pass - elif cid == self.CID_EXPORT_AS_PNG[0]: - pass - elif cid == self.CID_EXIT[0]: - self.Close(True) - elif cid == self.CID_UNDO[0]: - self.panelCanvas.undo() - elif cid == self.CID_REDO[0]: - self.panelCanvas.redo() - elif cid == self.CID_CUT[0]: - pass - elif cid == self.CID_COPY[0]: - pass - elif cid == self.CID_PASTE[0]: - pass - elif cid == self.CID_DELETE[0]: - pass - elif cid == self.CID_INCRBRUSH[0]: - pass - elif cid == self.CID_DECRBRUSH[0]: - pass - elif cid == self.CID_SOLIDBRUSH[0]: - pass - elif cid == self.CID_RECT[0]: - pass - elif cid == self.CID_CIRCLE[0]: - pass - elif cid == self.CID_LINE[0]: - pass - elif cid >= self.CID_COLOUR00[0] \ - and cid <= self.CID_COLOUR15[0]: - numColour = cid - self.CID_COLOUR00[0] - if event.GetEventType() == wx.wxEVT_TOOL: - self.panelCanvas.mircFg = numColour - elif event.GetEventType() == wx.wxEVT_TOOL_RCLICKED: - self.panelCanvas.mircBg = numColour - self._updateStatusBar() - # }}} - # {{{ __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), cellSize=(7, 14), canvasSize=(80, 25)): initialisation method - def __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), cellSize=(7, 14), canvasSize=(80, 25)): - super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize) - self.panelSkin = wx.Panel(self, wx.ID_ANY) - self.panelCanvas = MiRCARTCanvas(self.panelSkin, \ - parentFrame=self, canvasPos=canvasPos, cellSize=cellSize, \ - canvasSize=canvasSize, canvasTools=[MiRCARTToolRect]) - - self.menuItemsById = {}; self.menuBar = wx.MenuBar(); - self._initMenus(self.menuBar, \ - [self.MID_FILE, self.MID_EDIT, self.MID_TOOLS], self.onFrameCommand) - self.SetMenuBar(self.menuBar) - - self.toolBar = wx.ToolBar(self.panelSkin, -1, \ - style=wx.HORIZONTAL|wx.TB_FLAT|wx.TB_NODIVIDER) - self.toolBar.SetToolBitmapSize((16,16)) - self._initToolBars(self.toolBar, [self.BID_TOOLBAR], self.onFrameCommand) - self.toolBar.Realize(); self.toolBar.Fit(); - - self.accelTable = wx.AcceleratorTable( \ - self._initAccelTable(self.AID_EDIT, self.onFrameCommand)) - self.SetAcceleratorTable(self.accelTable) - - self.statusBar = self.CreateStatusBar(); self._updateStatusBar(); - self.SetFocus(); self.Show(True); self.onCanvasUpdate(); - # }}} +from MiRCARTFrame import MiRCARTFrame +from MiRCARTToolRect import MiRCARTToolRect +import sys, wx # # Entry point def main(*argv): wxApp = wx.App(False) - MiRCARTFrame(None) + MiRCARTFrame(None, canvasTools=[MiRCARTToolRect]) wxApp.MainLoop() if __name__ == "__main__": main(*sys.argv) diff --git a/MiRCARTCanvas.py b/MiRCARTCanvas.py new file mode 100644 index 0000000..3743b5c --- /dev/null +++ b/MiRCARTCanvas.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +# +# MiRCARTCanvas.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +from MiRCARTCanvasJournal import MiRCARTCanvasJournal +from MiRCARTColours import MiRCARTColours +import wx + +class MiRCARTCanvas(wx.Panel): + """XXX""" + parentFrame = None + canvasPos = canvasSize = canvasWinSize = cellPos = cellSize = None + canvasBitmap = canvasMap = canvasTools = None + mircBg = mircFg = mircBrushes = mircPens = None + canvasJournal = None + + # {{{ _drawPatch(self, patch, eventDc, tmpDc, atPoint): XXX + def _drawPatch(self, patch, eventDc, tmpDc, atPoint): + absPoint = self._relMapPointToAbsPoint((patch[0], patch[1]), atPoint) + if patch[4] == " ": + brushFg = self.mircBrushes[patch[3]]; brushBg = self.mircBrushes[patch[3]]; + pen = self.mircPens[patch[3]] + else: + brushFg = self.mircBrushes[patch[2]]; brushBg = self.mircBrushes[patch[3]]; + pen = self.mircPens[patch[2]] + for dc in (eventDc, tmpDc): + dc.SetBrush(brushFg); dc.SetBackground(brushBg); dc.SetPen(pen); + dc.DrawRectangle(absPoint[0], absPoint[1], self.cellSize[0], self.cellSize[1]) + # }}} + # {{{ _eventPointToMapPoint(self, eventPoint): XXX + def _eventPointToMapPoint(self, eventPoint): + rectX = eventPoint.x - (eventPoint.x % self.cellSize[0]) + rectY = eventPoint.y - (eventPoint.y % self.cellSize[1]) + mapX = int(rectX / self.cellSize[0] if rectX else 0) + mapY = int(rectY / self.cellSize[1] if rectY else 0) + return (mapX, mapY) + # }}} + # {{{ _getMapCell(self, absMapPoint): XXX + def _getMapCell(self, absMapPoint): + return self.canvasMap[absMapPoint[1]][absMapPoint[0]] + # }}} + # {{{ _relMapPointToAbsPoint(self, relMapPoint, atPoint): XXX + def _relMapPointToAbsPoint(self, relMapPoint, atPoint): + absX = (atPoint[0] + relMapPoint[0]) * self.cellSize[0] + absY = (atPoint[1] + relMapPoint[1]) * self.cellSize[1] + return (absX, absY) + # }}} + # {{{ _setMapCell(self, absMapPoint, colourFg, colourBg, char): XXX + def _setMapCell(self, absMapPoint, colourFg, colourBg, char): + self.canvasMap[absMapPoint[1]][absMapPoint[0]] = [colourFg, colourBg, char] + # }}} + # {{{ onClose(self, event): XXX + def onClose(self, event): + self.Destroy(); self.__del__(); + # }}} + # {{{ onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): + def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): + if eventDc == None: + eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); + if tmpDc == None: + tmpDc.SelectObject(self.canvasBitmap) + if isTmp == True: + self._drawPatch(patch, eventDc, tmpDc, atPoint) + else: + self._setMapCell(absMapPoint, *patch[2:5]) + self._drawPatch(patch, eventDc, tmpDc, atPoint) + self.parentFrame.onCanvasUpdate() + # }}} + # {{{ onMouseEvent(self, event): XXX + def onMouseEvent(self, event): + eventObject = event.GetEventObject() + eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); + tmpDc.SelectObject(self.canvasBitmap) + eventPoint = event.GetLogicalPosition(eventDc) + mapPoint = self._eventPointToMapPoint(eventPoint) + for tool in self.canvasTools: + mapPatches = tool.onMouseEvent(event, mapPoint, event.Dragging(), \ + event.LeftIsDown(), event.RightIsDown()) + self.canvasJournal.merge(mapPatches, eventDc, tmpDc, mapPoint) + # }}} + # {{{ onPaint(self, event): XXX + def onPaint(self, event): + eventDc = wx.BufferedPaintDC(self, self.canvasBitmap) + # }}} + # {{{ redo(self): XXX + def redo(self): + return self.canvasJournal.redo() + # }}} + # {{{ undo(self): XXX + def undo(self): + return self.canvasJournal.undo() + # }}} + # {{{ __del__(self): destructor method + def __del__(self): + if self.canvasBitmap != None: + self.canvasBitmap.Destroy(); self.canvasBitmap = None; + for brush in self.mircBrushes or []: + brush.Destroy() + self.mircBrushes = None + for pen in self.mircPens or []: + pen.Destroy() + self.mircPens = None + # }}} + + # + # _init__(self, parent, parentFrame, canvasPos, cellSize, canvasSize, canvasTools): initialisation method + def __init__(self, parent, parentFrame, canvasPos, cellSize, canvasSize, canvasTools): + self.parentFrame = parentFrame + canvasWinSize = (cellSize[0] * canvasSize[0], cellSize[1] * canvasSize[1]) + super().__init__(parent, pos=canvasPos, size=canvasWinSize) + self.canvasPos = canvasPos; self.canvasSize = canvasSize; self.canvasWinSize = canvasWinSize; + self.cellPos = (0, 0); self.cellSize = cellSize; + + self.canvasBitmap = wx.Bitmap(canvasWinSize) + self.canvasMap = [[[1, 1, " "] for x in range(canvasSize[0])] for y in range(canvasSize[1])] + self.canvasTools = [] + for canvasTool in canvasTools: + self.canvasTools.append(canvasTool(self)) + + self.mircBg = 1; self.mircFg = 4; + self.mircBrushes = [None for x in range(len(MiRCARTColours))] + self.mircPens = [None for x in range(len(MiRCARTColours))] + for mircColour in range(0, len(MiRCARTColours)): + self.mircBrushes[mircColour] = wx.Brush( \ + wx.Colour(MiRCARTColours[mircColour]), wx.BRUSHSTYLE_SOLID) + self.mircPens[mircColour] = wx.Pen( \ + wx.Colour(MiRCARTColours[mircColour]), 1) + + self.canvasJournal = MiRCARTCanvasJournal(self) + + self.Bind(wx.EVT_CLOSE, self.onClose) + self.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) + self.Bind(wx.EVT_MOTION, self.onMouseEvent) + self.Bind(wx.EVT_PAINT, self.onPaint) + self.Bind(wx.EVT_RIGHT_DOWN, self.onMouseEvent) + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTCanvasJournal.py b/MiRCARTCanvasJournal.py new file mode 100644 index 0000000..03e5f93 --- /dev/null +++ b/MiRCARTCanvasJournal.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# +# MiRCARTCanvasJournal.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +class MiRCARTCanvasJournal(): + """XXX""" + parentCanvas = None + patchesTmp = patchesUndo = patchesUndoLevel = None + + # {{{ _popTmp(self, eventDc, tmpDc): XXX + def _popTmp(self, eventDc, tmpDc): + if self.patchesTmp: + for patch in self.patchesTmp: + patch[2:] = self.parentCanvas._getMapCell([patch[0], patch[1]]) + self.parentCanvas.onJournalUpdate(True, \ + (patch[0:2]), patch, eventDc, tmpDc, (0, 0)) + self.patchesTmp = [] + # }}} + # {{{ _pushTmp(self, atPoint, patch): XXX + def _pushTmp(self, absMapPoint): + self.patchesTmp.append([*absMapPoint, None, None, None]) + # }}} + # {{{ _pushUndo(self, atPoint, patch): XXX + def _pushUndo(self, atPoint, patch, mapItem): + if self.patchesUndoLevel > 0: + del self.patchesUndo[0:self.patchesUndoLevel] + self.patchesUndoLevel = 0 + absMapPoint = self._relMapPointToAbsMapPoint((patch[0], patch[1]), atPoint) + self.patchesUndo.insert(0, ( \ + (absMapPoint[0], absMapPoint[1], mapItem[0], mapItem[1], mapItem[2]), \ + (absMapPoint[0], absMapPoint[1], patch[2], patch[3], patch[4]))) + # }}} + # {{{ _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): XXX + def _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): + return (atPoint[0] + relMapPoint[0], atPoint[1] + relMapPoint[1]) + # }}} + # {{{ merge(self, mapPatches, eventDc, tmpDc, atPoint): XXX + def merge(self, mapPatches, eventDc, tmpDc, atPoint): + for mapPatch in mapPatches: + mapPatchTmp = mapPatch[0] + if mapPatchTmp: + self._popTmp(eventDc, tmpDc) + for patch in mapPatch[1]: + absMapPoint = self._relMapPointToAbsMapPoint(patch[0:2], atPoint) + mapItem = self.parentCanvas._getMapCell(absMapPoint) + if mapPatchTmp: + self._pushTmp(absMapPoint) + self.parentCanvas.onJournalUpdate(mapPatchTmp, \ + absMapPoint, patch, eventDc, tmpDc, atPoint) + elif mapItem != patch[2:5]: + self._pushUndo(atPoint, patch, mapItem) + self.parentCanvas.onJournalUpdate(mapPatchTmp, \ + absMapPoint, patch, eventDc, tmpDc, atPoint) + # }}} + # {{{ redo(self): XXX + def redo(self): + if self.patchesUndoLevel > 0: + self.patchesUndoLevel -= 1 + redoPatch = self.patchesUndo[self.patchesUndoLevel][1] + self.parentCanvas.onJournalUpdate(False, \ + (redoPatch[0:2]), redoPatch, None, None, (0, 0)) + return True + else: + return False + # }}} + # {{{ undo(self): XXX + def undo(self): + if self.patchesUndo[self.patchesUndoLevel] != None: + undoPatch = self.patchesUndo[self.patchesUndoLevel][0] + self.patchesUndoLevel += 1 + self.parentCanvas.onJournalUpdate(False, \ + (undoPatch[0:2]), undoPatch, None, None, (0, 0)) + return True + else: + return False + # }}} + + # + # __init__(self, parentCanvas): initialisation method + def __init__(self, parentCanvas): + self.parentCanvas = parentCanvas + self.patchesTmp = [] + self.patchesUndo = [None]; self.patchesUndoLevel = 0; + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTColours.py b/MiRCARTColours.py new file mode 100755 index 0000000..9489b08 --- /dev/null +++ b/MiRCARTColours.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# MiRCARTColours.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +# +# MiRCARTColours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline) +# +MiRCARTColours = [ + (255, 255, 255, 255), # White + (0, 0, 0, 255), # Black + (0, 0, 187, 255), # Blue + (0, 187, 0, 255), # Green + (255, 85, 85, 255), # Light Red + (187, 0, 0, 255), # Red + (187, 0, 187, 255), # Purple + (187, 187, 0, 255), # Yellow + (255, 255, 85, 255), # Light Yellow + (85, 255, 85, 255), # Light Green + (0, 187, 187, 255), # Cyan + (85, 255, 255, 255), # Light Cyan + (85, 85, 255, 255), # Light Blue + (255, 85, 255, 255), # Pink + (85, 85, 85, 255), # Grey + (187, 187, 187, 255), # Light Grey +] + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTFrame.py b/MiRCARTFrame.py new file mode 100644 index 0000000..4e84a8b --- /dev/null +++ b/MiRCARTFrame.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python3 +# +# MiRCARTFrame.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +from MiRCARTCanvas import MiRCARTCanvas +from MiRCARTColours import MiRCARTColours +from MiRCARTFromTextFile import MiRCARTFromTextFile +from MiRCARTToTextFile import MiRCARTToTextFile +import os, wx + +try: + from MiRCARTToPastebin import MiRCARTToPastebin + haveMiRCARTToPastebin = True +except ImportError: + haveMiRCARTToPastebin = False + +try: + from MiRCARTToPngFile import MiRCARTToPngFile + haveMiRCARTToPngFile = True +except ImportError: + haveMiRCARTToPngFile = False + +class MiRCARTFrame(wx.Frame): + """XXX""" + panelSkin = panelCanvas = canvasPathName = None + canvasPos = canvasSize = canvasTools = cellSize = None + menuItemsById = menuBar = toolBar = accelTable = statusBar = None + + # {{{ Types + TID_COMMAND = (0x001) + TID_NOTHING = (0x002) + TID_MENU = (0x003) + TID_TOOLBAR = (0x004) + TID_ACCELS = (0x005) + # }}} + # {{{ Commands + # Id Type Id Labels Icon bitmap Accelerator + CID_NEW = (0x100, TID_COMMAND, "New", "&New", [wx.ART_NEW], None) + CID_OPEN = (0x101, TID_COMMAND, "Open", "&Open", [wx.ART_FILE_OPEN], None) + CID_SAVE = (0x102, TID_COMMAND, "Save", "&Save", [wx.ART_FILE_SAVE], None) + CID_SAVEAS = (0x103, TID_COMMAND, "Save As...", "Save &As...", [wx.ART_FILE_SAVE_AS], None) + CID_EXPORT_AS_PNG = (0x104, TID_COMMAND, "Export as PNG...", "Export as PN&G...", (), None) + CID_EXPORT_PASTEBIN = (0x105, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", (), None) + CID_EXIT = (0x106, TID_COMMAND, "Exit", "E&xit", (), None) + CID_UNDO = (0x107, TID_COMMAND, "Undo", "&Undo", [wx.ART_UNDO], (wx.ACCEL_CTRL, ord("Z"))) + CID_REDO = (0x108, TID_COMMAND, "Redo", "&Redo", [wx.ART_REDO], (wx.ACCEL_CTRL, ord("Y"))) + CID_CUT = (0x109, TID_COMMAND, "Cut", "Cu&t", [wx.ART_CUT], None) + CID_COPY = (0x10a, TID_COMMAND, "Copy", "&Copy", [wx.ART_COPY], None) + CID_PASTE = (0x10b, TID_COMMAND, "Paste", "&Paste", [wx.ART_PASTE], None) + CID_DELETE = (0x10c, TID_COMMAND, "Delete", "De&lete", [wx.ART_DELETE], None) + CID_INCRBRUSH = (0x10d, TID_COMMAND, "Increase brush size", "&Increase brush size", [wx.ART_PLUS], None) + CID_DECRBRUSH = (0x10e, TID_COMMAND, "Decrease brush size", "&Decrease brush size", [wx.ART_MINUS], None) + CID_SOLIDBRUSH = (0x10f, TID_COMMAND, "Solid brush", "&Solid brush", [None], None) + CID_RECT = (0x110, TID_COMMAND, "Rectangle", "&Rectangle", [None], None) + CID_CIRCLE = (0x111, TID_COMMAND, "Circle", "&Circle", [None], None) + CID_LINE = (0x112, TID_COMMAND, "Line", "&Line", [None], None) + CID_COLOUR00 = (0x113, TID_COMMAND, "Colour #00", "Colour #00", MiRCARTColours[0], None) + CID_COLOUR01 = (0x114, TID_COMMAND, "Colour #01", "Colour #01", MiRCARTColours[1], None) + CID_COLOUR02 = (0x115, TID_COMMAND, "Colour #02", "Colour #02", MiRCARTColours[2], None) + CID_COLOUR03 = (0x116, TID_COMMAND, "Colour #03", "Colour #03", MiRCARTColours[3], None) + CID_COLOUR04 = (0x117, TID_COMMAND, "Colour #04", "Colour #04", MiRCARTColours[4], None) + CID_COLOUR05 = (0x118, TID_COMMAND, "Colour #05", "Colour #05", MiRCARTColours[5], None) + CID_COLOUR06 = (0x119, TID_COMMAND, "Colour #06", "Colour #06", MiRCARTColours[6], None) + CID_COLOUR07 = (0x11a, TID_COMMAND, "Colour #07", "Colour #07", MiRCARTColours[7], None) + CID_COLOUR08 = (0x11b, TID_COMMAND, "Colour #08", "Colour #08", MiRCARTColours[8], None) + CID_COLOUR09 = (0x11c, TID_COMMAND, "Colour #09", "Colour #09", MiRCARTColours[9], None) + CID_COLOUR10 = (0x11d, TID_COMMAND, "Colour #10", "Colour #10", MiRCARTColours[10], None) + CID_COLOUR11 = (0x11e, TID_COMMAND, "Colour #11", "Colour #11", MiRCARTColours[11], None) + CID_COLOUR12 = (0x11f, TID_COMMAND, "Colour #12", "Colour #12", MiRCARTColours[12], None) + CID_COLOUR13 = (0x120, TID_COMMAND, "Colour #13", "Colour #13", MiRCARTColours[13], None) + CID_COLOUR14 = (0x121, TID_COMMAND, "Colour #14", "Colour #14", MiRCARTColours[14], None) + CID_COLOUR15 = (0x122, TID_COMMAND, "Colour #15", "Colour #15", MiRCARTColours[15], None) + # }}} + # {{{ Non-items + NID_MENU_SEP = (0x200, TID_NOTHING) + NID_TOOLBAR_SEP = (0x201, TID_NOTHING) + # }}} + # {{{ Menus + MID_FILE = (0x300, TID_MENU, "File", "&File", ( \ + CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_MENU_SEP, \ + CID_EXPORT_PASTEBIN, CID_EXPORT_AS_PNG, NID_MENU_SEP, \ + CID_EXIT)) + MID_EDIT = (0x301, TID_MENU, "Edit", "&Edit", ( \ + CID_UNDO, CID_REDO, NID_MENU_SEP, \ + CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_MENU_SEP, \ + CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLIDBRUSH)) + MID_TOOLS = (0x302, TID_MENU, "Tools", "&Tools", ( \ + CID_RECT, CID_CIRCLE, CID_LINE)) + # }}} + # {{{ Toolbars + BID_TOOLBAR = (0x400, TID_TOOLBAR, ( \ + CID_NEW, CID_OPEN, CID_SAVE, CID_SAVEAS, NID_TOOLBAR_SEP, \ + CID_UNDO, CID_REDO, NID_TOOLBAR_SEP, \ + CID_CUT, CID_COPY, CID_PASTE, CID_DELETE, NID_TOOLBAR_SEP, \ + CID_INCRBRUSH, CID_DECRBRUSH, CID_SOLIDBRUSH, NID_TOOLBAR_SEP, \ + CID_RECT, CID_CIRCLE, CID_LINE, NID_TOOLBAR_SEP, \ + CID_COLOUR00, CID_COLOUR01, CID_COLOUR02, CID_COLOUR03, CID_COLOUR04, \ + CID_COLOUR05, CID_COLOUR06, CID_COLOUR07, CID_COLOUR08, CID_COLOUR09, \ + CID_COLOUR10, CID_COLOUR11, CID_COLOUR12, CID_COLOUR13, CID_COLOUR14, \ + CID_COLOUR15)) + # }}} + # {{{ Accelerators (hotkeys) + AID_EDIT = (0x500, TID_ACCELS, (CID_UNDO, CID_REDO)) + # }}} + + # {{{ _drawIcon(self, solidColour): XXX + def _drawIcon(self, solidColour): + iconBitmap = wx.Bitmap((16,16)) + iconDc = wx.MemoryDC(); iconDc.SelectObject(iconBitmap); + iconBrush = wx.Brush(wx.Colour(solidColour), wx.BRUSHSTYLE_SOLID) + iconDc.SetBrush(iconBrush); iconDc.SetBackground(iconBrush); + iconDc.SetPen(wx.Pen(wx.Colour(solidColour), 1)) + iconDc.DrawRectangle(0, 0, 16, 16) + return iconBitmap + # }}} + # {{{ _initAccelTable(self, accelsDescr, handler): XXX + def _initAccelTable(self, accelsDescr, handler): + accelTableEntries = [wx.AcceleratorEntry() for n in range(0, len(accelsDescr[2]))] + for numAccel in range(0, len(accelsDescr[2])): + accelDescr = accelsDescr[2][numAccel] + if accelDescr[5] != None: + accelTableEntries[numAccel].Set(accelDescr[5][0], accelDescr[5][1], accelDescr[0]) + self.Bind(wx.EVT_MENU, handler, id=accelDescr[0]) + return accelTableEntries + # }}} + # {{{ _initMenus(self, menuBar, menusDescr, handler): XXX + def _initMenus(self, menuBar, menusDescr, handler): + for menuDescr in menusDescr: + menuWindow = wx.Menu() + for menuItem in menuDescr[4]: + if menuItem == self.NID_MENU_SEP: + menuWindow.AppendSeparator() + else: + menuItemWindow = menuWindow.Append(menuItem[0], menuItem[3], menuItem[2]) + self.menuItemsById[menuItem[0]] = menuItemWindow + self.Bind(wx.EVT_MENU, handler, menuItemWindow) + menuBar.Append(menuWindow, menuDescr[3]) + # }}} + # {{{ _initToolBars(self, toolBar, toolBarsDescr, handler): XXX + def _initToolBars(self, toolBar, toolBarsDescr, handler): + for toolBarDescr in toolBarsDescr: + for toolBarItem in toolBarDescr[2]: + if toolBarItem == self.NID_TOOLBAR_SEP: + toolBar.AddSeparator() + else: + if len(toolBarItem[4]) == 4: + toolBarItemIcon = self._drawIcon(toolBarItem[4]) + elif len(toolBarItem[4]) == 1 \ + and toolBarItem[4][0] != None: + toolBarItemIcon = wx.ArtProvider.GetBitmap( \ + toolBarItem[4][0], wx.ART_TOOLBAR, (16,16)) + else: + toolBarItemIcon = wx.ArtProvider.GetBitmap( \ + wx.ART_HELP, wx.ART_TOOLBAR, (16,16)) + toolBarItemWindow = self.toolBar.AddTool( \ + toolBarItem[0], toolBarItem[2], toolBarItemIcon) + self.Bind(wx.EVT_TOOL, handler, toolBarItemWindow) + self.Bind(wx.EVT_TOOL_RCLICKED, handler, toolBarItemWindow) + # }}} + # {{{ _updateStatusBar(self): XXX + def _updateStatusBar(self): + text = "Foreground colour:" + text += " " + str(self.panelCanvas.mircFg) + text += " | " + text += "Background colour:" + text += " " + str(self.panelCanvas.mircBg) + self.statusBar.SetStatusText(text) + # }}} + + # {{{ canvasExportAsPng(self): XXX + def canvasExportAsPng(self): + with wx.FileDialog(self, self.CID_SAVEAS[2], os.getcwd(), "", \ + "*.png", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog: + if dialog.ShowModal() == wx.ID_CANCEL: + return False + else: + outPathName = dialog.GetPath() + outTmpFile = io.StringIO() + outToTextFile = MiRCARTToTextFile( \ + self.panelCanvas.canvasMap, self.canvasSize) + outToTextFile.export(outTmpFile) + MiRCARTToPngFile(tmpFile).export(outPathName) + return True + # }}} + # {{{ canvasExportPastebin(self): XXX + def canvasExportPastebin(self): + MiRCARTToPastebin("253ce2f0a45140ee0a44ca99aa49260", \ + self.panelCanvas.canvasMap, self.canvasSize).export() + # }}} + # {{{ canvasNew(self, canvasPos=None, canvasSize=None, cellSize=None): XXX + def canvasNew(self, canvasPos=None, canvasSize=None, cellSize=None): + canvasPos = canvasPos if canvasPos != None else self.canvasPos + canvasSize = canvasSize if canvasSize != None else self.canvasSize + cellSize = cellSize if cellSize != None else self.cellSize + if self.panelCanvas != None: + self.panelCanvas.Close(); self.panelCanvas = None; + self.canvasPos = canvasPos; self.canvasSize = canvasSize; + self.cellSize = cellSize + self.panelCanvas = MiRCARTCanvas(self.panelSkin, parentFrame=self, \ + canvasPos=self.canvasPos, cellSize=self.cellSize, \ + canvasSize=self.canvasSize, canvasTools=self.canvasTools) + self._updateStatusBar(); self.onCanvasUpdate(); + # }}} + # {{{ canvasOpen(self): XXX + def canvasOpen(self): + with wx.FileDialog(self, self.CID_OPEN[2], os.getcwd(), "", \ + "*.txt", wx.FD_OPEN) as dialog: + if dialog.ShowModal() == wx.ID_CANCEL: + return False + else: + self.canvasPathName = dialog.GetPath() + with open(self.canvasPathName, "r") as newFile: + newFromTextFile = MiRCARTFromTextFile(newFile) + newMap = newFromTextFile.getMap() + self.canvasNew(canvasSize=newFromTextFile.getSize()) + eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); + tmpDc.SelectObject(self.panelCanvas.canvasBitmap) + for newNumRow in range(0, len(newMap)): + for newNumCol in range(0, len(newMap[newNumRow])): + self.panelCanvas.onJournalUpdate(False, \ + (newNumCol, newNumRow), \ + [newNumCol, newNumRow, \ + newMap[newNumRow][newNumCol][0][0], \ + newMap[newNumRow][newNumCol][0][1], \ + newMap[newNumRow][newNumCol][2]], \ + eventDc, tmpDc, (0, 0)) + wx.SafeYield() + return True + # }}} + # {{{ canvasSave(self): XXX + def canvasSave(self): + if self.canvasPathName == None: + if self.canvasSaveAs() == False: + return + try: + with open(self.canvasPathName, "w") as outFile: + MiRCARTToTextFile(self.panelCanvas.canvasMap, \ + self.panelCanvas.canvasSize).export(outFile) + except IOError as error: + pass + # }}} + # {{{ canvasSaveAs(self): XXX + def canvasSaveAs(self): + with wx.FileDialog(self, self.CID_SAVEAS[2], os.getcwd(), "", \ + "*.txt", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) as dialog: + if dialog.ShowModal() == wx.ID_CANCEL: + return False + else: + self.canvasPathName = dialog.GetPath() + return True + # }}} + # {{{ onCanvasUpdate(self): XXX + def onCanvasUpdate(self): + if self.panelCanvas.canvasJournal.patchesUndo[self.panelCanvas.canvasJournal.patchesUndoLevel] != None: + self.menuItemsById[self.CID_UNDO[0]].Enable(True) + else: + self.menuItemsById[self.CID_UNDO[0]].Enable(False) + if self.panelCanvas.canvasJournal.patchesUndoLevel > 0: + self.menuItemsById[self.CID_REDO[0]].Enable(True) + else: + self.menuItemsById[self.CID_REDO[0]].Enable(False) + # }}} + # {{{ onClose(self, event): XXX + def onClose(self, event): + self.Destroy(); self.__del__(); + # }}} + # {{{ onFrameCommand(self, event): XXX + def onFrameCommand(self, event): + cid = event.GetId() + if cid == self.CID_NEW[0]: + self.canvasNew() + elif cid == self.CID_OPEN[0]: + self.canvasOpen() + elif cid == self.CID_SAVE[0]: + self.canvasSave() + elif cid == self.CID_SAVEAS[0]: + self.canvasSaveAs() + elif cid == self.CID_EXPORT_AS_PNG[0]: + self.canvasExportAsPng() + elif cid == self.CID_EXPORT_PASTEBIN[0]: + self.canvasExportPastebin() + elif cid == self.CID_EXIT[0]: + self.Close(True) + elif cid == self.CID_UNDO[0]: + self.panelCanvas.undo() + elif cid == self.CID_REDO[0]: + self.panelCanvas.redo() + elif cid == self.CID_CUT[0]: + pass + elif cid == self.CID_COPY[0]: + pass + elif cid == self.CID_PASTE[0]: + pass + elif cid == self.CID_DELETE[0]: + pass + elif cid == self.CID_INCRBRUSH[0]: + pass + elif cid == self.CID_DECRBRUSH[0]: + pass + elif cid == self.CID_SOLIDBRUSH[0]: + pass + elif cid == self.CID_RECT[0]: + pass + elif cid == self.CID_CIRCLE[0]: + pass + elif cid == self.CID_LINE[0]: + pass + elif cid >= self.CID_COLOUR00[0] \ + and cid <= self.CID_COLOUR15[0]: + numColour = cid - self.CID_COLOUR00[0] + if event.GetEventType() == wx.wxEVT_TOOL: + self.panelCanvas.mircFg = numColour + elif event.GetEventType() == wx.wxEVT_TOOL_RCLICKED: + self.panelCanvas.mircBg = numColour + self._updateStatusBar() + # }}} + # {{{ __del__(self): destructor method + def __del__(self): + if self.panelCanvas != None: + self.panelCanvas.Close(); self.panelCanvas = None; + # }}} + + # + # __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), cellSize=(7, 14), canvasSize=(100, 30), canvasTools=[]): initialisation method + def __init__(self, parent, appSize=(800, 600), canvasPos=(25, 50), cellSize=(7, 14), canvasSize=(100, 30), canvasTools=[]): + super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize) + self.panelSkin = wx.Panel(self, wx.ID_ANY) + self.canvasPathName = None + + self.menuItemsById = {}; self.menuBar = wx.MenuBar(); + self._initMenus(self.menuBar, \ + [self.MID_FILE, self.MID_EDIT, self.MID_TOOLS], self.onFrameCommand) + self.SetMenuBar(self.menuBar) + if not haveMiRCARTToPastebin: + self.menuItemsById[self.CID_EXPORT_PASTEBIN[0]].Enable(False) + if not haveMiRCARTToPngFile: + self.menuItemsById[self.CID_EXPORT_AS_PNG[0]].Enable(False) + + self.toolBar = wx.ToolBar(self.panelSkin, -1, \ + style=wx.HORIZONTAL|wx.TB_FLAT|wx.TB_NODIVIDER) + self.toolBar.SetToolBitmapSize((16,16)) + self._initToolBars(self.toolBar, [self.BID_TOOLBAR], self.onFrameCommand) + self.toolBar.Realize(); self.toolBar.Fit(); + + self.accelTable = wx.AcceleratorTable( \ + self._initAccelTable(self.AID_EDIT, self.onFrameCommand)) + self.SetAcceleratorTable(self.accelTable) + + self.Bind(wx.EVT_CLOSE, self.onClose) + self.statusBar = self.CreateStatusBar(); + self.SetFocus(); self.Show(True); + self.canvasTools = canvasTools + self.canvasNew(canvasPos, canvasSize, cellSize) + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTFromTextFile.py b/MiRCARTFromTextFile.py new file mode 100644 index 0000000..6459877 --- /dev/null +++ b/MiRCARTFromTextFile.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +# +# MiRCARTFromTextFile.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +class MiRCARTFromTextFile(): + """XXX""" + inFile = inSize = outMap = None + + # + # _CellState(): Cell state + class _CellState(): + CS_NONE = 0x00 + CS_BOLD = 0x01 + CS_ITALIC = 0x02 + CS_UNDERLINE = 0x04 + + # + # _ParseState(): Parsing loop state + class _ParseState(): + PS_CHAR = 1 + PS_COLOUR_DIGIT0 = 2 + PS_COLOUR_DIGIT1 = 3 + + # {{{ _parseCharAsColourSpec(self, colourSpec, curColours): XXX + def _parseCharAsColourSpec(self, colourSpec, curColours): + if len(colourSpec) > 0: + colourSpec = colourSpec.split(",") + if len(colourSpec) == 2: + return (int(colourSpec[0] or curColours[0]), \ + int(colourSpec[1])) + elif len(colourSpec) == 1: + return (int(colourSpec[0]), curColours[0]) + else: + return (15, 1) + # }}} + # {{{ _flipCellStateBit(self, cellState, bit): XXX + def _flipCellStateBit(self, cellState, bit): + if cellState & bit: + return cellState & ~bit + else: + return cellState | bit + # }}} + # {{{ _transform(self): XXX + def _transform(self): + inCurColourSpec = ""; inCurRow = -1; + inLine = self.inFile.readline() + inSize = [0, 0]; outMap = []; inMaxCols = 0; + while inLine: + inCellState = self._CellState.CS_NONE + inParseState = self._ParseState.PS_CHAR + inCurCol = 0; inMaxCol = len(inLine); + inCurColourDigits = 0; inCurColours = (15, 1); inCurColourSpec = ""; + inCurRow += 1; outMap.append([]); inRowCols = 0; inSize[1] += 1; + while inCurCol < inMaxCol: + inChar = inLine[inCurCol] + if inChar in set("\r\n"): \ + inCurCol += 1 + elif inParseState == self._ParseState.PS_CHAR: + inCurCol += 1 + if inChar == "": + inCellState = self._flipCellStateBit( \ + inCellState, self._CellState.CS_BOLD) + elif inChar == "": + inParseState = self._ParseState.PS_COLOUR_DIGIT0 + elif inChar == "": + inCellState = self._flipCellStateBit( \ + inCellState, self._CellState.CS_ITALIC) + elif inChar == "": + inCellState |= self._CellState.CS_NONE + inCurColours = (15, 1) + elif inChar == "": + inCurColours = (inCurColours[1], inCurColours[0]) + elif inChar == "": + inCellState = self._flipCellStateBit( \ + inCellState, self._CellState.CS_UNDERLINE) + else: + inRowCols += 1 + outMap[inCurRow].append((inCurColours, inCellState, inChar)) + elif inParseState == self._ParseState.PS_COLOUR_DIGIT0 \ + or inParseState == self._ParseState.PS_COLOUR_DIGIT1: + if inChar == "," \ + and inParseState == self._ParseState.PS_COLOUR_DIGIT0: + inCurCol += 1 + inCurColourDigits = 0; inCurColourSpec += inChar; + inParseState = self._ParseState.PS_COLOUR_DIGIT1 + elif inChar in set("0123456789") \ + and inCurColourDigits == 0: + inCurCol += 1 + inCurColourDigits += 1; inCurColourSpec += inChar; + elif inChar in set("0123456789") \ + and inCurColourDigits == 1 \ + and inCurColourSpec[-1] == "0": + inCurCol += 1 + inCurColourDigits += 1; inCurColourSpec += inChar; + elif inChar in set("012345") \ + and inCurColourDigits == 1 \ + and inCurColourSpec[-1] == "1": + inCurCol += 1 + inCurColourDigits += 1; inCurColourSpec += inChar; + else: + inCurColours = self._parseCharAsColourSpec( \ + inCurColourSpec, inCurColours) + inCurColourDigits = 0; inCurColourSpec = ""; + inParseState = self._ParseState.PS_CHAR + inMaxCols = max(inMaxCols, inRowCols) + inLine = self.inFile.readline() + inSize[0] = inMaxCols; self.inSize = inSize; self.outMap = outMap; + # }}} + # {{{ getMap(self): XXX + def getMap(self): + if self.outMap == None: + self._transform() + return self.outMap + # }}} + # {{{ getSize(self): XXX + def getSize(self): + if self.inSize == None: + self._transform() + return self.inSize + # }}} + + # + # __init__(self): initialisation method + def __init__(self, inFile): + self.inFile = inFile; self.inSize = None; self.outMap = None; + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTToPastebin.py b/MiRCARTToPastebin.py new file mode 100644 index 0000000..88b25bc --- /dev/null +++ b/MiRCARTToPastebin.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# +# MiRCARTToPastebin.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +from MiRCARTToTextFile import MiRCARTToTextFile +import io +import base64 +import requests, urllib.request + +class MiRCARTToPastebin(): + apiDevKey = outFile = outToTextFile = None + + # export(self): XXX + def export(self): + self.outToTextFile.export(self.outFile, pasteName="", pastePrivate=0) + requestData = { \ + "api_dev_key": self.apiDevKey, \ + "api_option": "paste", \ + "api_paste_code": base64.b64encode(self.outFile.read()), \ + "api_paste_name": pasteName, \ + "api_paste_private": pastePrivate} + responseHttp = requests.post("https://pastebin.com/post.php", \ + data=requestData) + if responseHttp.status_code == 200: + return responseHttp.text + else: + return None + + # __init__(self, canvasMap, canvasSize): XXX + def __init__(self, apiDevKey, canvasMap, canvasSize): + self.apiDevKey = apiDevKey + self.outFile = io.StringIO() + self.outToTextFile = MiRCARTToTextFile(canvasMap, canvasSize) + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTToPngFile.py b/MiRCARTToPngFile.py new file mode 100755 index 0000000..8503b41 --- /dev/null +++ b/MiRCARTToPngFile.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python3 +# +# MiRCARTToPngFile.py -- convert ASCII w/ mIRC control codes to monospaced PNG (for EFnet #MiRCART) +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +from PIL import Image, ImageDraw, ImageFont +from MiRCARTFromTextFile import MiRCARTFromTextFile +import string, sys + +class MiRCARTToPngFile: + """XXX""" + inFile = inFilePath = inFromTextFile = None + outFontFilePath = outFontSize = None + + # {{{ _ColourMapBold: mIRC colour number to RGBA map given ^B (bold) + _ColourMapBold = [ + [255, 255, 255], # White + [85, 85, 85], # Grey + [85, 85, 255], # Light Blue + [85, 255, 85], # Light Green + [255, 85, 85], # Light Red + [255, 85, 85], # Light Red + [255, 85, 255], # Pink + [255, 255, 85], # Light Yellow + [255, 255, 85], # Light Yellow + [85, 255, 85], # Light Green + [85, 255, 255], # Light Cyan + [85, 255, 255], # Light Cyan + [85, 85, 255], # Light Blue + [255, 85, 255], # Pink + [85, 85, 85], # Grey + [255, 255, 255], # White + ] + # }}} + # {{{ _ColourMapNormal: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline) + _ColourMapNormal = [ + [255, 255, 255], # White + [0, 0, 0], # Black + [0, 0, 187], # Blue + [0, 187, 0], # Green + [255, 85, 85], # Light Red + [187, 0, 0], # Red + [187, 0, 187], # Purple + [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], # Light Blue + [255, 85, 255], # Pink + [85, 85, 85], # Grey + [187, 187, 187], # Light Grey + ] + # }}} + # {{{ _drawUnderline(self, curPos, fontSize, imgDraw): XXX + def _drawUnderLine(self, curPos, fontSize, imgDraw): + imgDraw.line( \ + (curPos[0], \ + curPos[1] + (fontSize[1] - 2)), \ + (curPos[0] + fontSize[0], \ + curPos[1] + (fontSize[1] - 2)), fill=outColours[0]) + # }}} + # {{{ export(self, outFilePath): XXX + def export(self, outFilePath): + inSize = self.inFromTextFile.getSize(); + outSize = [inSize[n] * self.outImgFontSize[n] for n in range(0, 2)] + outCurPos = [0, 0] + outImg = Image.new("RGBA", outSize, (*self._ColourMapNormal[1], 255)) + outImgDraw = ImageDraw.Draw(outImg) + for inCurRow in range(0, inSize[1]): + for inCurCol in range(0, len(self.inFromTextFile.outMap[inCurRow])): + inCurCell = self.inFromTextFile.outMap[inCurRow][inCurCol] + outColours = [0, 0] + if inCurCell[1] & MiRCARTFromTextFile._CellState.CS_BOLD: + if inCurCell[2] != " ": + outColours[0] = self._ColourMapBold[inCurCell[0][0]] + outColours[1] = self._ColourMapBold[inCurCell[0][1]] + else: + if inCurCell[2] != " ": + outColours[0] = self._ColourMapNormal[inCurCell[0][0]] + outColours[1] = self._ColourMapNormal[inCurCell[0][1]] + outImgDraw.rectangle((*outCurPos, \ + outCurPos[0] + self.outImgFontSize[0], \ + outCurPos[1] + self.outImgFontSize[1]), \ + fill=(*outColours[1], 255)) + if inCurCell[2] != " " \ + and outColours[0] != outColours[1]: + # XXX implement italic + outImgDraw.text(outCurPos, \ + inCurCell[2], (*outColours[0], 255), self.outImgFont) + if inCurCell[1] & MiRCARTFromTextFile._CellState.CS_UNDERLINE: + self._drawUnderLine(curPos, self.outImgFontSize, outImgDraw) + outCurPos[0] += self.outImgFontSize[0]; + outCurPos[0] = 0 + outCurPos[1] += self.outImgFontSize[1] + outImg.save(outFilePath); + # }}} + + # + # __init__(self, inFilePath, fontFilePath="DejaVuSansMono.ttf", fontSize=11): initialisation method + def __init__(self, inFilePath, fontFilePath="DejaVuSansMono.ttf", fontSize=11): + self.inFilePath = inFilePath; self.inFile = open(inFilePath, "r"); + self.inFromTextFile = MiRCARTFromTextFile(self.inFile) + + self.outFontFilePath = fontFilePath; self.outFontSize = int(fontSize); + self.outImgFont = ImageFont.truetype( \ + self.outFontFilePath, self.outFontSize) + self.outImgFontSize = [*self.outImgFont.getsize(" ")] + self.outImgFontSize[1] += 3 + +# +# Entry point +def main(*argv): + MiRCARTToPngFile(argv[1], *argv[3:]).export(argv[2]) +if __name__ == "__main__": + if ((len(sys.argv) - 1) < 2)\ + or ((len(sys.argv) - 1) > 4): + print("usage: {} " \ + " " \ + " " \ + "[] " \ + "[]".format(sys.argv[0]), file=sys.stderr) + else: + main(*sys.argv) + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTToTextFile.py b/MiRCARTToTextFile.py new file mode 100644 index 0000000..ee0950d --- /dev/null +++ b/MiRCARTToTextFile.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# +# MiRCARTToTextFile.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +class MiRCARTToTextFile(): + canvasMap = canvasSize = None + + # export(self, outFile): XXX + def export(self, outFile): + for canvasRow in range(0, self.canvasSize[1]): + canvasLastColours = [] + for canvasCol in range(0, self.canvasSize[0]): + canvasColColours = self.canvasMap[canvasRow][canvasCol][0:2] + canvasColText = self.canvasMap[canvasRow][canvasCol][2] + if canvasColColours != canvasLastColours: + canvasLastColours = canvasColColours + outFile.write("\x03" + \ + str(canvasColColours[0]) + \ + "," + str(canvasColColours[1])) + outFile.write(canvasColText) + outFile.write("\n") + + # __init__(self, canvasMap, canvasSize): XXX + def __init__(self, canvasMap, canvasSize): + self.canvasMap = canvasMap; self.canvasSize = canvasSize; + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTTool.py b/MiRCARTTool.py new file mode 100644 index 0000000..0dad5ad --- /dev/null +++ b/MiRCARTTool.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# +# MiRCARTTool.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +class MiRCARTTool(): + """XXX""" + parentCanvas = None + + # {{{ onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX + def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): + pass + # }}} + + # + # __init__(self, parentCanvas): initialisation method + def __init__(self, parentCanvas): + self.parentCanvas = parentCanvas + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTToolRect.py b/MiRCARTToolRect.py new file mode 100644 index 0000000..b9e9fb2 --- /dev/null +++ b/MiRCARTToolRect.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# +# MiRCARTToolRect.py -- XXX +# Copyright (c) 2018 Lucio Andrés Illanes Albornoz +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +from MiRCARTTool import MiRCARTTool + +class MiRCARTToolRect(MiRCARTTool): + """XXX""" + + # + # onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX + def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): + if isLeftDown: + return [[False, [[0, 0, \ + self.parentCanvas.mircFg, \ + self.parentCanvas.mircFg, " "]]], + [True, [[0, 0, \ + self.parentCanvas.mircFg, \ + self.parentCanvas.mircFg, " "]]]] + elif isRightDown: + return [[False, [[0, 0, \ + self.parentCanvas.mircBg, \ + self.parentCanvas.mircBg, " "]]], \ + [True, [[0, 0, \ + self.parentCanvas.mircBg, \ + self.parentCanvas.mircBg, " "]]]] + else: + return [[True, [[0, 0, \ + self.parentCanvas.mircFg, \ + self.parentCanvas.mircFg, " "]]]] + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/README.md b/README.md index 736ccee..5785840 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ * Prerequisites: python3 && python3-{json,requests,urllib3} on Debian-family Linux distributions * IrcMiRCARTBot.py usage: IrcMiRCARTBot.py `` [``] [``] [``] [``] [``] -# MiRC2png.py -- convert ASCII w/ mIRC control codes to monospaced PNG (pending cleanup) +# MiRCARTToPngFile.py -- convert ASCII w/ mIRC control codes to monospaced PNG (pending cleanup) * Prerequisites: python3 && python3-pil on Debian-family Linux distributions * MiRC2png.py usage: MiRC2png.py `` `` [``] [``]