drawlib 0.2.3.dev2__py3-none-any.whl → 0.2.3.dev4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of drawlib might be problematic. Click here for more details.
- drawlib/__init__.py +1 -1
- drawlib/v0_2/apis.py +5 -0
- drawlib/v0_2/private/core/model.py +19 -1
- drawlib/v0_2/private/core/util.py +6 -0
- drawlib/v0_2/private/core_canvas/base.py +53 -1
- drawlib/v0_2/private/core_canvas/canvas.py +8 -1
- drawlib/v0_2/private/core_canvas/line.py +192 -1
- drawlib/v0_2/private/core_canvas/original_arrow.py +477 -1
- drawlib/v0_2/private/core_canvas/patches.py +19 -69
- drawlib/v0_2/private/smartarts/boxlist.py +178 -0
- drawlib/v0_2/private/smartarts/bubblespeech.py +16 -16
- drawlib/v0_2/private/smartarts/bulletpoints.py +188 -0
- drawlib/v0_2/private/smartarts/dsart.py +7 -0
- drawlib/v0_2/private/smartarts/gridlayout.py +47 -26
- drawlib/v0_2/private/smartarts/pyramid.py +229 -17
- drawlib/v0_2/private/smartarts/table.py +683 -0
- drawlib/v0_2/private/smartarts/tree.py +10 -5
- drawlib/v0_2/private/util.py +116 -1
- drawlib/v0_2/private/validators/args.py +26 -11
- {drawlib-0.2.3.dev2.dist-info → drawlib-0.2.3.dev4.dist-info}/METADATA +1 -1
- {drawlib-0.2.3.dev2.dist-info → drawlib-0.2.3.dev4.dist-info}/RECORD +24 -21
- {drawlib-0.2.3.dev2.dist-info → drawlib-0.2.3.dev4.dist-info}/LICENSE.txt +0 -0
- {drawlib-0.2.3.dev2.dist-info → drawlib-0.2.3.dev4.dist-info}/WHEEL +0 -0
- {drawlib-0.2.3.dev2.dist-info → drawlib-0.2.3.dev4.dist-info}/entry_points.txt +0 -0
|
@@ -11,20 +11,24 @@
|
|
|
11
11
|
"""Pyramid implementation module."""
|
|
12
12
|
|
|
13
13
|
import dataclasses
|
|
14
|
-
from typing import List, Optional, Tuple, Union
|
|
14
|
+
from typing import List, Literal, Optional, Tuple, Union
|
|
15
15
|
|
|
16
16
|
from drawlib.v0_2.private.core.model import ShapeStyle, ShapeTextStyle
|
|
17
17
|
from drawlib.v0_2.private.core.theme import dtheme
|
|
18
18
|
from drawlib.v0_2.private.core_canvas.canvas import trapezoid, triangle
|
|
19
|
+
from drawlib.v0_2.private.util import error_handler
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
class Pyramid:
|
|
22
23
|
"""Class for rendering smart art pyramid."""
|
|
23
24
|
|
|
25
|
+
@error_handler
|
|
24
26
|
def __init__(
|
|
25
27
|
self,
|
|
26
28
|
default_style: Union[str, ShapeStyle, None] = None,
|
|
27
29
|
default_textstyle: Union[str, ShapeTextStyle, None] = None,
|
|
30
|
+
default_textangle: Optional[float] = None,
|
|
31
|
+
default_text_xy_shift: Optional[Tuple[float, float]] = None,
|
|
28
32
|
) -> None:
|
|
29
33
|
"""Initialize class."""
|
|
30
34
|
if isinstance(default_style, str):
|
|
@@ -33,14 +37,19 @@ class Pyramid:
|
|
|
33
37
|
if isinstance(default_textstyle, str):
|
|
34
38
|
default_textstyle = dtheme.rectangletextstyles.get(default_textstyle)
|
|
35
39
|
self._default_textstyle = default_textstyle
|
|
40
|
+
self._default_textangle = default_textangle
|
|
41
|
+
self._default_text_xy_shift = default_text_xy_shift
|
|
36
42
|
|
|
37
43
|
self._items: List[_PyramidItem] = []
|
|
38
44
|
|
|
45
|
+
@error_handler
|
|
39
46
|
def add( # noqa: C901
|
|
40
47
|
self,
|
|
41
48
|
style: Union[str, ShapeStyle, None] = None,
|
|
42
49
|
text: str = "",
|
|
43
50
|
textstyle: Union[str, ShapeTextStyle, None] = None,
|
|
51
|
+
textangle: Optional[float] = None,
|
|
52
|
+
text_xy_shift: Optional[Tuple[float, float]] = None,
|
|
44
53
|
) -> None:
|
|
45
54
|
"""
|
|
46
55
|
Add an item to the pyramid.
|
|
@@ -54,6 +63,10 @@ class Pyramid:
|
|
|
54
63
|
textstyle (Union[str, ShapeTextStyle, None], optional):
|
|
55
64
|
The text style of the item. Can be a string key for a predefined text style,
|
|
56
65
|
a ShapeTextStyle object, or None to use the default text style.
|
|
66
|
+
textangle (Optional[float], optional):
|
|
67
|
+
The angle of the text. Default is None, which is same to 0.
|
|
68
|
+
text_xy_shift (Optional[Tuple[float, float]], optional):
|
|
69
|
+
The XY shift of the text. Default is None, which is same to (0, 0).
|
|
57
70
|
"""
|
|
58
71
|
# string style to Style class
|
|
59
72
|
if isinstance(style, str):
|
|
@@ -67,6 +80,26 @@ class Pyramid:
|
|
|
67
80
|
if textstyle is None:
|
|
68
81
|
textstyle = self._default_textstyle
|
|
69
82
|
|
|
83
|
+
# apply align to shape style
|
|
84
|
+
if style is None:
|
|
85
|
+
style = dtheme.rectanglestyles.get()
|
|
86
|
+
else:
|
|
87
|
+
style = style.copy()
|
|
88
|
+
|
|
89
|
+
# apply angle and shift to shape text style
|
|
90
|
+
if textstyle is None:
|
|
91
|
+
textstyle = dtheme.shapetextstyles.get()
|
|
92
|
+
else:
|
|
93
|
+
textstyle = textstyle.copy()
|
|
94
|
+
if textangle is None:
|
|
95
|
+
textangle = self._default_textangle
|
|
96
|
+
if textangle is not None:
|
|
97
|
+
textstyle.angle = textangle
|
|
98
|
+
if text_xy_shift is None:
|
|
99
|
+
text_xy_shift = self._default_text_xy_shift
|
|
100
|
+
if text_xy_shift is not None:
|
|
101
|
+
textstyle.xy_abs_shift = text_xy_shift
|
|
102
|
+
|
|
70
103
|
# push
|
|
71
104
|
item = _PyramidItem(
|
|
72
105
|
text=text,
|
|
@@ -75,12 +108,14 @@ class Pyramid:
|
|
|
75
108
|
)
|
|
76
109
|
self._items.append(item)
|
|
77
110
|
|
|
111
|
+
@error_handler
|
|
78
112
|
def draw(
|
|
79
113
|
self,
|
|
80
114
|
xy: Tuple[float, float],
|
|
81
115
|
width: float,
|
|
82
116
|
height: float,
|
|
83
117
|
margin: float,
|
|
118
|
+
align: Literal["bottom", "top", "left", "right"] = "bottom",
|
|
84
119
|
) -> None:
|
|
85
120
|
"""Draw smart art pyramid.
|
|
86
121
|
|
|
@@ -89,9 +124,10 @@ class Pyramid:
|
|
|
89
124
|
width (float): The width of the pyramid.
|
|
90
125
|
height (float): The heifht of the pyramid.
|
|
91
126
|
margin (float): The margin between pyramid items.
|
|
127
|
+
align (str): Alignment of a pyramid.
|
|
92
128
|
"""
|
|
93
129
|
if len(self._items) == 0:
|
|
94
|
-
raise ValueError()
|
|
130
|
+
raise ValueError("Number of pyramid item is 0.")
|
|
95
131
|
|
|
96
132
|
margins = [margin] * (len(self._items) - 1)
|
|
97
133
|
item_height = (height - sum(margins)) / len(self._items)
|
|
@@ -102,14 +138,17 @@ class Pyramid:
|
|
|
102
138
|
width=width,
|
|
103
139
|
item_heights=item_heights,
|
|
104
140
|
margins=margins,
|
|
141
|
+
align=align,
|
|
105
142
|
)
|
|
106
143
|
|
|
107
|
-
|
|
144
|
+
@error_handler
|
|
145
|
+
def draw_flexible(
|
|
108
146
|
self,
|
|
109
147
|
xy: Tuple[float, float],
|
|
110
148
|
width: float,
|
|
111
149
|
item_heights: List[float],
|
|
112
150
|
margins: List[float],
|
|
151
|
+
align: Literal["bottom", "top", "left", "right"] = "bottom",
|
|
113
152
|
) -> None:
|
|
114
153
|
"""Draw smart art pyramid with flexible pyramid item heights.
|
|
115
154
|
|
|
@@ -118,37 +157,48 @@ class Pyramid:
|
|
|
118
157
|
width (float): The width of the pyramid.
|
|
119
158
|
item_heights (float): The height of the each pyramid items.
|
|
120
159
|
margins (float): The margin between pyramid items.
|
|
160
|
+
align (str): Alignment of a pyramid.
|
|
121
161
|
|
|
122
162
|
Raises:
|
|
123
163
|
ValueError: If the lengths of column_widths, column_margins, row_heights, or row_margins are incorrect.
|
|
124
164
|
"""
|
|
125
165
|
# validate
|
|
126
166
|
if len(self._items) == 0:
|
|
127
|
-
raise ValueError()
|
|
167
|
+
raise ValueError("Number of pyramid item is 0.")
|
|
128
168
|
|
|
129
169
|
if len(self._items) != len(item_heights):
|
|
130
|
-
raise ValueError()
|
|
170
|
+
raise ValueError('Number of pyramid item and arg "items_heights" length are different.')
|
|
131
171
|
|
|
132
172
|
if len(self._items) != len(margins) + 1:
|
|
133
|
-
raise ValueError()
|
|
173
|
+
raise ValueError('Number of pyramid item and arg "margins" length does not match.')
|
|
174
|
+
|
|
175
|
+
if align == "bottom":
|
|
176
|
+
self._draw_flexible_bottom(xy, width, item_heights, margins)
|
|
177
|
+
elif align == "top":
|
|
178
|
+
self._draw_flexible_top(xy, width, item_heights, margins)
|
|
179
|
+
elif align == "left":
|
|
180
|
+
self._draw_flexible_left(xy, width, item_heights, margins)
|
|
181
|
+
elif align == "right":
|
|
182
|
+
self._draw_flexible_right(xy, width, item_heights, margins)
|
|
183
|
+
else:
|
|
184
|
+
raise ValueError("Drawlib internal error.")
|
|
134
185
|
|
|
186
|
+
def _draw_flexible_bottom(
|
|
187
|
+
self,
|
|
188
|
+
xy: Tuple[float, float],
|
|
189
|
+
width: float,
|
|
190
|
+
item_heights: List[float],
|
|
191
|
+
margins: List[float],
|
|
192
|
+
) -> None:
|
|
135
193
|
x = xy[0] + width / 2
|
|
136
194
|
height = sum(item_heights) + sum(margins)
|
|
137
195
|
current_height = 0
|
|
138
196
|
for i, item in enumerate(self._items):
|
|
139
197
|
text = item.text
|
|
140
|
-
textstyle = item.textstyle
|
|
141
|
-
if textstyle is None:
|
|
142
|
-
textstyle = self._default_textstyle
|
|
143
198
|
style = item.style
|
|
144
|
-
if style is None:
|
|
145
|
-
style = self._default_style
|
|
146
|
-
if style is None:
|
|
147
|
-
style = dtheme.rectanglestyles.get()
|
|
148
|
-
else:
|
|
149
|
-
style = style.copy()
|
|
150
199
|
style.halign = "center"
|
|
151
200
|
style.valign = "bottom"
|
|
201
|
+
textstyle = item.textstyle
|
|
152
202
|
|
|
153
203
|
is_last = i == len(self._items) - 1
|
|
154
204
|
if is_last:
|
|
@@ -181,9 +231,171 @@ class Pyramid:
|
|
|
181
231
|
)
|
|
182
232
|
current_height += item_height + margins[i]
|
|
183
233
|
|
|
234
|
+
def _draw_flexible_top(
|
|
235
|
+
self,
|
|
236
|
+
xy: Tuple[float, float],
|
|
237
|
+
width: float,
|
|
238
|
+
item_heights: List[float],
|
|
239
|
+
margins: List[float],
|
|
240
|
+
) -> None:
|
|
241
|
+
x = xy[0] + width / 2
|
|
242
|
+
height = sum(item_heights) + sum(margins)
|
|
243
|
+
current_height = 0
|
|
244
|
+
for i, item in enumerate(self._items):
|
|
245
|
+
text = item.text
|
|
246
|
+
style = item.style
|
|
247
|
+
style.halign = "center"
|
|
248
|
+
style.valign = "bottom"
|
|
249
|
+
textstyle = item.textstyle
|
|
250
|
+
|
|
251
|
+
is_last = i == len(self._items) - 1
|
|
252
|
+
if is_last:
|
|
253
|
+
ratio = (height - current_height) / height
|
|
254
|
+
item_width = ratio * width
|
|
255
|
+
item_height = item_heights[i]
|
|
256
|
+
y = xy[1] + height - current_height - item_height
|
|
257
|
+
if textstyle.angle is None:
|
|
258
|
+
textstyle.angle = 0
|
|
259
|
+
triangle(
|
|
260
|
+
(x, y),
|
|
261
|
+
width=item_width,
|
|
262
|
+
height=item_height,
|
|
263
|
+
style=style,
|
|
264
|
+
text=text,
|
|
265
|
+
textstyle=textstyle,
|
|
266
|
+
angle=180,
|
|
267
|
+
)
|
|
268
|
+
continue
|
|
269
|
+
|
|
270
|
+
bottom_ratio = (height - current_height) / height
|
|
271
|
+
bottom_width = bottom_ratio * width
|
|
272
|
+
item_height = item_heights[i]
|
|
273
|
+
top_ratio = (height - current_height - item_height) / height
|
|
274
|
+
top_width = top_ratio * width
|
|
275
|
+
y = xy[1] + height - current_height - item_height
|
|
276
|
+
trapezoid(
|
|
277
|
+
(x, y),
|
|
278
|
+
item_height,
|
|
279
|
+
bottomedge_width=top_width,
|
|
280
|
+
topedge_width=bottom_width,
|
|
281
|
+
style=style,
|
|
282
|
+
text=text,
|
|
283
|
+
textstyle=textstyle,
|
|
284
|
+
)
|
|
285
|
+
current_height += item_height + margins[i]
|
|
286
|
+
|
|
287
|
+
def _draw_flexible_left(
|
|
288
|
+
self,
|
|
289
|
+
xy: Tuple[float, float],
|
|
290
|
+
width: float,
|
|
291
|
+
item_heights: List[float],
|
|
292
|
+
margins: List[float],
|
|
293
|
+
) -> None:
|
|
294
|
+
y = xy[1] + width / 2
|
|
295
|
+
height = sum(item_heights) + sum(margins)
|
|
296
|
+
current_height = 0
|
|
297
|
+
for i, item in enumerate(self._items):
|
|
298
|
+
text = item.text
|
|
299
|
+
style = item.style
|
|
300
|
+
style.halign = "center"
|
|
301
|
+
style.valign = "center"
|
|
302
|
+
textstyle = item.textstyle
|
|
303
|
+
|
|
304
|
+
if textstyle.angle is None:
|
|
305
|
+
textstyle.angle = 0
|
|
306
|
+
|
|
307
|
+
is_last = i == len(self._items) - 1
|
|
308
|
+
if is_last:
|
|
309
|
+
ratio = (height - current_height) / height
|
|
310
|
+
item_width = ratio * width
|
|
311
|
+
item_height = item_heights[i]
|
|
312
|
+
x = xy[0] + current_height + item_height / 2
|
|
313
|
+
triangle(
|
|
314
|
+
(x, y),
|
|
315
|
+
width=item_width,
|
|
316
|
+
height=item_height,
|
|
317
|
+
style=style,
|
|
318
|
+
text=text,
|
|
319
|
+
textstyle=textstyle,
|
|
320
|
+
angle=270,
|
|
321
|
+
)
|
|
322
|
+
continue
|
|
323
|
+
|
|
324
|
+
bottom_ratio = (height - current_height) / height
|
|
325
|
+
bottom_width = bottom_ratio * width
|
|
326
|
+
item_height = item_heights[i]
|
|
327
|
+
top_ratio = (height - current_height - item_height) / height
|
|
328
|
+
top_width = top_ratio * width
|
|
329
|
+
x = xy[0] + current_height + item_height / 2
|
|
330
|
+
trapezoid(
|
|
331
|
+
(x, y),
|
|
332
|
+
item_height,
|
|
333
|
+
bottomedge_width=bottom_width,
|
|
334
|
+
topedge_width=top_width,
|
|
335
|
+
style=style,
|
|
336
|
+
text=text,
|
|
337
|
+
textstyle=textstyle,
|
|
338
|
+
angle=270,
|
|
339
|
+
)
|
|
340
|
+
current_height += item_height + margins[i]
|
|
341
|
+
|
|
342
|
+
def _draw_flexible_right(
|
|
343
|
+
self,
|
|
344
|
+
xy: Tuple[float, float],
|
|
345
|
+
width: float,
|
|
346
|
+
item_heights: List[float],
|
|
347
|
+
margins: List[float],
|
|
348
|
+
) -> None:
|
|
349
|
+
y = xy[1] + width / 2
|
|
350
|
+
height = sum(item_heights) + sum(margins)
|
|
351
|
+
current_height = 0
|
|
352
|
+
for i, item in enumerate(self._items):
|
|
353
|
+
text = item.text
|
|
354
|
+
style = item.style
|
|
355
|
+
style.halign = "center"
|
|
356
|
+
style.valign = "center"
|
|
357
|
+
textstyle = item.textstyle
|
|
358
|
+
if textstyle.angle is None:
|
|
359
|
+
textstyle.angle = 0
|
|
360
|
+
|
|
361
|
+
is_last = i == len(self._items) - 1
|
|
362
|
+
if is_last:
|
|
363
|
+
ratio = (height - current_height) / height
|
|
364
|
+
item_width = ratio * width
|
|
365
|
+
item_height = item_heights[i]
|
|
366
|
+
x = xy[0] + height - current_height - item_height / 2
|
|
367
|
+
triangle(
|
|
368
|
+
(x, y),
|
|
369
|
+
width=item_width,
|
|
370
|
+
height=item_height,
|
|
371
|
+
style=style,
|
|
372
|
+
text=text,
|
|
373
|
+
textstyle=textstyle,
|
|
374
|
+
angle=90,
|
|
375
|
+
)
|
|
376
|
+
continue
|
|
377
|
+
|
|
378
|
+
bottom_ratio = (height - current_height) / height
|
|
379
|
+
bottom_width = bottom_ratio * width
|
|
380
|
+
item_height = item_heights[i]
|
|
381
|
+
top_ratio = (height - current_height - item_height) / height
|
|
382
|
+
top_width = top_ratio * width
|
|
383
|
+
x = xy[0] + height - current_height - item_height / 2
|
|
384
|
+
trapezoid(
|
|
385
|
+
(x, y),
|
|
386
|
+
item_height,
|
|
387
|
+
bottomedge_width=bottom_width,
|
|
388
|
+
topedge_width=top_width,
|
|
389
|
+
style=style,
|
|
390
|
+
text=text,
|
|
391
|
+
textstyle=textstyle,
|
|
392
|
+
angle=90,
|
|
393
|
+
)
|
|
394
|
+
current_height += item_height + margins[i]
|
|
395
|
+
|
|
184
396
|
|
|
185
397
|
@dataclasses.dataclass
|
|
186
398
|
class _PyramidItem:
|
|
187
|
-
style:
|
|
399
|
+
style: ShapeStyle
|
|
188
400
|
text: str
|
|
189
|
-
textstyle:
|
|
401
|
+
textstyle: ShapeTextStyle
|