diff --git a/assets/text/TODO b/assets/text/TODO index f67bf8f..74f9ab4 100644 --- a/assets/text/TODO +++ b/assets/text/TODO @@ -4,20 +4,18 @@ 4) Open and toggle a reference image in the background 5) Client-Server or Peer-to-Peer realtime collaboration 6) Arbitrary {format,palette}s ({4,8} bit ANSI/mIRC, etc.) -7) Hotkey & graphical interfaces to {composed,parametrised} tools -8) Incremental auto{load,save} & {backup,restore} (needs Settings window) -9) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...) -10) Composition and parametrisation of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools; unit tools: - a) geometric primitives (arrow, circle, cloud/speech bubble, curve, heart, hexagon, line, pentagon, polygon, rhombus, triangle, square, star) - b) regions (crop, duplicate, erase, fill, invert, measure, pick, rotate, scale, select, shift, slice, tile, translate) - c) text (edit, Unicode sets) -11) GUI: - a) {copy,cut,insert from,paste}, {de,in}crease cell size - b) replace logo w/ canvas panel in About dialogue - c) switch from wxPython to GTK - d) edit asset in new canvas - e) MRU {directories,files} - f) ruler -12) fix outstanding {re,un}do bugs +7) Incremental auto{load,save} & {backup,restore} (needs Settings window) +8) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...) +9) Composition, parametrisation & keying of tools from higher-order operators (brushes, filters, outlines, patterns & shaders) and unit tools +10) GUI: a) switch to GTK b) replace logo w/ canvas panel in About dialogue c) {copy,cut,insert from,paste}, {edit asset in new canvas,import from canvas} + +High-priority list: +1) geometric primitives: arrow, circle, cloud/speech bubble, curve, heart, hexagon, line, pentagon, polygon, rhombus, triangle, square, star +2) region filters: crop, duplicate, erase, fill, invert, measure, pick, rotate, scale, select, shift, slice, tile, translate +3) text tool: a) allow navigating w/ cursor keys b) Unicode set key & GUI w/ MRU +4) fix outstanding {re,un}do bugs +5) GUI: {de,in}crease cell size +6) GUI: MRU {directories,files} +7) cleanup & refactor vim:ff=dos tw=0 diff --git a/libcanvas/CanvasJournal.py b/libcanvas/CanvasJournal.py index 1956115..e76c140 100644 --- a/libcanvas/CanvasJournal.py +++ b/libcanvas/CanvasJournal.py @@ -7,12 +7,12 @@ class CanvasJournal(): # {{{ begin(self) def begin(self): - deltaItem = [[], []]; self.patchesUndo.insert(0, deltaItem); + deltaItem = [[], []]; self.patchesUndo.insert(self.patchesUndoLevel, deltaItem); # }}} # {{{ end(self) def end(self): - if self.patchesUndo[0] == [[], []]: - del self.patchesUndo[0] + if self.patchesUndo[self.patchesUndoLevel] == [[], []]: + del self.patchesUndo[self.patchesUndoLevel] # }}} # {{{ popCursor(self) def popCursor(self): @@ -56,7 +56,8 @@ class CanvasJournal(): # }}} # {{{ updateCurrentDeltas(self, redoPatches, undoPatches) def updateCurrentDeltas(self, redoPatches, undoPatches): - self.patchesUndo[0][0].append(undoPatches); self.patchesUndo[0][1].append(redoPatches); + self.patchesUndo[self.patchesUndoLevel][0].append(undoPatches) + self.patchesUndo[self.patchesUndoLevel][1].append(redoPatches) # }}} # {{{ __del__(self): destructor method diff --git a/libgui/GuiWindow.py b/libgui/GuiWindow.py index ed476cb..91fb6b6 100644 --- a/libgui/GuiWindow.py +++ b/libgui/GuiWindow.py @@ -21,6 +21,10 @@ class GuiWindow(wx.ScrolledWindow): def onClose(self, event): self.Destroy() # }}} + # {{{ onEnterWindow(self, event) + def onEnterWindow(self, event): + event.Skip() + # }}} # {{{ onKeyboardInput(self, event) def onKeyboardInput(self, event): return False @@ -60,10 +64,10 @@ class GuiWindow(wx.ScrolledWindow): super().__init__(parent, pos=pos, size=size, style=style) self.pos, self.scrollFlag, self.scrollStep, self.size = pos, False, scrollStep, size for eventType, f in ( - (wx.EVT_CHAR, self.onKeyboardInput), (wx.EVT_CLOSE, self.onClose), (wx.EVT_LEAVE_WINDOW, self.onLeaveWindow), - (wx.EVT_LEFT_DOWN, self.onMouseInput), (wx.EVT_MOTION, self.onMouseInput), (wx.EVT_PAINT, self.onPaint), - (wx.EVT_RIGHT_DOWN, self.onMouseInput), (wx.EVT_SCROLLWIN_LINEDOWN, self.onScroll), (wx.EVT_SCROLLWIN_LINEUP, self.onScroll), - (wx.EVT_SIZE, self.onSize)): + (wx.EVT_CHAR, self.onKeyboardInput), (wx.EVT_CLOSE, self.onClose), (wx.EVT_ENTER_WINDOW, self.onEnterWindow), + (wx.EVT_LEAVE_WINDOW, self.onLeaveWindow), (wx.EVT_LEFT_DOWN, self.onMouseInput), (wx.EVT_MOTION, self.onMouseInput), + (wx.EVT_PAINT, self.onPaint), (wx.EVT_RIGHT_DOWN, self.onMouseInput), (wx.EVT_SCROLLWIN_LINEDOWN, self.onScroll), + (wx.EVT_SCROLLWIN_LINEUP, self.onScroll), (wx.EVT_SIZE, self.onSize)): self.Bind(eventType, f) self.SetScrollRate(*self.scrollStep); self._updateScrollBars(); diff --git a/libroar/RoarCanvasWindow.py b/libroar/RoarCanvasWindow.py index de96c1b..0f6c27f 100644 --- a/libroar/RoarCanvasWindow.py +++ b/libroar/RoarCanvasWindow.py @@ -49,10 +49,13 @@ class RoarCanvasWindow(GuiWindow): dirty, self.canvas.dirtyCursor, rc = False, False, False self.canvas.journal.begin() if eventMouse: - if (mapPoint[0] < self.canvas.size[0]) \ - and (mapPoint[1] < self.canvas.size[1]): - self.brushPos = mapPoint + if ((mapPoint[0] < self.canvas.size[0]) \ + and (mapPoint[1] < self.canvas.size[1])) \ + and ((self.dirtyLastCell == None) or (self.dirtyLastCell != mapPoint)): + self.brushPos = list(mapPoint) rc, dirty = tool.onMouseEvent(self.brushColours, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, self.brushPos, mouseDragging, mouseLeftDown, mouseRightDown, viewRect) + if dirty: + self.dirtyLastCell = list(mapPoint) else: rc, dirty = tool.onKeyboardEvent(self.brushColours, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, keyChar, keyModifiers, self.brushPos, viewRect) if dirty: @@ -122,10 +125,15 @@ class RoarCanvasWindow(GuiWindow): if not self.applyTool(eventDc, False, keyChar, keyModifiers, None, None, None, None, self.commands.currentTool, viewRect): event.Skip() # }}} + # {{{ onEnterWindow(self, event) + def onEnterWindow(self, event): + self.dirtyLastCell = None + # }}} # {{{ onLeaveWindow(self, event) def onLeaveWindow(self, event): eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, self.GetViewStart()) self.backend.drawCursorMaskWithJournal(self.canvas.journal, eventDc, self.GetViewStart()) + self.dirtyLastCell = None # }}} # {{{ onMouseInput(self, event) def onMouseInput(self, event): @@ -154,7 +162,7 @@ class RoarCanvasWindow(GuiWindow): def __init__(self, backend, canvas, cellSize, commands, parent, parentFrame, pos, scrollStep, size): super().__init__(parent, pos, scrollStep, [w * h for w, h in zip(cellSize, size)]) self.backend, self.canvas, self.cellSize, self.commands, self.parentFrame = backend(self.size, cellSize), canvas, cellSize, commands(self, parentFrame), parentFrame - self.brushColours, self.brushPos, self.brushSize, self.dirty = [4, 1], [0, 0], [1, 1], False + self.brushColours, self.brushPos, self.brushSize, self.dirty, self.dirtyLastCell = [4, 1], [0, 0], [1, 1], False, None self.dropTarget = RoarCanvasWindowDropTarget(self) self.SetDropTarget(self.dropTarget)