drawlib 0.2.3.dev2__py3-none-any.whl → 0.2.3.dev3__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.

@@ -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
- def draw_flexible( # noqa: C901
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: Optional[ShapeStyle]
399
+ style: ShapeStyle
188
400
  text: str
189
- textstyle: Optional[ShapeTextStyle]
401
+ textstyle: ShapeTextStyle