Fully implement {{arrow keys,backspace,enter},arrow keys} in {text,} tool{,s}.

libroar/RoarCanvasWindow.py:applyTool(): delegate updating of brushPos to ToolText if current tool.
libroar/RoarCanvasWindow.py:applyTool(): fix function result.
libroar/RoarCanvasWindow.py:applyTool(): pass updated set of arguments to on{Keyboard,Mouse}Event().
libroar/RoarCanvasWindow.py:onKeyboardInput(): allow wrapping around canvas when receiving cursor key input.
libroar/RoarCanvasWindow.py:onKeyboardInput(): supply keyCode or None to applyTool().
libroar/RoarCanvas{CommandsTools,Window}.py: supply keyCode or None to applyTool().
libtools/Tool{,Circle,Fill,Line,Object,Rect}.py:on{Keyboard,Mouse}Event(): update type signature.
libtools/ToolText.py:onKeyboardEvent(): fully implement {arrow keys,backspace,enter}.
libtools/ToolText.py:onKeyboardEvent(): update cursor when necessary.
libtools/ToolText.py:onMouseEvent(): correctly set brushPos if mouseLeftDown or mouseRightDown.
libtools/ToolText.py:__init__(): removed.
assets/text/TODO: updated.
This commit is contained in:
Lucio Andrés Illanes Albornoz 2019-09-16 09:55:30 +02:00
parent 299a045aa9
commit 99369626c4
10 changed files with 86 additions and 65 deletions

View File

@ -20,11 +20,10 @@ High-priority list:
d) {copy,cut,delete,insert from,paste}, {edit asset in new canvas,import from {canvas,object}}
Queue:
1) start @ top, down key til cursor below visible canvas, scroll down, cursor gone GRRRR
2) text tool: impl. backspace & enter, update internal brushPos if updated w/ arrow keys
3) text tool: a) honour RTL text flow b) navigating w/ cursor keys c) pasting text
4) scroll down, apply operator to entire canvas, scroll up
5) select-related {re,un}do bugs
6) clone selection lag
1) scrolling bug: start @ top, down key til cursor below visible canvas, scroll down, cursor gone GRRRR
2) scrolling bug: scroll down, apply operator to entire canvas, scroll up
3) text tool: a) honour RTL text flow b) pasting text
4) select-related {re,un}do bugs
5) clone selection lag
vim:ff=dos tw=0

View File

@ -34,7 +34,7 @@ class RoarCanvasCommandsTools():
self.update(toolName=self.currentTool.name)
viewRect = self.parentCanvas.GetViewStart()
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas, viewRect)
self.parentCanvas.applyTool(eventDc, True, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, viewRect)
self.parentCanvas.applyTool(eventDc, True, None, None, None, self.parentCanvas.brushPos, False, False, False, self.currentTool, viewRect)
else:
self.update(toolName="Cursor")
setattr(canvasTool_, "attrDict", f.attrList[idx])

View File

@ -6,6 +6,7 @@
from GuiWindow import GuiWindow
from ToolObject import ToolObject
from ToolText import ToolText
import json, wx, sys
import time
@ -30,7 +31,7 @@ class RoarCanvasWindowDropTarget(wx.TextDropTarget):
self.parent.commands.currentTool.setRegion(self.parent.canvas, mapPoint, dropMap, dropSize, external=True)
self.parent.commands.update(toolName=self.parent.commands.currentTool.name)
eventDc = self.parent.backend.getDeviceContext(self.parent.GetClientSize(), self.parent, viewRect)
self.parent.applyTool(eventDc, True, None, None, self.parent.brushPos, False, False, False, self.parent.commands.currentTool, viewRect)
self.parent.applyTool(eventDc, True, None, None, None, self.parent.brushPos, False, False, False, self.parent.commands.currentTool, viewRect)
rc = True; self.inProgress = True;
except:
with wx.MessageDialog(self.parent, "Error: {}".format(sys.exc_info()[1]), "", wx.OK | wx.OK_DEFAULT) as dialog:
@ -53,8 +54,8 @@ class RoarCanvasWindow(GuiWindow):
self.canvas.journal.pushCursor(patchDelta)
# }}}
# {{{ applyTool(self, eventDc, eventMouse, keyChar, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect)
def applyTool(self, eventDc, eventMouse, keyChar, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect):
# {{{ applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect)
def applyTool(self, eventDc, eventMouse, keyChar, keyCode, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, tool, viewRect):
if mapPoint != None:
mapPoint = [a + b for a, b in zip(mapPoint, viewRect)]
dirty, self.canvas.dirtyCursor, rc = False, False, False
@ -64,22 +65,23 @@ class RoarCanvasWindow(GuiWindow):
and (mapPoint[1] < self.canvas.size[1])) \
and ((self.lastCellState == None) \
or (self.lastCellState != [list(mapPoint), mouseDragging, mouseLeftDown, mouseRightDown, list(viewRect)])):
self.brushPos = list(mapPoint)
self.lastCellState = [list(mapPoint), mouseDragging, mouseLeftDown, mouseRightDown, list(viewRect)]
if tool.__class__ != ToolText:
self.brushPos = list(mapPoint)
if tool != None:
rc, dirty = tool.onMouseEvent(self.brushColours, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, keyModifiers, self.brushPos, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
rc, dirty = tool.onMouseEvent(mapPoint, self.brushColours, self.brushPos, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, keyModifiers, self.brushPos, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
else:
self.dispatchPatchSingle(eventDc, True, [*mapPoint, self.brushColours[0], self.brushColours[0], 0, " "] , viewRect)
self.lastCellState = [list(mapPoint), mouseDragging, mouseLeftDown, mouseRightDown, list(viewRect)]
else:
if tool != None:
rc, dirty = tool.onKeyboardEvent(self.brushColours, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, keyChar, keyModifiers, self.brushPos, viewRect)
rc, dirty = tool.onKeyboardEvent(mapPoint, self.brushColours, self.brushPos, self.brushSize, self.canvas, self.dispatchPatchSingle, eventDc, keyChar, keyCode, keyModifiers, self.brushPos, viewRect)
elif mapPoint != None:
self.dispatchPatchSingle(eventDc, True, [*mapPoint, self.brushColours[0], self.brushColours[0], 0, " "] , viewRect)
if dirty:
self.dirty = True
self.commands.update(dirty=self.dirty, cellPos=self.brushPos, undoLevel=self.canvas.journal.patchesUndoLevel)
else:
self.commands.update(cellPos=mapPoint if mapPoint else self.brushPos)
self.commands.update(cellPos=self.brushPos)
self.canvas.journal.end()
if rc and (tool.__class__ == ToolObject):
if tool.toolState > tool.TS_NONE:
@ -94,7 +96,7 @@ class RoarCanvasWindow(GuiWindow):
self.commands.update(toolName="Cursor", undoInhibit=False)
else:
self.commands.update(undoInhibit=False)
return rc
return rc
# }}}
# {{{ dispatchDeltaPatches(self, deltaPatches)
def dispatchDeltaPatches(self, deltaPatches):
@ -157,18 +159,30 @@ class RoarCanvasWindow(GuiWindow):
and (keyModifiers == wx.MOD_SHIFT):
import pdb; pdb.set_trace()
elif keyCode in (wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_UP):
if (keyCode == wx.WXK_DOWN) and (self.brushPos[1] < (self.canvas.size[1] - 1)):
self.brushPos = [self.brushPos[0], self.brushPos[1] + 1]
elif (keyCode == wx.WXK_LEFT) and (self.brushPos[0] > 0):
self.brushPos = [self.brushPos[0] - 1, self.brushPos[1]]
elif (keyCode == wx.WXK_RIGHT) and (self.brushPos[0] < (self.canvas.size[0] - 1)):
self.brushPos = [self.brushPos[0] + 1, self.brushPos[1]]
elif (keyCode == wx.WXK_UP) and (self.brushPos[1] > 0):
self.brushPos = [self.brushPos[0], self.brushPos[1] - 1]
if keyCode == wx.WXK_DOWN:
if self.brushPos[1] < (self.canvas.size[1] - 1):
self.brushPos = [self.brushPos[0], self.brushPos[1] + 1]
else:
self.brushPos = [self.brushPos[0], 0]
elif keyCode == wx.WXK_LEFT:
if self.brushPos[0] > 0:
self.brushPos = [self.brushPos[0] - 1, self.brushPos[1]]
else:
self.brushPos = [self.canvas.size[0] - 1, self.brushPos[1]]
elif keyCode == wx.WXK_RIGHT:
if self.brushPos[0] < (self.canvas.size[0] - 1):
self.brushPos = [self.brushPos[0] + 1, self.brushPos[1]]
else:
self.brushPos = [0, self.brushPos[1]]
elif keyCode == wx.WXK_UP:
if self.brushPos[1] > 0:
self.brushPos = [self.brushPos[0], self.brushPos[1] - 1]
else:
self.brushPos = [self.brushPos[0], self.canvas.size[1] - 1]
self.commands.update(cellPos=self.brushPos)
self.applyTool(eventDc, True, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
self.applyTool(eventDc, True, None, None, None, self.brushPos, False, False, False, self.commands.currentTool, viewRect)
else:
if not self.applyTool(eventDc, False, chr(event.GetUnicodeKey()), keyModifiers, None, None, None, None, self.commands.currentTool, viewRect):
if not self.applyTool(eventDc, False, chr(event.GetUnicodeKey()), keyCode, keyModifiers, None, None, None, None, self.commands.currentTool, viewRect):
event.Skip()
# }}}
# {{{ onEnterWindow(self, event)
@ -191,7 +205,7 @@ class RoarCanvasWindow(GuiWindow):
and (self.commands.currentTool.__class__ == ToolObject) \
and (self.commands.currentTool.toolState >= self.commands.currentTool.TS_SELECT):
self.popupEventDc = eventDc; self.PopupMenu(self.operatorsMenu); self.popupEventDc = None;
elif not self.applyTool(eventDc, True, None, event.GetModifiers(), mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, self.commands.currentTool, viewRect):
elif not self.applyTool(eventDc, True, None, None, event.GetModifiers(), mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, self.commands.currentTool, viewRect):
event.Skip()
# }}}
# {{{ onMouseWheel(self, event)

View File

@ -5,12 +5,12 @@
#
class Tool(object):
# {{{ onKeyboardEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyChar, keyModifiers, mapPoint, viewRect)
def onKeyboardEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyChar, keyModifiers, mapPoint, viewRect):
# {{{ onKeyboardEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyChar, keyCode, keyModifiers, mapPoint, viewRect)
def onKeyboardEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyChar, keyCode, keyModifiers, mapPoint, viewRect):
return False, False
# }}}
# {{{ onMouseEvent(self, brushColours, brushSize, dispatchFn, eventDc, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# {{{ onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, dispatchFn, eventDc, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
return False, False
# }}}

View File

@ -10,8 +10,8 @@ class ToolCircle(Tool):
name = "Circle"
#
# onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
brushColours, dirty = brushColours.copy(), False
if mouseLeftDown:
brushColours[1] = brushColours[0]

View File

@ -10,8 +10,8 @@ class ToolFill(Tool):
name = "Fill"
#
# onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
dirty, pointsDone, pointStack, testChar, testColour = False, [], [list(mapPoint)], canvas.map[mapPoint[1]][mapPoint[0]][3], canvas.map[mapPoint[1]][mapPoint[0]][0:2]
if mouseLeftDown or mouseRightDown:
while len(pointStack) > 0:

View File

@ -51,8 +51,8 @@ class ToolLine(Tool):
# }}}
#
# onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
brushColours, dirty = brushColours.copy(), False
if mouseLeftDown:
brushColours[1] = brushColours[0]

View File

@ -108,8 +108,8 @@ class ToolObject(Tool):
def getRegion(self, canvas):
return self.objectMap
# }}}
# {{{ onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# {{{ onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
dirty = False
if self.toolState == self.TS_NONE:
dirty = self._mouseEventTsNone(brushColours, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, viewRect)

View File

@ -10,8 +10,8 @@ class ToolRect(Tool):
name = "Rectangle"
#
# onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
brushColours, dirty = brushColours.copy(), False
if mouseLeftDown:
brushColours[1] = brushColours[0]

View File

@ -11,37 +11,45 @@ class ToolText(Tool):
name = "Text"
#
# onKeyboardEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyChar, keyModifiers, mapPoint, viewRect)
def onKeyboardEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyChar, keyModifiers, mapPoint, viewRect):
if (ord(keyChar) != wx.WXK_NONE) \
and (not keyChar in set("\t\n\v\f\r")) \
and ((ord(keyChar) >= 32) if ord(keyChar) < 127 else True) \
and (keyModifiers in (wx.MOD_NONE, wx.MOD_SHIFT)):
rc, dirty = True, True
if self.textPos == None:
self.textPos = list(mapPoint)
dispatchFn(eventDc, False, [*self.textPos, *brushColours, 0, keyChar], viewRect)
if self.textPos[0] < (canvas.size[0] - 1):
self.textPos[0] += 1
elif self.textPos[1] < (canvas.size[1] - 1):
self.textPos[0] = 0; self.textPos[1] += 1;
# onKeyboardEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyChar, keyCode, keyModifiers, mapPoint, viewRect)
def onKeyboardEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyChar, keyCode, keyModifiers, mapPoint, viewRect):
if keyCode == wx.WXK_BACK:
if brushPos[0] > 0:
brushPos[0] -= 1
elif brushPos[1] > 0:
brushPos[0], brushPos[1] = canvas.size[0] - 1, brushPos[1] - 1
else:
self.textPos = [0, 0]
brushPos[0], brushPos[1] = canvas.size[0] - 1, canvas.size[1] - 1
rc, dirty = True, False; dispatchFn(eventDc, True, [*brushPos, *brushColours, 0, "_"], viewRect);
elif keyCode == wx.WXK_RETURN:
if brushPos[1] < (canvas.size[1] - 1):
brushPos[0], brushPos[1] = 0, brushPos[1] + 1
else:
brushPos[0], brushPos[1] = 0, 0
rc, dirty = True, False; dispatchFn(eventDc, True, [*brushPos, *brushColours, 0, "_"], viewRect);
elif (ord(keyChar) != wx.WXK_NONE) \
and (not keyChar in set("\t\n\v\f\r")) \
and ((ord(keyChar) >= 32) if ord(keyChar) < 127 else True) \
and (keyModifiers in (wx.MOD_NONE, wx.MOD_SHIFT)):
dispatchFn(eventDc, False, [*brushPos, *brushColours, 0, keyChar], viewRect);
if brushPos[0] < (canvas.size[0] - 1):
brushPos[0] += 1
elif brushPos[1] < (canvas.size[1] - 1):
brushPos[0], brushPos[1] = 0, brushPos[1] + 1
else:
brushPos[0], brushPos[1] = 0, 0
dispatchFn(eventDc, True, [*brushPos, *brushColours, 0, "_"], viewRect)
rc, dirty = True, True
else:
rc, dirty = False, False
return rc, dirty
#
# onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, brushColours, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
# onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect)
def onMouseEvent(self, atPoint, brushColours, brushPos, brushSize, canvas, dispatchFn, eventDc, keyModifiers, mapPoint, mouseDragging, mouseLeftDown, mouseRightDown, viewRect):
if mouseLeftDown or mouseRightDown:
self.textPos = list(mapPoint)
dispatchFn(eventDc, True, [*mapPoint, *brushColours, 0, "_"], viewRect)
brushPos[0], brushPos[1] = atPoint[0], atPoint[1]
dispatchFn(eventDc, True, [*brushPos, *brushColours, 0, "_"], viewRect)
return True, False
# __init__(self, *args): initialisation method
def __init__(self, *args):
super().__init__(*args)
self.textColours = self.textPos = None
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120