228 lines
7.5 KiB
Python
228 lines
7.5 KiB
Python
from .pyside import QtCore
|
|
from .shapepath import get_absolute_path, get_relative_path
|
|
|
|
class Transform:
|
|
def __init__(self, snap=None):
|
|
self.snap = snap
|
|
self.direction = None
|
|
self.rect = None
|
|
self.mode = None
|
|
self.square = False
|
|
self.reference_x = None
|
|
self.reference_y = None
|
|
self.reference_rect = None
|
|
|
|
def set_rect(self, rect):
|
|
self.rect = rect
|
|
if rect is None:
|
|
self.reference_x = None
|
|
self.reference_y = None
|
|
return
|
|
|
|
def set_reference_point(self, cursor):
|
|
self.reference_x = cursor.x() - self.rect.left()
|
|
self.reference_y = cursor.y() - self.rect.top()
|
|
|
|
def resize(self, shapes, cursor):
|
|
if self.snap is not None:
|
|
x, y = snap(cursor.x(), cursor.y(), self.snap)
|
|
cursor.setX(x)
|
|
cursor.setY(y)
|
|
resize_rect_with_direction(
|
|
self.rect, cursor, self.direction, force_square=self.square)
|
|
self.apply_relative_transformation(shapes)
|
|
|
|
def apply_relative_transformation(self, shapes):
|
|
for shape in shapes:
|
|
resize_shape_with_reference(shape, self.reference_rect, self.rect)
|
|
|
|
self.reference_rect = QtCore.QRectF(
|
|
self.rect.topLeft(), self.rect.size())
|
|
|
|
def move(self, shapes, cursor):
|
|
x = cursor.x() - self.reference_x
|
|
y = cursor.y() - self.reference_y
|
|
if self.snap is not None:
|
|
x, y = snap(x, y, self.snap)
|
|
self.apply_topleft(shapes, x, y)
|
|
|
|
def shift(self, shapes, offset):
|
|
x, y = offset
|
|
if self.snap is not None:
|
|
x *= self.snap[0]
|
|
y *= self.snap[1]
|
|
x = self.rect.left() + x
|
|
y = self.rect.top() + y
|
|
if self.snap:
|
|
x, y = snap(x, y, self.snap)
|
|
self.apply_topleft(shapes, x, y)
|
|
|
|
def apply_topleft(self, shapes, x, y):
|
|
width = self.rect.width()
|
|
height = self.rect.height()
|
|
self.rect.setTopLeft(QtCore.QPoint(x, y))
|
|
self.rect.setWidth(width)
|
|
self.rect.setHeight(height)
|
|
self.apply_relative_transformation(shapes)
|
|
|
|
|
|
def snap(x, y, snap):
|
|
x = snap[0] * round(x / snap[0])
|
|
y = snap[1] * round(y / snap[1])
|
|
return round(x), round(y)
|
|
|
|
|
|
def relative(value, in_min, in_max, out_min, out_max):
|
|
"""
|
|
this function resolve simple equation and return the unknown value
|
|
in between two values.
|
|
a, a" = in_min, out_min
|
|
b, b " = out_max, out_max
|
|
c = value
|
|
? is the unknown processed by function.
|
|
a --------- c --------- b
|
|
a" --------------- ? ---------------- b"
|
|
"""
|
|
factor = float((value - in_min)) / (in_max - in_min)
|
|
width = out_max - out_min
|
|
return out_min + (width * (factor))
|
|
|
|
|
|
def resize_shape_with_reference(shape, reference_rect, rect):
|
|
if not shape.options['shape.path']:
|
|
resize_rect_with_reference(shape.rect, reference_rect, rect)
|
|
return
|
|
point = shape.options['shape.left'], shape.options['shape.top']
|
|
absolute_path = get_absolute_path(point, shape.options['shape.path'])
|
|
|
|
resize_rect_with_reference(shape.rect, reference_rect, rect)
|
|
shape.synchronize_rect()
|
|
|
|
resize_path_with_reference(absolute_path, reference_rect, rect)
|
|
point = shape.options['shape.left'], shape.options['shape.top']
|
|
relative_path = get_relative_path(point, absolute_path)
|
|
shape.options['shape.path'] = relative_path
|
|
shape.update_path()
|
|
|
|
|
|
def resize_path_with_reference(path, in_reference_rect, out_reference_rect):
|
|
for point in path:
|
|
for key in ['point', 'tangent_in', 'tangent_out']:
|
|
if point[key] is not None:
|
|
x = relative(
|
|
point[key][0],
|
|
in_min=in_reference_rect.left(),
|
|
in_max=in_reference_rect.right(),
|
|
out_min=out_reference_rect.left(),
|
|
out_max=out_reference_rect.right())
|
|
y = relative(
|
|
point[key][1],
|
|
in_min=in_reference_rect.top(),
|
|
in_max=in_reference_rect.bottom(),
|
|
out_min=out_reference_rect.top(),
|
|
out_max=out_reference_rect.bottom())
|
|
point[key] = [x, y]
|
|
|
|
|
|
def resize_rect_with_reference(rect, in_reference_rect, out_reference_rect):
|
|
"""
|
|
__________________________________ B
|
|
| ________________ A |
|
|
| | | |
|
|
| |_______________| |
|
|
| |
|
|
|________________________________|
|
|
__________________________ C
|
|
| ? |
|
|
| |
|
|
|________________________|
|
|
A = rect given
|
|
B = in_reference_rect
|
|
C = out_reference_rect
|
|
the function process the fourth rect,
|
|
it scale the A rect using the B, C scales as reference
|
|
"""
|
|
|
|
left = relative(
|
|
value=rect.left(),
|
|
in_min=in_reference_rect.left(),
|
|
in_max=in_reference_rect.right(),
|
|
out_min=out_reference_rect.left(),
|
|
out_max=out_reference_rect.right())
|
|
top = relative(
|
|
value=rect.top(),
|
|
in_min=in_reference_rect.top(),
|
|
in_max=in_reference_rect.bottom(),
|
|
out_min=out_reference_rect.top(),
|
|
out_max=out_reference_rect.bottom())
|
|
right = relative(
|
|
value=rect.right(),
|
|
in_min=in_reference_rect.left(),
|
|
in_max=in_reference_rect.right(),
|
|
out_min=out_reference_rect.left(),
|
|
out_max=out_reference_rect.right())
|
|
bottom = relative(
|
|
value=rect.bottom(),
|
|
in_min=in_reference_rect.top(),
|
|
in_max=in_reference_rect.bottom(),
|
|
out_min=out_reference_rect.top(),
|
|
out_max=out_reference_rect.bottom())
|
|
rect.setCoords(left, top, right, bottom)
|
|
|
|
|
|
def resize_rect_with_direction(rect, cursor, direction, force_square=False):
|
|
point = QtCore.QPointF(cursor)
|
|
|
|
if direction == 'top_left':
|
|
point.setX(min((point.x(), rect.right() - 1)))
|
|
point.setY(min((point.y(), rect.bottom() - 1)))
|
|
rect.setTopLeft(point)
|
|
if force_square:
|
|
left = rect.right() - rect.height()
|
|
rect.setLeft(left)
|
|
|
|
elif direction == 'bottom_left':
|
|
point.setX(min((point.x(), rect.right() - 1)))
|
|
point.setY(max((point.y(), rect.top() + 1)))
|
|
rect.setBottomLeft(point)
|
|
if force_square:
|
|
rect.setHeight(rect.width())
|
|
|
|
elif direction == 'top_right':
|
|
point.setX(max((point.x(), rect.left() + 1)))
|
|
point.setY(min((point.y(), rect.bottom() + 1)))
|
|
rect.setTopRight(point)
|
|
if force_square:
|
|
rect.setWidth(rect.height())
|
|
|
|
elif direction == 'bottom_right':
|
|
point.setX(max((point.x(), rect.left() + 1)))
|
|
point.setY(max((point.y(), rect.top() + 1)))
|
|
rect.setBottomRight(point)
|
|
if force_square:
|
|
rect.setHeight(rect.width())
|
|
|
|
elif direction == 'left':
|
|
point.setX(min((point.x(), rect.right() - 1)))
|
|
rect.setLeft(point.x())
|
|
if force_square:
|
|
rect.setHeight(rect.width())
|
|
|
|
elif direction == 'right':
|
|
point.setX(max((point.x(), rect.left() + 1)))
|
|
rect.setRight(point.x())
|
|
if force_square:
|
|
rect.setHeight(rect.width())
|
|
|
|
elif direction == 'top':
|
|
point.setY(min((point.y(), rect.bottom() - 1)))
|
|
rect.setTop(point.y())
|
|
if force_square:
|
|
rect.setWidth(rect.height())
|
|
|
|
elif direction == 'bottom':
|
|
point.setY(max((point.y(), rect.top() + 1)))
|
|
rect.setBottom(point.y())
|
|
if force_square:
|
|
rect.setWidth(rect.height())
|