mirror of
https://github.com/lalbornoz/roar.git
synced 2024-12-22 12:26:37 +00:00
Initial {rotate,tile} operator implementation.
This commit is contained in:
parent
62e7edc852
commit
eb3795a98e
1
.TODO
Normal file
1
.TODO
Normal file
@ -0,0 +1 @@
|
||||
text bug: a) select text tool b) paste stuff c) undo d) artifacts
|
70
.vscode/launch.json
vendored
Executable file
70
.vscode/launch.json
vendored
Executable file
@ -0,0 +1,70 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python: Current File (Integrated Terminal)",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Python: Remote Attach",
|
||||
"type": "python",
|
||||
"request": "attach",
|
||||
"port": 5678,
|
||||
"host": "localhost",
|
||||
"pathMappings": [
|
||||
{
|
||||
"localRoot": "${workspaceFolder}",
|
||||
"remoteRoot": "."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Python: Module",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "enter-your-module-name-here",
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Python: Django",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/manage.py",
|
||||
"console": "integratedTerminal",
|
||||
"args": [
|
||||
"runserver",
|
||||
"--noreload",
|
||||
"--nothreading"
|
||||
],
|
||||
"django": true
|
||||
},
|
||||
{
|
||||
"name": "Python: Flask",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"module": "flask",
|
||||
"env": {
|
||||
"FLASK_APP": "app.py"
|
||||
},
|
||||
"args": [
|
||||
"run",
|
||||
"--no-debugger",
|
||||
"--no-reload"
|
||||
],
|
||||
"jinja": true
|
||||
},
|
||||
{
|
||||
"name": "Python: Current File (External Terminal)",
|
||||
"type": "python",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "externalTerminal"
|
||||
}
|
||||
]
|
||||
}
|
12
.vscode/tasks.json
vendored
Executable file
12
.vscode/tasks.json
vendored
Executable file
@ -0,0 +1,12 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "echo",
|
||||
"type": "shell",
|
||||
"command": "echo Hello"
|
||||
}
|
||||
]
|
||||
}
|
@ -9,6 +9,7 @@ Low-priority list:
|
||||
8) Incremental auto{load,save} & {backup,restore} (needs Settings window)
|
||||
9) Composition, parametrisation & keying of tools from higher-order operators (brushes, functions, filters, outlines, patterns & shaders) and unit tools
|
||||
10) Sprites & scripted (Python?) animation on the basis of asset traits and {composable,parametrised} patterns (metric flow, particle system, rigging, ...)
|
||||
11) Integrate ENNTool code in the form of OpenGL-based animation window (see 9) and 10))
|
||||
|
||||
High-priority list:
|
||||
1) unit tools: arrow, {cloud,speech bubble}, curve, measure, pick, polygon, triangle, unicode
|
||||
|
38
liboperators/OperatorRotate.py
Executable file
38
liboperators/OperatorRotate.py
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# OperatorRotate.py
|
||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||
#
|
||||
|
||||
from Operator import Operator
|
||||
import math
|
||||
|
||||
class OperatorRotate(Operator):
|
||||
name = "Rotate"
|
||||
|
||||
#
|
||||
# apply2(self, mapPoint, mousePoint, regionOld, region)
|
||||
def apply2(self, mapPoint, mousePoint, regionOld, region):
|
||||
if self.originPoint == None:
|
||||
self.originPoint = list(mousePoint)
|
||||
delta = [b - a for a, b in zip(self.originPoint, mousePoint)]
|
||||
radius = math.sqrt(math.pow(delta[0], 2) + math.pow(delta[1], 2))
|
||||
if radius >= 10:
|
||||
regionSize = (len(region[0]), len(region))
|
||||
theta = math.atan2(-delta[1], delta[0]); cos, sin = math.cos(theta), math.sin(theta);
|
||||
for numCol in range(regionSize[0]):
|
||||
for numRow in range(regionSize[1]):
|
||||
numRow_, numCol_ = (numRow / regionSize[1]) * 2 - 1, (numCol / regionSize[0]) * 2 - 1
|
||||
b, a = (numCol_ * sin) + (numRow_ * cos), (numCol_ * cos) - (numRow_ * sin)
|
||||
numRow_, numCol_ = int((b + 1) / 2 * regionSize[1]), int((a + 1) / 2 * regionSize[0])
|
||||
if (numRow_ < regionSize[1]) and (numCol_ < regionSize[0]):
|
||||
region[numRow][numCol] = list(regionOld[numRow_][numCol_])
|
||||
return region
|
||||
else:
|
||||
return region
|
||||
|
||||
# __init__(self, *args): initialisation method
|
||||
def __init__(self, *args):
|
||||
self.originPoint = None
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
39
liboperators/OperatorTile.py
Executable file
39
liboperators/OperatorTile.py
Executable file
@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# OperatorTile.py
|
||||
# Copyright (c) 2018, 2019 Lucio Andrés Illanes Albornoz <lucio@lucioillanes.de>
|
||||
#
|
||||
|
||||
from Operator import Operator
|
||||
import copy
|
||||
|
||||
class OperatorTile(Operator):
|
||||
name = "Tile"
|
||||
|
||||
#
|
||||
# apply2(self, mapPoint, mousePoint, regionOld, region)
|
||||
def apply2(self, mapPoint, mousePoint, regionOld, region):
|
||||
if self.lastPoint == None:
|
||||
self.lastPoint = list(mapPoint)
|
||||
if self.tileObject == None:
|
||||
self.tileObject = copy.deepcopy(region)
|
||||
delta = [b - a for a, b in zip(self.lastPoint, mapPoint)]
|
||||
if delta[1] > 0:
|
||||
for numNewRow in range(delta[1]):
|
||||
newRow = copy.deepcopy(self.tileObject[len(region) % len(self.tileObject)])
|
||||
if len(newRow) < len(region[0]):
|
||||
for numNewCol in range(len(newRow), len(region[0])):
|
||||
newRow += [list(self.tileObject[len(region) % len(self.tileObject)][numNewCol % len(self.tileObject[len(region) % len(self.tileObject)])])]
|
||||
region += [newRow]
|
||||
if delta[0] > 0:
|
||||
for numRow in range(len(region)):
|
||||
for numNewCol in range(len(region[numRow]), len(region[numRow]) + delta[0]):
|
||||
region[numRow] += [list(self.tileObject[numRow % len(self.tileObject)][numNewCol % len(self.tileObject[numRow % len(self.tileObject)])])]
|
||||
self.lastPoint = list(mapPoint)
|
||||
return region
|
||||
|
||||
# __init__(self, *args): initialisation method
|
||||
def __init__(self, *args):
|
||||
self.lastPoint, self.tileObject = None, None
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=120
|
@ -64,6 +64,9 @@ class RoarCanvasCommands(RoarCanvasCommandsFile, RoarCanvasCommandsEdit, RoarCan
|
||||
self.parentFrame.SetTitle("roar")
|
||||
if "toolName" in self.lastPanelState:
|
||||
textItems.append("Current tool: {}".format(self.lastPanelState["toolName"]))
|
||||
if ("operator" in self.lastPanelState) \
|
||||
and (self.lastPanelState["operator"] != None):
|
||||
textItems.append("Current operator: {}".format(self.lastPanelState["operator"]))
|
||||
if "dirty" in self.lastPanelState \
|
||||
and self.lastPanelState["dirty"]:
|
||||
textItems.append("*")
|
||||
|
@ -7,6 +7,8 @@
|
||||
from OperatorFlipHorizontal import OperatorFlipHorizontal
|
||||
from OperatorFlipVertical import OperatorFlipVertical
|
||||
from OperatorInvert import OperatorInvert
|
||||
from OperatorRotate import OperatorRotate
|
||||
from OperatorTile import OperatorTile
|
||||
from GuiFrame import GuiCommandListDecorator
|
||||
from ToolObject import ToolObject
|
||||
import copy, wx
|
||||
@ -16,41 +18,13 @@ class RoarCanvasCommandsOperators():
|
||||
@GuiCommandListDecorator(0, "Flip", "&Flip", None, None, None)
|
||||
@GuiCommandListDecorator(1, "Flip horizontally", "Flip &horizontally", None, None, None)
|
||||
@GuiCommandListDecorator(2, "Invert", "&Invert", None, None, None)
|
||||
@GuiCommandListDecorator(3, "Rotate", "&Rotate", None, None, None)
|
||||
@GuiCommandListDecorator(4, "Tile", "&Tile", None, None, None)
|
||||
def canvasOperator(self, f, idx):
|
||||
def canvasOperator_(event):
|
||||
applyOperator = [OperatorFlipVertical, OperatorFlipHorizontal, OperatorInvert][idx]()
|
||||
if (self.currentTool.__class__ == ToolObject) \
|
||||
and (self.currentTool.toolState >= self.currentTool.TS_SELECT):
|
||||
region = self.currentTool.getRegion(self.parentCanvas.canvas)
|
||||
else:
|
||||
region = self.parentCanvas.canvas.map
|
||||
region = applyOperator.apply(copy.deepcopy(region))
|
||||
if (self.currentTool.__class__ == ToolObject) \
|
||||
and (self.currentTool.toolState >= self.currentTool.TS_SELECT):
|
||||
if self.parentCanvas.popupEventDc == None:
|
||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
||||
else:
|
||||
eventDc = self.parentCanvas.popupEventDc
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
self.currentTool.setRegion(self.parentCanvas.canvas, None, region, [len(region[0]), len(region)], self.currentTool.external)
|
||||
self.currentTool.onSelectEvent(self.parentCanvas.canvas, (0, 0), self.parentCanvas.dispatchPatchSingle, eventDc, True, wx.MOD_NONE, None, self.currentTool.targetRect)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
else:
|
||||
if self.parentCanvas.popupEventDc == None:
|
||||
eventDc = self.parentCanvas.backend.getDeviceContext(self.parentCanvas.GetClientSize(), self.parentCanvas)
|
||||
else:
|
||||
eventDc = self.parentCanvas.popupEventDc
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
self.parentCanvas.canvas.journal.begin()
|
||||
dirty = False
|
||||
for numRow in range(len(region)):
|
||||
for numCol in range(len(region[numRow])):
|
||||
if not dirty:
|
||||
self.parentCanvas.dirty = True
|
||||
self.parentCanvas.dispatchPatchSingle(eventDc, False, [numCol, numRow, *region[numRow][numCol]])
|
||||
self.parentCanvas.canvas.journal.end()
|
||||
self.parentCanvas.commands.update(dirty=self.parentCanvas.dirty, undoLevel=self.parentCanvas.canvas.journal.patchesUndoLevel)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
self.currentOperator = [OperatorFlipVertical, OperatorFlipHorizontal, OperatorInvert, OperatorRotate, OperatorTile][idx]()
|
||||
self.operatorState = None
|
||||
self.parentCanvas.applyOperator(self.currentTool, self.parentCanvas.brushPos, None, False, self.currentOperator, self.parentCanvas.GetViewStart())
|
||||
setattr(canvasOperator_, "attrDict", f.attrList[idx])
|
||||
return canvasOperator_
|
||||
# }}}
|
||||
@ -60,9 +34,10 @@ class RoarCanvasCommandsOperators():
|
||||
def __init__(self):
|
||||
self.menus = (
|
||||
("&Operators",
|
||||
self.canvasOperator(self.canvasOperator, 0), self.canvasOperator(self.canvasOperator, 1), self.canvasOperator(self.canvasOperator, 2),
|
||||
self.canvasOperator(self.canvasOperator, 0), self.canvasOperator(self.canvasOperator, 1), self.canvasOperator(self.canvasOperator, 2), self.canvasOperator(self.canvasOperator, 3), self.canvasOperator(self.canvasOperator, 4),
|
||||
),
|
||||
)
|
||||
self.toolBars = ()
|
||||
self.currentOperator, self.operatorState = None, None
|
||||
|
||||
# vim:expandtab foldmethod=marker sw=4 ts=4 tw=0
|
||||
|
@ -31,6 +31,7 @@ class RoarCanvasCommandsTools():
|
||||
self.lastTool, self.currentTool = self.currentTool, [ToolCircle, None, ToolFill, ToolLine, ToolObject, ToolRect, ToolText][idx]
|
||||
if self.currentTool != None:
|
||||
self.currentTool = self.currentTool()
|
||||
self.currentOperator, self.operatorState = None, None
|
||||
self.parentFrame.menuItemsById[self.canvasTool.attrList[idx]["id"]].Check(True)
|
||||
toolBar = self.parentFrame.toolBarItemsById[self.canvasTool.attrList[idx]["id"]].GetToolBar()
|
||||
toolBar.ToggleTool(self.canvasTool.attrList[idx]["id"], True)
|
||||
|
@ -7,7 +7,7 @@
|
||||
from GuiWindow import GuiWindow
|
||||
from ToolObject import ToolObject
|
||||
from ToolText import ToolText
|
||||
import json, wx, sys
|
||||
import copy, json, wx, sys
|
||||
|
||||
class RoarCanvasWindowDropTarget(wx.TextDropTarget):
|
||||
# {{{ done(self)
|
||||
@ -54,6 +54,47 @@ class RoarCanvasWindow(GuiWindow):
|
||||
self.canvas.journal.pushCursor(patchDelta)
|
||||
# }}}
|
||||
|
||||
# {{{ applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect)
|
||||
def applyOperator(self, currentTool, mapPoint, mouseLeftDown, mousePoint, operator, viewRect):
|
||||
self.canvas.dirtyCursor = False
|
||||
if (currentTool.__class__ == ToolObject) \
|
||||
and (currentTool.toolState >= currentTool.TS_SELECT):
|
||||
region = currentTool.getRegion(self.canvas)
|
||||
else:
|
||||
region = self.canvas.map
|
||||
if hasattr(operator, "apply2"):
|
||||
if mouseLeftDown:
|
||||
if self.commands.operatorState == None:
|
||||
self.commands.operatorState = True
|
||||
region = operator.apply2(mapPoint, mousePoint, region, copy.deepcopy(region))
|
||||
self.commands.update(operator=self.commands.currentOperator.name)
|
||||
elif self.commands.operatorState != None:
|
||||
self.commands.currentOperator = None
|
||||
self.commands.update(operator=None)
|
||||
return
|
||||
else:
|
||||
region = operator.apply(copy.deepcopy(region))
|
||||
self.commands.currentOperator = None
|
||||
if (currentTool.__class__ == ToolObject) \
|
||||
and (currentTool.toolState >= currentTool.TS_SELECT):
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self) if self.popupEventDc == None else self.popupEventDc
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
currentTool.setRegion(self.canvas, None, region, [len(region[0]), len(region)], currentTool.external)
|
||||
currentTool.onSelectEvent(self.canvas, (0, 0), self.dispatchPatchSingle, eventDc, True, wx.MOD_NONE, None, currentTool.targetRect)
|
||||
currentTool._drawSelectRect(currentTool.targetRect, self.dispatchPatchSingle, eventDc)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
else:
|
||||
eventDc = self.backend.getDeviceContext(self.GetClientSize(), self) if self.popupEventDc == None else self.popupEventDc
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
self.canvas.journal.begin()
|
||||
for numRow in range(len(region)):
|
||||
for numCol in range(len(region[numRow])):
|
||||
self.dirty = True if not self.dirty else self.dirty
|
||||
self.dispatchPatchSingle(eventDc, False, [numCol, numRow, *region[numRow][numCol]])
|
||||
self.canvas.journal.end()
|
||||
self.commands.update(dirty=self.dirty, undoLevel=self.canvas.journal.patchesUndoLevel)
|
||||
eventDc.SetDeviceOrigin(*eventDcOrigin)
|
||||
# }}}
|
||||
# {{{ 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):
|
||||
eventDcOrigin = eventDc.GetDeviceOrigin(); eventDc.SetDeviceOrigin(0, 0);
|
||||
@ -223,7 +264,9 @@ class RoarCanvasWindow(GuiWindow):
|
||||
viewRect = self.GetViewStart(); eventDc = self.backend.getDeviceContext(self.GetClientSize(), self, viewRect);
|
||||
mouseDragging, mouseLeftDown, mouseRightDown = event.Dragging(), event.LeftIsDown(), event.RightIsDown()
|
||||
mapPoint = self.backend.xlateEventPoint(event, eventDc, viewRect)
|
||||
if mouseRightDown \
|
||||
if self.commands.currentOperator != None:
|
||||
self.applyOperator(self.commands.currentTool, mapPoint, mouseLeftDown, event.GetLogicalPosition(eventDc), self.commands.currentOperator, viewRect)
|
||||
elif mouseRightDown \
|
||||
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;
|
||||
|
@ -162,7 +162,7 @@ class ToolObject(Tool):
|
||||
elif self.objectSize != objectSize:
|
||||
if self.objectSize == None:
|
||||
self.objectSize = objectSize
|
||||
self.targetRect[1] = [t + d for t, d in zip(self.targetRect[1], (a - b for a, b in zip(self.objectSize, objectSize)))]
|
||||
self.targetRect[1] = [t + d for t, d in zip(self.targetRect[1], (b - a for a, b in zip(self.objectSize, objectSize)))]
|
||||
if self.srcRect == None:
|
||||
self.srcRect = self.targetRect
|
||||
self.objectMap, self.objectSize = objectMap, objectSize
|
||||
|
Loading…
Reference in New Issue
Block a user