diff --git a/IrcClient.py b/IrcClient.py index 0816558..1d8647a 100644 --- a/IrcClient.py +++ b/IrcClient.py @@ -90,7 +90,7 @@ class IrcClient: # {{{ queue(self, *args): Parse and queue single line to server from list def queue(self, *args): msg = ""; argNumMax = len(args); - for argNum in range(0, argNumMax): + for argNum in range(argNumMax): if argNum == (argNumMax - 1): msg += ":" + args[argNum] else: diff --git a/IrcMiRCARTBot.py b/IrcMiRCARTBot.py index 6d75554..b943f23 100755 --- a/IrcMiRCARTBot.py +++ b/IrcMiRCARTBot.py @@ -27,6 +27,7 @@ import os, sys, time import json import IrcClient import requests, urllib.request +from MiRCARTCanvasStore import MiRCARTCanvasStore from MiRCARTToPngFile import MiRCARTToPngFile class IrcMiRCARTBot(IrcClient.IrcClient): @@ -139,7 +140,9 @@ class IrcMiRCARTBot(IrcClient.IrcClient): self._log("Unknown URL type specified!") self.queue("PRIVMSG", message[2], "4/!\\ Unknown URL type specified!") return - MiRCARTToPngFile(asciiTmpFilePath, "DejaVuSansMono.ttf", 11).export(imgTmpFilePath) + + canvasStore = MiRCARTCanvasStore(inFile=asciiTmpFilePath) + MiRCARTToPngFile(canvasStore.outMap, "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/MiRCARTCanvas.py b/MiRCARTCanvas.py index f8b5a47..0503889 100644 --- a/MiRCARTCanvas.py +++ b/MiRCARTCanvas.py @@ -23,40 +23,43 @@ # from MiRCARTCanvasJournal import MiRCARTCanvasJournal -from MiRCARTCanvasStore import MiRCARTCanvasStore +from MiRCARTCanvasStore import MiRCARTCanvasStore, haveMiRCARTToPngFile, haveUrllib from MiRCARTColours import MiRCARTColours import wx class MiRCARTCanvas(wx.Panel): """XXX""" parentFrame = None - canvasPos = canvasSize = canvasWinSize = cellPos = cellSize = None + canvasPos = canvasSize = canvasWinSize = cellSize = None canvasBitmap = canvasMap = canvasTools = None - mircBg = mircFg = mircBrushes = mircPens = None + brushColours = brushPos = brushSize = None + mircBrushes = mircPens = None canvasJournal = canvasStore = None # {{{ _initBrushesAndPens(self): XXX def _initBrushesAndPens(self): 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)): + for mircColour in range(len(MiRCARTColours)): self.mircBrushes[mircColour] = wx.Brush( \ - wx.Colour(MiRCARTColours[mircColour]), wx.BRUSHSTYLE_SOLID) + wx.Colour(MiRCARTColours[mircColour][0:4]), wx.BRUSHSTYLE_SOLID) self.mircPens[mircColour] = wx.Pen( \ - wx.Colour(MiRCARTColours[mircColour]), 1) + wx.Colour(MiRCARTColours[mircColour][0:4]), 1) # }}} # {{{ _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]] + absPoint = self._relMapPointToAbsPoint(patch[0], atPoint) + if patch[3] == " ": + brushFg = self.mircBrushes[patch[1][1]] + brushBg = self.mircBrushes[patch[1][0]] + pen = self.mircPens[patch[1][1]] else: - brushFg = self.mircBrushes[patch[2]]; brushBg = self.mircBrushes[patch[3]]; - pen = self.mircPens[patch[2]] + brushFg = self.mircBrushes[patch[1][0]] + brushBg = self.mircBrushes[patch[1][1]] + pen = self.mircPens[patch[1][0]] 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]) + dc.DrawRectangle(*absPoint, *self.cellSize) # }}} # {{{ _eventPointToMapPoint(self, eventPoint): XXX def _eventPointToMapPoint(self, eventPoint): @@ -72,13 +75,11 @@ class MiRCARTCanvas(wx.Panel): # }}} # {{{ _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) + return [(a+b)*c for a,b,c in zip(atPoint, relMapPoint, self.cellSize)] # }}} - # {{{ _setMapCell(self, absMapPoint, colourFg, colourBg, char): XXX - def _setMapCell(self, absMapPoint, colourFg, colourBg, char): - self.canvasMap[absMapPoint[1]][absMapPoint[0]] = [colourFg, colourBg, char] + # {{{ _setMapCell(self, absMapPoint, colours, charAttrs, char): XXX + def _setMapCell(self, absMapPoint, colours, charAttrs, char): + self.canvasMap[absMapPoint[1]][absMapPoint[0]] = [colours, charAttrs, char] # }}} # {{{ onClose(self, event): XXX @@ -86,17 +87,24 @@ class MiRCARTCanvas(wx.Panel): self.Destroy(); self.__del__(); # }}} # {{{ onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): - def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint): + def onJournalUpdate(self, isTmp, absMapPoint, patch, eventDc, tmpDc, atPoint, isInherit=False): if eventDc == None: eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); if tmpDc == None: tmpDc.SelectObject(self.canvasBitmap) if isTmp == True: + if isInherit: + patch[1:] = self._getMapCell(patch[0]) self._drawPatch(patch, eventDc, tmpDc, atPoint) else: - self._setMapCell(absMapPoint, *patch[2:5]) + if isInherit: + patchOld = patch.copy() + patchOld[1:] = self._getMapCell(patchOld[0]) + self._setMapCell(absMapPoint, *patch[1:]) self._drawPatch(patch, eventDc, tmpDc, atPoint) self.parentFrame.onCanvasUpdate() + if isInherit: + return patchOld # }}} # {{{ onMouseEvent(self, event): XXX def onMouseEvent(self, event): @@ -106,14 +114,58 @@ class MiRCARTCanvas(wx.Panel): eventPoint = event.GetLogicalPosition(eventDc) mapPoint = self._eventPointToMapPoint(eventPoint) for tool in self.canvasTools: - mapPatches = tool.onMouseEvent(event, mapPoint, event.Dragging(), \ - event.LeftIsDown(), event.RightIsDown()) + mapPatches = tool.onMouseEvent( \ + event, mapPoint, self.brushColours, self.brushSize, \ + event.Dragging(), event.LeftIsDown(), event.RightIsDown()) self.canvasJournal.merge(mapPatches, eventDc, tmpDc, mapPoint) + self.parentFrame.onCanvasMotion(event, mapPoint) + # }}} + # {{{ onMouseWindowEvent(self, event): XXX + def onMouseWindowEvent(self, event): + eventObject = event.GetEventObject() + eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); + tmpDc.SelectObject(self.canvasBitmap) + self.canvasJournal.resetCursor(eventDc, tmpDc) + self.parentFrame.onCanvasMotion(event) # }}} # {{{ onPaint(self, event): XXX def onPaint(self, event): eventDc = wx.BufferedPaintDC(self, self.canvasBitmap) # }}} + # {{{ onStoreUpdate(self, newCanvasSize, newCanvas=None): + def onStoreUpdate(self, newCanvasSize, newCanvas=None): + if newCanvasSize != None: + self.resize(newCanvasSize) + self.canvasJournal.reset() + if newCanvas != None: + self.canvasMap = newCanvas.copy() + for numRow in range(self.canvasSize[1]): + numRowCols = len(self.canvasMap[numRow]) + if numRowCols < self.canvasSize[0]: + colsDelta = self.canvasSize[0] - numRowCols + self.canvasMap[numRow][self.canvasSize[0]:] = \ + [[(1, 1), 0, " "] for y in range(colsDelta)] + else: + del self.canvasMap[numRow][self.canvasSize[0]:] + else: + self.canvasMap = [[[(1, 1), 0, " "] \ + for x in range(self.canvasSize[0])] \ + for y in range(self.canvasSize[1])] + canvasWinSize = [a*b for a,b in zip(self.canvasSize, self.cellSize)] + if self.canvasBitmap != None: + self.canvasBitmap.Destroy() + self.canvasBitmap = wx.Bitmap(canvasWinSize) + eventDc = wx.ClientDC(self); tmpDc = wx.MemoryDC(); + tmpDc.SelectObject(self.canvasBitmap) + for numRow in range(self.canvasSize[1]): + for numCol in range(self.canvasSize[0]): + self.onJournalUpdate(False, \ + (numCol, numRow), \ + [(numCol, numRow), \ + *self.canvasMap[numRow][numCol]], \ + eventDc, tmpDc, (0, 0)) + wx.SafeYield() + # }}} # {{{ redo(self): XXX def redo(self): return self.canvasJournal.redo() @@ -124,12 +176,12 @@ class MiRCARTCanvas(wx.Panel): self.SetSize(*self.canvasPos, \ newCanvasSize[0] * self.cellSize[0], \ newCanvasSize[1] * self.cellSize[1]) - for numRow in range(0, self.canvasSize[1]): + for numRow in range(self.canvasSize[1]): for numNewCol in range(self.canvasSize[0], newCanvasSize[0]): self.canvasMap[numRow].append([1, 1, " "]) for numNewRow in range(self.canvasSize[1], newCanvasSize[1]): self.canvasMap.append([]) - for numNewCol in range(0, newCanvasSize[0]): + for numNewCol in range(newCanvasSize[0]): self.canvasMap[numNewRow].append([1, 1, " "]) self.canvasSize = newCanvasSize canvasWinSize = ( \ @@ -162,14 +214,16 @@ class MiRCARTCanvas(wx.Panel): self.canvasTools = [canvasTool(self) for canvasTool in canvasTools] self.cellSize = cellSize - self.cellPos = (0, 0) - self.mircBg = 1; self.mircFg = 4; self._initBrushesAndPens(); + self.brushColours = [4, 1]; self._initBrushesAndPens(); + self.brushPos = [0, 0]; self.brushSize = [1, 1]; self.canvasJournal = MiRCARTCanvasJournal(parentCanvas=self) self.canvasStore = MiRCARTCanvasStore(parentCanvas=self) super().__init__(parent, pos=canvasPos, \ size=[w*h for w,h in zip(canvasSize, cellSize)]) self.Bind(wx.EVT_CLOSE, self.onClose) + self.Bind(wx.EVT_ENTER_WINDOW, self.onMouseWindowEvent) + self.Bind(wx.EVT_LEAVE_WINDOW, self.onMouseWindowEvent) self.Bind(wx.EVT_LEFT_DOWN, self.onMouseEvent) self.Bind(wx.EVT_MOTION, self.onMouseEvent) self.Bind(wx.EVT_PAINT, self.onPaint) diff --git a/MiRCARTCanvasJournal.py b/MiRCARTCanvasJournal.py index a712d36..3b70dbc 100644 --- a/MiRCARTCanvasJournal.py +++ b/MiRCARTCanvasJournal.py @@ -31,28 +31,26 @@ class MiRCARTCanvasJournal(): 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.parentCanvas.onJournalUpdate(True, \ + patch[0], patch, eventDc, tmpDc, (0, 0), True) self.patchesTmp = [] # }}} # {{{ _pushTmp(self, atPoint, patch): XXX def _pushTmp(self, absMapPoint): - self.patchesTmp.append([*absMapPoint, None, None, None]) + self.patchesTmp.append([absMapPoint, None, None, None]) # }}} - # {{{ _pushUndo(self, atPoint, patch): XXX - def _pushUndo(self, atPoint, patch, mapItem): + # {{{ _pushUndo(self, atPoint, patchUndo, patchRedo): XXX + def _pushUndo(self, atPoint, patchUndo, patchRedo): 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]))) + absMapPoint = self._relMapPointToAbsMapPoint(patchUndo[0], atPoint) + self.patchesUndo.insert(0, [ \ + [absMapPoint, *patchUndo[1:]], [absMapPoint, *patchRedo[1:]]]) # }}} # {{{ _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): XXX def _relMapPointToAbsMapPoint(self, relMapPoint, atPoint): - return (atPoint[0] + relMapPoint[0], atPoint[1] + relMapPoint[1]) + return [a+b for a,b in zip(atPoint, relMapPoint)] # }}} # {{{ merge(self, mapPatches, eventDc, tmpDc, atPoint): XXX def merge(self, mapPatches, eventDc, tmpDc, atPoint): @@ -61,40 +59,45 @@ class MiRCARTCanvasJournal(): if mapPatchTmp: self._popTmp(eventDc, tmpDc) for patch in mapPatch[1]: - absMapPoint = self._relMapPointToAbsMapPoint(patch[0:2], atPoint) - mapItem = self.parentCanvas._getMapCell(absMapPoint) + absMapPoint = self._relMapPointToAbsMapPoint(patch[0], atPoint) 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, \ + self.parentCanvas.onJournalUpdate(mapPatchTmp, \ absMapPoint, patch, eventDc, tmpDc, atPoint) + else: + patchUndo = \ + self.parentCanvas.onJournalUpdate(mapPatchTmp, \ + absMapPoint, patch, eventDc, tmpDc, atPoint, True) + self._pushUndo(atPoint, patchUndo, patch) # }}} # {{{ 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)) + self.parentCanvas.onJournalUpdate(False, \ + redoPatch[0], redoPatch, None, None, (0, 0)) return True else: return False # }}} # {{{ reset(self): XXX def reset(self): - self.patchesTmp = [] - self.patchesUndo = [None]; self.patchesUndoLevel = 0; + self.patchesTmp = []; self.patchesUndo = [None]; self.patchesUndoLevel = 0; + # }}} + # {{{ resetCursor(self, eventDc, tmpDc): XXX + def resetCursor(self, eventDc, tmpDc): + if len(self.patchesTmp): + self._popTmp(eventDc, tmpDc) + self.patchesTmp = [] # }}} # {{{ 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)) + self.parentCanvas.onJournalUpdate(False, \ + undoPatch[0], undoPatch, None, None, (0, 0)) return True else: return False diff --git a/MiRCARTCanvasStore.py b/MiRCARTCanvasStore.py index a3b106e..8a65cd2 100644 --- a/MiRCARTCanvasStore.py +++ b/MiRCARTCanvasStore.py @@ -22,9 +22,13 @@ # SOFTWARE. # -import base64 import io -import wx + +try: + import wx + haveWx = True +except ImportError: + haveWx = False try: from MiRCARTToPngFile import MiRCARTToPngFile @@ -78,66 +82,59 @@ class MiRCARTCanvasStore(): return cellState | bit # }}} - # {{{ exportPastebin(self, apiDevKey): XXX - def exportPastebin(self, apiDevKey): + # {{{ exportBitmapToPngFile(self, canvasBitmap, outPathName, outType): XXX + def exportBitmapToPngFile(self, canvasBitmap, outPathName, outType): + return canvasBitmap.ConvertToImage().SaveFile(outPathName, outType) + # }}} + # {{{ exportPastebin(self, apiDevKey, canvasMap, canvasSize, pasteName="", pastePrivate=0): XXX + def exportPastebin(self, apiDevKey, canvasMap, canvasSize, pasteName="", pastePrivate=0): if haveUrllib: - outFile = io.StringIO(); self.exportTextFile(outFile); - requestData = { \ - "api_dev_key": self.apiDevKey, \ - "api_option": "paste", \ - "api_paste_code": base64.b64encode(outFile.read()), \ - "api_paste_name": pasteName, \ + outFile = io.StringIO() + self.exportTextFile(canvasMap, canvasSize, outFile) + requestData = { \ + "api_dev_key": apiDevKey, \ + "api_option": "paste", \ + "api_paste_code": outFile.getvalue().encode(), \ + "api_paste_name": pasteName, \ "api_paste_private": pastePrivate} - responseHttp = requests.post("https://pastebin.com/post.php", \ + responseHttp = requests.post("https://pastebin.com/api/api_post.php", \ data=requestData) if responseHttp.status_code == 200: - return responseHttp.text + if responseHttp.text.startswith("http"): + return (True, responseHttp.text) + else: + return (False, responseHttp.text) else: - return None + return (False, str(responseHttp.status_code)) else: - return None + return (False, "missing requests and/or urllib3 module(s)") # }}} - # {{{ exportPngFile(self): XXX - def exportPngFile(self, pathName): + # {{{ exportPngFile(self, canvasMap, outPathName): XXX + def exportPngFile(self, canvasMap, outPathName): if haveMiRCARTToPngFile: - outFile = io.StringIO(); self.exportTextFile(outFile); - MiRCARTToPng(outFile).export(pathName) + MiRCARTToPngFile(canvasMap).export(outPathName) return True else: return False # }}} - # {{{ exportTextFile(self, outFile): XXX - def exportTextFile(self, outFile): - canvasMap = self.parentCanvas.canvasMap - canvasSize = self.parentCanvas.canvasSize - for canvasRow in range(0, canvasSize[1]): + # {{{ exportTextFile(self, canvasMap, canvasSize, outFile): XXX + def exportTextFile(self, canvasMap, canvasSize, outFile): + for canvasRow in range(canvasSize[1]): canvasLastColours = [] - for canvasCol in range(0, canvasSize[0]): - canvasColColours = 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])) + for canvasCol in range(canvasSize[0]): + canvasColColours = canvasMap[canvasRow][canvasCol][0] + canvasColText = canvasMap[canvasRow][canvasCol][2] + if canvasColColours != canvasLastColours: + canvasLastColours = canvasColColours + outFile.write("\x03" + \ + str(canvasColColours[0]) + \ + "," + str(canvasColColours[1])) outFile.write(canvasColText) outFile.write("\n") # }}} # {{{ importIntoPanel(self): XXX def importIntoPanel(self): - canvasSize = self.inSize; self.parentCanvas.resize(canvasSize); - self.parentCanvas.canvasJournal.reset() - eventDc = wx.ClientDC(self.parentCanvas); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.parentCanvas.canvasBitmap) - for numRow in range(0, len(self.outMap)): - for numCol in range(0, len(self.outMap[numRow])): - self.parentCanvas.onJournalUpdate(False, \ - (numCol, numRow), [numCol, numRow, \ - self.outMap[numRow][numCol][0][0], \ - self.outMap[numRow][numCol][0][1], \ - self.outMap[numRow][numCol][2]], \ - eventDc, tmpDc, (0, 0)) - wx.SafeYield() + self.parentCanvas.onStoreUpdate(self.inSize, self.outMap) # }}} # {{{ importTextFile(self, pathName): XXX def importTextFile(self, pathName): @@ -210,26 +207,7 @@ class MiRCARTCanvasStore(): # }}} # {{{ importNew(self, newCanvasSize=None): XXX def importNew(self, newCanvasSize=None): - if newCanvasSize != None: - self.parentCanvas.resize(newCanvasSize) - self.parentCanvas.canvasJournal.reset() - self.parentCanvas.canvasMap = [[[1, 1, " "] \ - for x in range(self.parentCanvas.canvasSize[0])] \ - for y in range(self.parentCanvas.canvasSize[1])] - canvasWinSize = ( \ - self.parentCanvas.cellSize[0] * self.parentCanvas.canvasSize[0], \ - self.parentCanvas.cellSize[1] * self.parentCanvas.canvasSize[1]) - if self.parentCanvas.canvasBitmap != None: - self.parentCanvas.canvasBitmap.Destroy() - self.parentCanvas.canvasBitmap = wx.Bitmap(canvasWinSize) - eventDc = wx.ClientDC(self.parentCanvas); tmpDc = wx.MemoryDC(); - tmpDc.SelectObject(self.parentCanvas.canvasBitmap) - for numRow in range(0, len(self.parentCanvas.canvasMap)): - for numCol in range(0, len(self.parentCanvas.canvasMap[numRow])): - self.parentCanvas.onJournalUpdate(False, \ - (numCol, numRow), [numCol, numRow, 1, 1, " "], \ - eventDc, tmpDc, (0, 0)) - wx.SafeYield() + self.parentCanvas.onStoreUpdate(newCanvasSize) # }}} # diff --git a/MiRCARTColours.py b/MiRCARTColours.py index 9489b08..2475cc6 100755 --- a/MiRCARTColours.py +++ b/MiRCARTColours.py @@ -23,25 +23,25 @@ # # -# MiRCARTColours: mIRC colour number to RGBA map given none of ^[BFV_] (bold, italic, reverse, underline) +# 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 + [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 index 058dae0..79af864 100644 --- a/MiRCARTFrame.py +++ b/MiRCARTFrame.py @@ -22,61 +22,59 @@ # SOFTWARE. # -from MiRCARTCanvas import MiRCARTCanvas +from MiRCARTCanvas import MiRCARTCanvas, haveUrllib from MiRCARTColours import MiRCARTColours +from MiRCARTGeneralFrame import MiRCARTGeneralFrame, \ + TID_COMMAND, TID_MENU, TID_NOTHING, TID_SELECT, TID_TOOLBAR, TID_ACCELS + import os, wx -class MiRCARTFrame(wx.Frame): +class MiRCARTFrame(MiRCARTGeneralFrame): """XXX""" - panelSkin = panelCanvas = canvasPathName = None + 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_SELECT = (0x004) - TID_TOOLBAR = (0x005) - TID_ACCELS = (0x006) - # }}} # {{{ Commands # Id Type Id Labels Icon bitmap Accelerator [Initial state] - 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, False) - CID_EXPORT_PASTEBIN = (0x105, TID_COMMAND, "Export to Pastebin...", "Export to Pasteb&in...", (), None, False) - CID_EXIT = (0x106, TID_COMMAND, "Exit", "E&xit", (), None) - CID_UNDO = (0x107, TID_COMMAND, "Undo", "&Undo", [wx.ART_UNDO], (wx.ACCEL_CTRL, ord("Z")), False) - CID_REDO = (0x108, TID_COMMAND, "Redo", "&Redo", [wx.ART_REDO], (wx.ACCEL_CTRL, ord("Y")), False) - CID_CUT = (0x109, TID_COMMAND, "Cut", "Cu&t", [wx.ART_CUT], None, False) - CID_COPY = (0x10a, TID_COMMAND, "Copy", "&Copy", [wx.ART_COPY], None, False) - CID_PASTE = (0x10b, TID_COMMAND, "Paste", "&Paste", [wx.ART_PASTE], None, False) - CID_DELETE = (0x10c, TID_COMMAND, "Delete", "De&lete", [wx.ART_DELETE], None, False) - 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_SOLID_BRUSH = (0x10f, TID_SELECT, "Solid brush", "&Solid brush", [None], None, True) - CID_RECT = (0x110, TID_SELECT, "Rectangle", "&Rectangle", [None], None, True) - CID_CIRCLE = (0x111, TID_SELECT, "Circle", "&Circle", [None], None, False) - CID_LINE = (0x112, TID_SELECT, "Line", "&Line", [None], None, False) - 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) + CID_NEW = (0x100, TID_COMMAND, "New", "&New", wx.ART_NEW, (wx.ACCEL_CTRL, ord("N"))) + CID_OPEN = (0x101, TID_COMMAND, "Open", "&Open", wx.ART_FILE_OPEN, (wx.ACCEL_CTRL, ord("O"))) + CID_SAVE = (0x102, TID_COMMAND, "Save", "&Save", wx.ART_FILE_SAVE, (wx.ACCEL_CTRL, ord("S"))) + 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, None) + CID_EXPORT_PASTEBIN = (0x105, TID_COMMAND, "Export to Pastebin...", \ + "Export to Pasteb&in...", None, None, haveUrllib) + CID_EXIT = (0x106, TID_COMMAND, "Exit", "E&xit", None, None) + CID_UNDO = (0x107, TID_COMMAND, "Undo", "&Undo", wx.ART_UNDO, (wx.ACCEL_CTRL, ord("Z")), False) + CID_REDO = (0x108, TID_COMMAND, "Redo", "&Redo", wx.ART_REDO, (wx.ACCEL_CTRL, ord("Y")), False) + CID_CUT = (0x109, TID_COMMAND, "Cut", "Cu&t", wx.ART_CUT, None, False) + CID_COPY = (0x10a, TID_COMMAND, "Copy", "&Copy", wx.ART_COPY, None, False) + CID_PASTE = (0x10b, TID_COMMAND, "Paste", "&Paste", wx.ART_PASTE, None, False) + CID_DELETE = (0x10c, TID_COMMAND, "Delete", "De&lete", wx.ART_DELETE, None, False) + 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_SOLID_BRUSH = (0x10f, TID_SELECT, "Solid brush", "&Solid brush", None, None, True) + CID_RECT = (0x110, TID_SELECT, "Rectangle", "&Rectangle", None, None, True) + CID_CIRCLE = (0x111, TID_SELECT, "Circle", "&Circle", None, None, False) + CID_LINE = (0x112, TID_SELECT, "Line", "&Line", None, None, False) + CID_COLOUR00 = (0x113, TID_COMMAND, "Colour #00", "Colour #00", None, None) + CID_COLOUR01 = (0x114, TID_COMMAND, "Colour #01", "Colour #01", None, None) + CID_COLOUR02 = (0x115, TID_COMMAND, "Colour #02", "Colour #02", None, None) + CID_COLOUR03 = (0x116, TID_COMMAND, "Colour #03", "Colour #03", None, None) + CID_COLOUR04 = (0x117, TID_COMMAND, "Colour #04", "Colour #04", None, None) + CID_COLOUR05 = (0x118, TID_COMMAND, "Colour #05", "Colour #05", None, None) + CID_COLOUR06 = (0x119, TID_COMMAND, "Colour #06", "Colour #06", None, None) + CID_COLOUR07 = (0x11a, TID_COMMAND, "Colour #07", "Colour #07", None, None) + CID_COLOUR08 = (0x11b, TID_COMMAND, "Colour #08", "Colour #08", None, None) + CID_COLOUR09 = (0x11c, TID_COMMAND, "Colour #09", "Colour #09", None, None) + CID_COLOUR10 = (0x11d, TID_COMMAND, "Colour #10", "Colour #10", None, None) + CID_COLOUR11 = (0x11e, TID_COMMAND, "Colour #11", "Colour #11", None, None) + CID_COLOUR12 = (0x11f, TID_COMMAND, "Colour #12", "Colour #12", None, None) + CID_COLOUR13 = (0x120, TID_COMMAND, "Colour #13", "Colour #13", None, None) + CID_COLOUR14 = (0x121, TID_COMMAND, "Colour #14", "Colour #14", None, None) + CID_COLOUR15 = (0x122, TID_COMMAND, "Colour #15", "Colour #15", None, None) # }}} # {{{ Non-items NID_MENU_SEP = (0x200, TID_NOTHING) @@ -107,79 +105,61 @@ class MiRCARTFrame(wx.Frame): CID_COLOUR15)) # }}} # {{{ Accelerators (hotkeys) - AID_EDIT = (0x500, TID_ACCELS, (CID_UNDO, CID_REDO)) + AID_EDIT = (0x500, TID_ACCELS, ( \ + CID_NEW, CID_OPEN, CID_SAVE, 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 + # {{{ _dialogSaveChanges(self) + def _dialogSaveChanges(self): + with wx.MessageDialog(self, \ + "Do you want to save changes to {}?".format( \ + self.canvasPathName), "MiRCART", \ + wx.CANCEL|wx.CANCEL_DEFAULT|wx.ICON_QUESTION|wx.YES_NO) as dialog: + dialogChoice = dialog.ShowModal() + return dialogChoice # }}} - # {{{ _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 + # {{{ _setPaletteToolBitmaps(self): XXX + def _setPaletteToolBitmaps(self): + paletteDescr = ( \ + self.CID_COLOUR00, self.CID_COLOUR01, self.CID_COLOUR02, self.CID_COLOUR03, self.CID_COLOUR04, \ + self.CID_COLOUR05, self.CID_COLOUR06, self.CID_COLOUR07, self.CID_COLOUR08, self.CID_COLOUR09, \ + self.CID_COLOUR10, self.CID_COLOUR11, self.CID_COLOUR12, self.CID_COLOUR13, self.CID_COLOUR14, \ + self.CID_COLOUR15) + for numColour in range(len(paletteDescr)): + toolBitmapColour = MiRCARTColours[numColour][0:4] + toolBitmap = wx.Bitmap((16,16)) + toolBitmapDc = wx.MemoryDC(); toolBitmapDc.SelectObject(toolBitmap); + toolBitmapBrush = wx.Brush( \ + wx.Colour(toolBitmapColour), wx.BRUSHSTYLE_SOLID) + toolBitmapDc.SetBrush(toolBitmapBrush) + toolBitmapDc.SetBackground(toolBitmapBrush) + toolBitmapDc.SetPen(wx.Pen(wx.Colour(toolBitmapColour), 1)) + toolBitmapDc.DrawRectangle(0, 0, 16, 16) + self.toolBar.SetToolNormalBitmap( \ + paletteDescr[numColour][0], toolBitmap) # }}} - # {{{ _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() - elif menuItem[1] == self.TID_SELECT: - menuItemWindow = menuWindow.AppendRadioItem(menuItem[0], menuItem[3], menuItem[2]) - self.menuItemsById[menuItem[0]] = menuItemWindow - self.Bind(wx.EVT_MENU, handler, menuItemWindow) - if len(menuItem) == 7: - menuItemWindow.Check(menuItem[6]) - else: - menuItemWindow = menuWindow.Append(menuItem[0], menuItem[3], menuItem[2]) - self.menuItemsById[menuItem[0]] = menuItemWindow - self.Bind(wx.EVT_MENU, handler, menuItemWindow) - if len(menuItem) == 7: - menuItemWindow.Enable(menuItem[6]) - 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) + # {{{ _updateStatusBar(self, showColours=None, showFileName=True, showPos=None): XXX + def _updateStatusBar(self, showColours=True, showFileName=True, showPos=True): + if showColours == True: + showColours = self.panelCanvas.brushColours + if showPos == True: + showPos = self.panelCanvas.brushPos + if showFileName == True: + showFileName = self.canvasPathName + textItems = [] + if showPos != None: + textItems.append("X: {:03d} Y: {:03d}".format( \ + showPos[0], showPos[1])) + if showColours != None: + textItems.append("FG: {:02d}, BG: {:02d}".format( \ + showColours[0],showColours[1])) + textItems.append("{} on {}".format( \ + MiRCARTColours[showColours[0]][4], \ + MiRCARTColours[showColours[1]][4])) + if showFileName != None: + textItems.append("Current file: {}".format( \ + os.path.basename(showFileName))) + self.statusBar.SetStatusText(" | ".join(textItems)) # }}} # {{{ canvasExportAsPng(self): XXX @@ -189,31 +169,57 @@ class MiRCARTFrame(wx.Frame): if dialog.ShowModal() == wx.ID_CANCEL: return False else: - try: - outPathName = dialog.GetPath() - self.panelCanvas.exportPngFile(outhPathName) - return True - except IOError as error: - pass + outPathName = dialog.GetPath() + self.panelCanvas.canvasStore.exportBitmapToPngFile( \ + self.panelCanvas.canvasBitmap, outPathName, \ + wx.BITMAP_TYPE_PNG) + return True # }}} # {{{ canvasExportPastebin(self): XXX def canvasExportPastebin(self): - try: - self.panelCanvas.exportPastebin("") - return True - except IOError as error: - pass + pasteStatus, pasteResult = \ + self.panelCanvas.canvasStore.exportPastebin( \ + "", \ + self.panelCanvas.canvasMap, \ + self.panelCanvas.canvasSize) + if pasteStatus: + if not wx.TheClipboard.IsOpened(): + wx.TheClipboard.Open() + wx.TheClipboard.SetData(wx.TextDataObject(pasteResult)) + wx.TheClipboard.Close() + wx.MessageBox("Exported to Pastebin: " + pasteResult, \ + "Export to Pastebin", wx.OK|wx.ICON_INFORMATION) + else: + wx.MessageBox("Failed to export to Pastebin: " + pasteResult, \ + "Export to Pastebin", wx.OK|wx.ICON_EXCLAMATION) # }}} # {{{ canvasNew(self, newCanvasSize=None): XXX def canvasNew(self, newCanvasSize=None): + 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() if newCanvasSize == None: newCanvasSize = (100, 30) self.panelCanvas.canvasStore.importNew(newCanvasSize) + self.canvasPathName = None self._updateStatusBar(); self.onCanvasUpdate(); # }}} # {{{ canvasOpen(self): XXX def canvasOpen(self): - with wx.FileDialog(self, self.CID_OPEN[2], os.getcwd(), "", \ + 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() + with wx.FileDialog(self, self.CID_OPEN[2], os.getcwd(), "", \ "*.txt", wx.FD_OPEN) as dialog: if dialog.ShowModal() == wx.ID_CANCEL: return False @@ -230,10 +236,13 @@ class MiRCARTFrame(wx.Frame): if self.canvasSaveAs() == False: return try: - self.panelCanvas.exportTextFile(self.canvasPathName) - return True + with open(self.canvasPathName, "w") as outFile: + self.panelCanvas.canvasStore.exportTextFile( \ + self.panelCanvas.canvasMap, \ + self.panelCanvas.canvasSize, outFile) + return True except IOError as error: - pass + return False # }}} # {{{ canvasSaveAs(self): XXX def canvasSaveAs(self): @@ -243,22 +252,32 @@ class MiRCARTFrame(wx.Frame): return False else: self.canvasPathName = dialog.GetPath() - return True + return self.canvasSave() + # }}} + # {{{ onCanvasMotion(self, event): XXX + def onCanvasMotion(self, event, mapPoint=None): + eventType = event.GetEventType() + if eventType == wx.wxEVT_ENTER_WINDOW: + pass + elif eventType == wx.wxEVT_MOTION: + self._updateStatusBar(showPos=mapPoint) + elif eventType == wx.wxEVT_LEAVE_WINDOW: + pass # }}} # {{{ onCanvasUpdate(self): XXX def onCanvasUpdate(self): if self.panelCanvas.canvasJournal.patchesUndo[self.panelCanvas.canvasJournal.patchesUndoLevel] != None: self.menuItemsById[self.CID_UNDO[0]].Enable(True) + self.toolBar.EnableTool(self.CID_UNDO[0], True) else: self.menuItemsById[self.CID_UNDO[0]].Enable(False) + self.toolBar.EnableTool(self.CID_UNDO[0], False) if self.panelCanvas.canvasJournal.patchesUndoLevel > 0: self.menuItemsById[self.CID_REDO[0]].Enable(True) + self.toolBar.EnableTool(self.CID_REDO[0], True) else: self.menuItemsById[self.CID_REDO[0]].Enable(False) - # }}} - # {{{ onClose(self, event): XXX - def onClose(self, event): - self.Destroy(); self.__del__(); + self.toolBar.EnableTool(self.CID_REDO[0], False) # }}} # {{{ onFrameCommand(self, event): XXX def onFrameCommand(self, event): @@ -305,9 +324,9 @@ class MiRCARTFrame(wx.Frame): and cid <= self.CID_COLOUR15[0]: numColour = cid - self.CID_COLOUR00[0] if event.GetEventType() == wx.wxEVT_TOOL: - self.panelCanvas.mircFg = numColour + self.panelCanvas.brushColours[0] = numColour elif event.GetEventType() == wx.wxEVT_TOOL_RCLICKED: - self.panelCanvas.mircBg = numColour + self.panelCanvas.brushColours[1] = numColour self._updateStatusBar() # }}} # {{{ __del__(self): destructor method @@ -319,32 +338,13 @@ class MiRCARTFrame(wx.Frame): # # __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) + panelSkin = super().__init__(parent, wx.ID_ANY, "MiRCART", size=appSize) + self._setPaletteToolBitmaps() self.canvasPos = canvasPos; self.cellSize = cellSize; self.canvasSize = canvasSize; 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) - - 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.panelCanvas = MiRCARTCanvas(self.panelSkin, parentFrame=self, \ - canvasPos=self.canvasPos, canvasSize=self.canvasSize, \ + self.panelCanvas = MiRCARTCanvas(panelSkin, parentFrame=self, \ + canvasPos=self.canvasPos, canvasSize=self.canvasSize, \ canvasTools=self.canvasTools, cellSize=self.cellSize) self.canvasNew() diff --git a/MiRCARTGeneralFrame.py b/MiRCARTGeneralFrame.py new file mode 100644 index 0000000..798af47 --- /dev/null +++ b/MiRCARTGeneralFrame.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# +# MiRCARTGeneralFrame.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. +# + +import os, wx + +# +# Types +TID_COMMAND = (0x001) +TID_MENU = (0x002) +TID_NOTHING = (0x003) +TID_SELECT = (0x004) +TID_TOOLBAR = (0x005) +TID_ACCELS = (0x006) + +class MiRCARTGeneralFrame(wx.Frame): + """XXX""" + menuItemsById = toolBarItemsById = None + statusBar = toolBar = None + + # {{{ _initAccelTable(self, accelsDescr, handler): XXX + def _initAccelTable(self, accelsDescr, handler): + accelTableEntries = [wx.AcceleratorEntry() for n in range(len(accelsDescr[2]))] + for numAccel in range(len(accelsDescr[2])): + accelDescr = accelsDescr[2][numAccel] + if accelDescr[5] != None: + accelTableEntries[numAccel].Set(*accelDescr[5], 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() + elif menuItem[1] == TID_SELECT: + menuItemWindow = menuWindow.AppendRadioItem(menuItem[0], menuItem[3], menuItem[2]) + self.menuItemsById[menuItem[0]] = menuItemWindow + self.Bind(wx.EVT_MENU, handler, menuItemWindow) + if len(menuItem) == 7: + menuItemWindow.Check(menuItem[6]) + else: + menuItemWindow = menuWindow.Append(menuItem[0], menuItem[3], menuItem[2]) + self.menuItemsById[menuItem[0]] = menuItemWindow + self.Bind(wx.EVT_MENU, handler, menuItemWindow) + if len(menuItem) == 7: + menuItemWindow.Enable(menuItem[6]) + 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 toolBarItem[4] != None: + toolBarItemIcon = wx.ArtProvider.GetBitmap( \ + toolBarItem[4], 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.toolBarItemsById[toolBarItem[0]] = toolBarItemWindow + if len(toolBarItem) == 7 \ + and toolBarItem[1] == TID_COMMAND: + toolBarItemWindow.Enable(toolBarItem[6]) + self.Bind(wx.EVT_TOOL, handler, toolBarItemWindow) + self.Bind(wx.EVT_TOOL_RCLICKED, handler, toolBarItemWindow) + # }}} + # {{{ onClose(self, event): XXX + def onClose(self, event): + self.Destroy(); self.__del__(); + # }}} + # {{{ onFrameCommand(self, event): XXX + def onFrameCommand(self, event): + pass + # }}} + + # + # __init__(self, *args, **kwargs): initialisation method + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + panelSkin = wx.Panel(self, wx.ID_ANY) + + # Initialise menu bar, menus & menu items + self.menuItemsById = {}; menuBar = wx.MenuBar(); + self._initMenus(menuBar, \ + [self.MID_FILE, self.MID_EDIT, self.MID_TOOLS], + self.onFrameCommand) + self.SetMenuBar(menuBar) + + # Initialise toolbar & toolbar items + self.toolBarItemsById = {} + self.toolBar = wx.ToolBar(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(); + + # Initialise accelerators (hotkeys) + accelTable = wx.AcceleratorTable( \ + self._initAccelTable(self.AID_EDIT, self.onFrameCommand)) + self.SetAcceleratorTable(accelTable) + + # Initialise status bar + self.statusBar = self.CreateStatusBar() + + # Bind event handlers + self.Bind(wx.EVT_CLOSE, self.onClose) + + # Set focus on & show window + self.SetFocus(); self.Show(True); + + return panelSkin + +# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/MiRCARTToPngFile.py b/MiRCARTToPngFile.py index 8503b41..cf6e7de 100755 --- a/MiRCARTToPngFile.py +++ b/MiRCARTToPngFile.py @@ -22,13 +22,13 @@ # SOFTWARE. # +import MiRCARTCanvasStore from PIL import Image, ImageDraw, ImageFont -from MiRCARTFromTextFile import MiRCARTFromTextFile import string, sys class MiRCARTToPngFile: """XXX""" - inFile = inFilePath = inFromTextFile = None + inFile = inFromTextFile = None outFontFilePath = outFontSize = None # {{{ _ColourMapBold: mIRC colour number to RGBA map given ^B (bold) @@ -81,23 +81,23 @@ class MiRCARTToPngFile: # }}} # {{{ export(self, outFilePath): XXX def export(self, outFilePath): - inSize = self.inFromTextFile.getSize(); - outSize = [inSize[n] * self.outImgFontSize[n] for n in range(0, 2)] + 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) - for inCurRow in range(0, inSize[1]): - for inCurCol in range(0, len(self.inFromTextFile.outMap[inCurRow])): - inCurCell = self.inFromTextFile.outMap[inCurRow][inCurCol] + 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[1] & MiRCARTFromTextFile._CellState.CS_BOLD: + if inCurCell[1] & 0x02: 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]] + outColours[1] = self._ColourMapNormal[inCurCell[0][1]] outImgDraw.rectangle((*outCurPos, \ outCurPos[0] + self.outImgFontSize[0], \ outCurPos[1] + self.outImgFontSize[1]), \ @@ -107,7 +107,7 @@ class MiRCARTToPngFile: # XXX implement italic outImgDraw.text(outCurPos, \ inCurCell[2], (*outColours[0], 255), self.outImgFont) - if inCurCell[1] & MiRCARTFromTextFile._CellState.CS_UNDERLINE: + if inCurCell[1] & 0x1f: self._drawUnderLine(curPos, self.outImgFontSize, outImgDraw) outCurPos[0] += self.outImgFontSize[0]; outCurPos[0] = 0 @@ -116,11 +116,9 @@ class MiRCARTToPngFile: # }}} # - # __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) - + # __init__(self, inCanvasMap, fontFilePath="DejaVuSansMono.ttf", fontSize=11): initialisation method + def __init__(self, inCanvasMap, fontFilePath="DejaVuSansMono.ttf", fontSize=11): + self.inCanvasMap = inCanvasMap self.outFontFilePath = fontFilePath; self.outFontSize = int(fontSize); self.outImgFont = ImageFont.truetype( \ self.outFontFilePath, self.outFontSize) @@ -130,7 +128,8 @@ class MiRCARTToPngFile: # # Entry point def main(*argv): - MiRCARTToPngFile(argv[1], *argv[3:]).export(argv[2]) + canvasStore = MiRCARTCanvasStore.MiRCARTCanvasStore(inFile=argv[1]) + MiRCARTToPngFile(canvasStore.outMap, *argv[3:]).export(argv[2]) if __name__ == "__main__": if ((len(sys.argv) - 1) < 2)\ or ((len(sys.argv) - 1) > 4): diff --git a/MiRCARTTool.py b/MiRCARTTool.py index 0dad5ad..ae91e6d 100644 --- a/MiRCARTTool.py +++ b/MiRCARTTool.py @@ -26,8 +26,8 @@ class MiRCARTTool(): """XXX""" parentCanvas = None - # {{{ onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX - def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): + # {{{ onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX + def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): pass # }}} diff --git a/MiRCARTToolRect.py b/MiRCARTToolRect.py index b9e9fb2..71e226d 100644 --- a/MiRCARTToolRect.py +++ b/MiRCARTToolRect.py @@ -28,25 +28,19 @@ class MiRCARTToolRect(MiRCARTTool): """XXX""" # - # onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): XXX - def onMouseEvent(self, event, mapPoint, isDragging, isLeftDown, isRightDown): + # onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): XXX + def onMouseEvent(self, event, atPoint, brushColours, brushSize, isDragging, isLeftDown, isRightDown): + brushColours = brushColours.copy() if isLeftDown: - return [[False, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]], - [True, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]]] + brushColours[1] = brushColours[0] + return [[False, [[[0, 0], brushColours, 0, " "]]], \ + [True, [[[0, 0], brushColours, 0, " "]]]] elif isRightDown: - return [[False, [[0, 0, \ - self.parentCanvas.mircBg, \ - self.parentCanvas.mircBg, " "]]], \ - [True, [[0, 0, \ - self.parentCanvas.mircBg, \ - self.parentCanvas.mircBg, " "]]]] + brushColours[0] = brushColours[1] + return [[False, [[[0, 0], brushColours, 0, " "]]], \ + [True, [[[0, 0], brushColours, 0, " "]]]] else: - return [[True, [[0, 0, \ - self.parentCanvas.mircFg, \ - self.parentCanvas.mircFg, " "]]]] + brushColours[1] = brushColours[0] + return [[True, [[[0, 0], brushColours, 0, " "]]]] # vim:expandtab foldmethod=marker sw=4 ts=4 tw=120 diff --git a/README.md b/README.md index 5785840..2795ff8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MiRCART.py -- mIRC art editor for Windows & Linux (WIP) -* Prerequisites on Windows: install Python v3.6.x[1] and wxPython v4.x.x w/ the following elevated command prompt command line: - `pip install wxPython` +* Prerequisites on Windows: install Python v3.6.x[1] and script dependencies w/ the following elevated command prompt command line: + `pip install requests urllib3 wxPython` * Prerequisites on Linux: python3 && python-wx{gtk2.8,tools} on Debian-family Linux distributions * Screenshot: ![Screenshot](https://github.com/lalbornoz/MiRCARTools/raw/master/MiRCART.png "Screenshot")