PCQRSCANER/venv/Lib/site-packages/pptx/shapes/connector.py

291 lines
9.6 KiB
Python
Raw Normal View History

2019-12-22 21:51:47 +01:00
# encoding: utf-8
"""Connector (line) shape and related objects.
A connector is a line shape having end-points that can be connected to other
objects (but not to other connectors). A connector can be straight, have
elbows, or can be curved.
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from pptx.dml.line import LineFormat
from pptx.shapes.base import BaseShape
from pptx.util import Emu, lazyproperty
class Connector(BaseShape):
"""Connector (line) shape.
A connector is a linear shape having end-points that can be connected to
other objects (but not to other connectors). A connector can be straight,
have elbows, or can be curved.
"""
def begin_connect(self, shape, cxn_pt_idx):
"""
**EXPERIMENTAL** - *The current implementation only works properly
with rectangular shapes, such as pictures and rectangles. Use with
other shape types may cause unexpected visual alignment of the
connected end-point and could lead to a load error if cxn_pt_idx
exceeds the connection point count available on the connected shape.
That said, a quick test should reveal what to expect when using this
method with other shape types.*
Connect the beginning of this connector to *shape* at the connection
point specified by *cxn_pt_idx*. Each shape has zero or more
connection points and they are identified by index, starting with 0.
Generally, the first connection point of a shape is at the top center
of its bounding box and numbering proceeds counter-clockwise from
there. However this is only a convention and may vary, especially
with non built-in shapes.
"""
self._connect_begin_to(shape, cxn_pt_idx)
self._move_begin_to_cxn(shape, cxn_pt_idx)
@property
def begin_x(self):
"""
Return the X-position of the begin point of this connector, in
English Metric Units (as a |Length| object).
"""
cxnSp = self._element
x, cx, flipH = cxnSp.x, cxnSp.cx, cxnSp.flipH
begin_x = x + cx if flipH else x
return Emu(begin_x)
@begin_x.setter
def begin_x(self, value):
cxnSp = self._element
x, cx, flipH, new_x = cxnSp.x, cxnSp.cx, cxnSp.flipH, int(value)
if flipH:
old_x = x + cx
dx = abs(new_x - old_x)
if new_x >= old_x:
cxnSp.cx = cx + dx
elif dx <= cx:
cxnSp.cx = cx - dx
else:
cxnSp.flipH = False
cxnSp.x = new_x
cxnSp.cx = dx - cx
else:
dx = abs(new_x - x)
if new_x <= x:
cxnSp.x = new_x
cxnSp.cx = cx + dx
elif dx <= cx:
cxnSp.x = new_x
cxnSp.cx = cx - dx
else:
cxnSp.flipH = True
cxnSp.x = x + cx
cxnSp.cx = dx - cx
@property
def begin_y(self):
"""
Return the Y-position of the begin point of this connector, in
English Metric Units (as a |Length| object).
"""
cxnSp = self._element
y, cy, flipV = cxnSp.y, cxnSp.cy, cxnSp.flipV
begin_y = y + cy if flipV else y
return Emu(begin_y)
@begin_y.setter
def begin_y(self, value):
cxnSp = self._element
y, cy, flipV, new_y = cxnSp.y, cxnSp.cy, cxnSp.flipV, int(value)
if flipV:
old_y = y + cy
dy = abs(new_y - old_y)
if new_y >= old_y:
cxnSp.cy = cy + dy
elif dy <= cy:
cxnSp.cy = cy - dy
else:
cxnSp.flipV = False
cxnSp.y = new_y
cxnSp.cy = dy - cy
else:
dy = abs(new_y - y)
if new_y <= y:
cxnSp.y = new_y
cxnSp.cy = cy + dy
elif dy <= cy:
cxnSp.y = new_y
cxnSp.cy = cy - dy
else:
cxnSp.flipV = True
cxnSp.y = y + cy
cxnSp.cy = dy - cy
def end_connect(self, shape, cxn_pt_idx):
"""
**EXPERIMENTAL** - *The current implementation only works properly
with rectangular shapes, such as pictures and rectangles. Use with
other shape types may cause unexpected visual alignment of the
connected end-point and could lead to a load error if cxn_pt_idx
exceeds the connection point count available on the connected shape.
That said, a quick test should reveal what to expect when using this
method with other shape types.*
Connect the ending of this connector to *shape* at the connection
point specified by *cxn_pt_idx*.
"""
self._connect_end_to(shape, cxn_pt_idx)
self._move_end_to_cxn(shape, cxn_pt_idx)
@property
def end_x(self):
"""
Return the X-position of the end point of this connector, in English
Metric Units (as a |Length| object).
"""
cxnSp = self._element
x, cx, flipH = cxnSp.x, cxnSp.cx, cxnSp.flipH
end_x = x if flipH else x + cx
return Emu(end_x)
@end_x.setter
def end_x(self, value):
cxnSp = self._element
x, cx, flipH, new_x = cxnSp.x, cxnSp.cx, cxnSp.flipH, int(value)
if flipH:
dx = abs(new_x - x)
if new_x <= x:
cxnSp.x = new_x
cxnSp.cx = cx + dx
elif dx <= cx:
cxnSp.x = new_x
cxnSp.cx = cx - dx
else:
cxnSp.flipH = False
cxnSp.x = x + cx
cxnSp.cx = dx - cx
else:
old_x = x + cx
dx = abs(new_x - old_x)
if new_x >= old_x:
cxnSp.cx = cx + dx
elif dx <= cx:
cxnSp.cx = cx - dx
else:
cxnSp.flipH = True
cxnSp.x = new_x
cxnSp.cx = dx - cx
@property
def end_y(self):
"""
Return the Y-position of the end point of this connector, in English
Metric Units (as a |Length| object).
"""
cxnSp = self._element
y, cy, flipV = cxnSp.y, cxnSp.cy, cxnSp.flipV
end_y = y if flipV else y + cy
return Emu(end_y)
@end_y.setter
def end_y(self, value):
cxnSp = self._element
y, cy, flipV, new_y = cxnSp.y, cxnSp.cy, cxnSp.flipV, int(value)
if flipV:
dy = abs(new_y - y)
if new_y <= y:
cxnSp.y = new_y
cxnSp.cy = cy + dy
elif dy <= cy:
cxnSp.y = new_y
cxnSp.cy = cy - dy
else:
cxnSp.flipV = False
cxnSp.y = y + cy
cxnSp.cy = dy - cy
else:
old_y = y + cy
dy = abs(new_y - old_y)
if new_y >= old_y:
cxnSp.cy = cy + dy
elif dy <= cy:
cxnSp.cy = cy - dy
else:
cxnSp.flipV = True
cxnSp.y = new_y
cxnSp.cy = dy - cy
def get_or_add_ln(self):
"""Helper method required by |LineFormat|."""
return self._element.spPr.get_or_add_ln()
@lazyproperty
def line(self):
"""|LineFormat| instance for this connector.
Provides access to line properties such as line color, width, and
line style.
"""
return LineFormat(self)
@property
def ln(self):
"""Helper method required by |LineFormat|.
The ``<a:ln>`` element containing the line format properties such as
line color and width. |None| if no `<a:ln>` element is present.
"""
return self._element.spPr.ln
def _connect_begin_to(self, shape, cxn_pt_idx):
"""
Add or update a stCxn element for this connector that connects its
begin point to the connection point of *shape* specified by
*cxn_pt_idx*.
"""
cNvCxnSpPr = self._element.nvCxnSpPr.cNvCxnSpPr
stCxn = cNvCxnSpPr.get_or_add_stCxn()
stCxn.id = shape.shape_id
stCxn.idx = cxn_pt_idx
def _connect_end_to(self, shape, cxn_pt_idx):
"""
Add or update an endCxn element for this connector that connects its
end point to the connection point of *shape* specified by
*cxn_pt_idx*.
"""
cNvCxnSpPr = self._element.nvCxnSpPr.cNvCxnSpPr
endCxn = cNvCxnSpPr.get_or_add_endCxn()
endCxn.id = shape.shape_id
endCxn.idx = cxn_pt_idx
def _move_begin_to_cxn(self, shape, cxn_pt_idx):
"""
Move the begin point of this connector to coordinates of the
connection point of *shape* specified by *cxn_pt_idx*.
"""
x, y, cx, cy = shape.left, shape.top, shape.width, shape.height
self.begin_x, self.begin_y = {
0: (int(x + cx / 2), y),
1: (x, int(y + cy / 2)),
2: (int(x + cx / 2), y + cy),
3: (x + cx, int(y + cy / 2)),
}[cxn_pt_idx]
def _move_end_to_cxn(self, shape, cxn_pt_idx):
"""
Move the end point of this connector to the coordinates of the
connection point of *shape* specified by *cxn_pt_idx*.
"""
x, y, cx, cy = shape.left, shape.top, shape.width, shape.height
self.end_x, self.end_y = {
0: (int(x + cx / 2), y),
1: (x, int(y + cy / 2)),
2: (int(x + cx / 2), y + cy),
3: (x + cx, int(y + cy / 2)),
}[cxn_pt_idx]