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
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
# Copyright (c) 2024 Yuichi Ito (yuichi@yuichi.com)
|
|
2
|
+
#
|
|
3
|
+
# This software is licensed under the Apache License, Version 2.0.
|
|
4
|
+
# For more information, please visit: https://github.com/yuichi110/drawlib
|
|
5
|
+
#
|
|
6
|
+
# This software is provided "as is", without warranty of any kind,
|
|
7
|
+
# express or implied, including but not limited to the warranties of
|
|
8
|
+
# merchantability, fitness for a particular purpose and noninfringement.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
"""Table implementation module."""
|
|
12
|
+
|
|
13
|
+
import dataclasses
|
|
14
|
+
from typing import Any, List, Literal, Optional, Tuple, Union
|
|
15
|
+
|
|
16
|
+
from drawlib.v0_2.private.core.colors import Colors, ColorsThemeEssentials
|
|
17
|
+
from drawlib.v0_2.private.core.fonts import Font
|
|
18
|
+
from drawlib.v0_2.private.core.model import LineStyle, ShapeStyle, ShapeTextStyle
|
|
19
|
+
from drawlib.v0_2.private.core.theme import dtheme
|
|
20
|
+
from drawlib.v0_2.private.core_canvas.canvas import line, rectangle
|
|
21
|
+
from drawlib.v0_2.private.util import error_handler
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclasses.dataclass
|
|
25
|
+
class _CellStyleOrder:
|
|
26
|
+
order: Literal["range", "even_odd"]
|
|
27
|
+
textstyle1: ShapeTextStyle
|
|
28
|
+
background_color1: Union[Tuple[int, int, int], Tuple[int, int, int, float]]
|
|
29
|
+
textstyle2: Optional[ShapeTextStyle] = None
|
|
30
|
+
background_color2: Union[Tuple[int, int, int], Tuple[int, int, int, float], None] = None
|
|
31
|
+
rows: Optional[List[int]] = None
|
|
32
|
+
columns: Optional[List[int]] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclasses.dataclass
|
|
36
|
+
class _CellInfo:
|
|
37
|
+
xy: Tuple[float, float]
|
|
38
|
+
width: float
|
|
39
|
+
height: float
|
|
40
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]]
|
|
41
|
+
textstyle: ShapeTextStyle
|
|
42
|
+
text: str
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Table:
|
|
46
|
+
"""A class used to create and manage the style and drawing of a table."""
|
|
47
|
+
|
|
48
|
+
@error_handler
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
"""Initialize instance"""
|
|
51
|
+
self._bs_top: Optional[LineStyle] = None
|
|
52
|
+
self._bs_top2: Optional[LineStyle] = None
|
|
53
|
+
self._bs_bottom: Optional[LineStyle] = None
|
|
54
|
+
self._bs_left: Optional[LineStyle] = None
|
|
55
|
+
self._bs_left2: Optional[LineStyle] = None
|
|
56
|
+
self._bs_right: Optional[LineStyle] = None
|
|
57
|
+
self._bs_between_columns: Optional[LineStyle] = None
|
|
58
|
+
self._bs_between_rows: Optional[LineStyle] = None
|
|
59
|
+
self._cell_style_orders: List[_CellStyleOrder] = []
|
|
60
|
+
|
|
61
|
+
self.set_predefined_style("default")
|
|
62
|
+
|
|
63
|
+
@error_handler
|
|
64
|
+
def clear_styles(self) -> None:
|
|
65
|
+
"""Clears all cell and border styles, resetting the table to have no styles."""
|
|
66
|
+
self._bs_top = None
|
|
67
|
+
self._bs_top2 = None
|
|
68
|
+
self._bs_bottom = None
|
|
69
|
+
self._bs_left = None
|
|
70
|
+
self._bs_left2 = None
|
|
71
|
+
self._bs_right = None
|
|
72
|
+
self._bs_between_columns = None
|
|
73
|
+
self._bs_between_rows = None
|
|
74
|
+
self._cell_style_orders = []
|
|
75
|
+
|
|
76
|
+
@error_handler
|
|
77
|
+
def set_predefined_style(
|
|
78
|
+
self,
|
|
79
|
+
name: Literal[
|
|
80
|
+
"default",
|
|
81
|
+
"none",
|
|
82
|
+
"monochrome",
|
|
83
|
+
"border_simple",
|
|
84
|
+
],
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Sets a predefined style for the table based on the given name.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
name (Literal["default", "monochrome", "white"]): The name of the predefined style.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
ValueError: If the provided style name is not recognized.
|
|
93
|
+
"""
|
|
94
|
+
self.clear_styles()
|
|
95
|
+
|
|
96
|
+
if name == "default":
|
|
97
|
+
"""
|
|
98
|
+
header: background light blue, bold white font
|
|
99
|
+
even_odd: even snow color, odd white color
|
|
100
|
+
border: bottom only
|
|
101
|
+
"""
|
|
102
|
+
self.set_style_cell_evenodd(
|
|
103
|
+
even_color=ColorsThemeEssentials.Snow,
|
|
104
|
+
even_textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
105
|
+
odd_color=ColorsThemeEssentials.White,
|
|
106
|
+
odd_textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
107
|
+
)
|
|
108
|
+
self.set_style_cell_header(
|
|
109
|
+
background_color=ColorsThemeEssentials.LightBlue,
|
|
110
|
+
textstyle=ShapeTextStyle(color=ColorsThemeEssentials.White, font=Font.SANSSERIF_BOLD),
|
|
111
|
+
)
|
|
112
|
+
self.set_style_border(
|
|
113
|
+
bottom=LineStyle(color=ColorsThemeEssentials.Charcoal, width=1),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
elif name == "none":
|
|
117
|
+
"""
|
|
118
|
+
header: background transparent
|
|
119
|
+
even_odd: both background transparent
|
|
120
|
+
border: no border
|
|
121
|
+
"""
|
|
122
|
+
self.set_style_cell(
|
|
123
|
+
background_color=Colors.Transparent,
|
|
124
|
+
textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
elif name == "monochrome":
|
|
128
|
+
"""
|
|
129
|
+
header: background gray, bold font
|
|
130
|
+
even_odd: even snow color, odd white color
|
|
131
|
+
border: bottom only
|
|
132
|
+
"""
|
|
133
|
+
self.set_style_cell_evenodd(
|
|
134
|
+
even_color=ColorsThemeEssentials.Snow,
|
|
135
|
+
even_textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
136
|
+
odd_color=ColorsThemeEssentials.White,
|
|
137
|
+
odd_textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
138
|
+
)
|
|
139
|
+
self.set_style_cell_header(
|
|
140
|
+
background_color=ColorsThemeEssentials.Graphite,
|
|
141
|
+
textstyle=ShapeTextStyle(color=ColorsThemeEssentials.White, font=Font.SANSSERIF_BOLD),
|
|
142
|
+
)
|
|
143
|
+
self.set_style_border(
|
|
144
|
+
bottom=LineStyle(color=ColorsThemeEssentials.Charcoal, width=1),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
elif name == "border_simple":
|
|
148
|
+
"""
|
|
149
|
+
header: background white, bold font
|
|
150
|
+
even_odd: both background white
|
|
151
|
+
border: header1, header2(light), bottom
|
|
152
|
+
"""
|
|
153
|
+
self.set_style_cell(
|
|
154
|
+
background_color=ColorsThemeEssentials.White,
|
|
155
|
+
textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal),
|
|
156
|
+
)
|
|
157
|
+
self.set_style_cell_header(
|
|
158
|
+
background_color=ColorsThemeEssentials.White,
|
|
159
|
+
textstyle=ShapeTextStyle(color=ColorsThemeEssentials.Charcoal, font=Font.SANSSERIF_BOLD),
|
|
160
|
+
)
|
|
161
|
+
self.set_style_border(
|
|
162
|
+
top=LineStyle(color=ColorsThemeEssentials.Charcoal, width=1.5),
|
|
163
|
+
top2=LineStyle(color=ColorsThemeEssentials.Charcoal, width=0.75),
|
|
164
|
+
bottom=LineStyle(color=ColorsThemeEssentials.Charcoal, width=1.5),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
else:
|
|
168
|
+
raise ValueError(f'Provided pre defined name "{name}" is not supported.')
|
|
169
|
+
|
|
170
|
+
# cell styles
|
|
171
|
+
|
|
172
|
+
@error_handler
|
|
173
|
+
def set_style_cell_headers(
|
|
174
|
+
self,
|
|
175
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
176
|
+
textstyle: Union[str, ShapeTextStyle],
|
|
177
|
+
) -> None:
|
|
178
|
+
"""Sets the style for both column and row headers.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
background_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
182
|
+
The background color of the headers.
|
|
183
|
+
textstyle (Union[str, ShapeTextStyle]):
|
|
184
|
+
The text style of the headers. Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
185
|
+
"""
|
|
186
|
+
if isinstance(textstyle, str):
|
|
187
|
+
textstyle = dtheme.shapetextstyles.get(textstyle)
|
|
188
|
+
|
|
189
|
+
self.set_style_cell_rowheader(background_color=background_color, textstyle=textstyle)
|
|
190
|
+
self.set_style_cell_header(background_color=background_color, textstyle=textstyle)
|
|
191
|
+
|
|
192
|
+
@error_handler
|
|
193
|
+
def set_style_cell_header(
|
|
194
|
+
self,
|
|
195
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
196
|
+
textstyle: Union[str, ShapeTextStyle],
|
|
197
|
+
) -> None:
|
|
198
|
+
"""
|
|
199
|
+
Sets the style for the column header.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
background_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
203
|
+
The background color of the column header.
|
|
204
|
+
textstyle (Union[str, ShapeTextStyle]):
|
|
205
|
+
The text style of the column header.
|
|
206
|
+
Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
207
|
+
"""
|
|
208
|
+
if isinstance(textstyle, str):
|
|
209
|
+
textstyle = dtheme.shapetextstyles.get(textstyle)
|
|
210
|
+
|
|
211
|
+
self.set_style_cell(
|
|
212
|
+
background_color=background_color,
|
|
213
|
+
textstyle=textstyle,
|
|
214
|
+
rows=[0],
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
@error_handler
|
|
218
|
+
def set_style_cell_rowheader(
|
|
219
|
+
self,
|
|
220
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
221
|
+
textstyle: Union[str, ShapeTextStyle],
|
|
222
|
+
) -> None:
|
|
223
|
+
"""
|
|
224
|
+
Sets the style for the row header.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
background_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
228
|
+
The background color of the row header.
|
|
229
|
+
textstyle (Union[str, ShapeTextStyle]):
|
|
230
|
+
The text style of the row header.
|
|
231
|
+
Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
232
|
+
"""
|
|
233
|
+
if isinstance(textstyle, str):
|
|
234
|
+
textstyle = dtheme.shapetextstyles.get(textstyle)
|
|
235
|
+
|
|
236
|
+
self.set_style_cell(
|
|
237
|
+
background_color=background_color,
|
|
238
|
+
textstyle=textstyle,
|
|
239
|
+
columns=[0],
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
@error_handler
|
|
243
|
+
def set_style_cell_evenodd(
|
|
244
|
+
self,
|
|
245
|
+
even_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
246
|
+
even_textstyle: Union[str, ShapeTextStyle],
|
|
247
|
+
odd_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
248
|
+
odd_textstyle: Union[str, ShapeTextStyle],
|
|
249
|
+
) -> None:
|
|
250
|
+
"""
|
|
251
|
+
Sets alternating styles for even and odd rows.
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
even_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
255
|
+
The background color for even rows.
|
|
256
|
+
even_textstyle (Union[str, ShapeTextStyle]):
|
|
257
|
+
The text style for even rows.
|
|
258
|
+
Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
259
|
+
odd_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
260
|
+
The background color for odd rows.
|
|
261
|
+
odd_textstyle (Union[str, ShapeTextStyle]):
|
|
262
|
+
The text style for odd rows.
|
|
263
|
+
Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
264
|
+
"""
|
|
265
|
+
if isinstance(even_textstyle, str):
|
|
266
|
+
even_textstyle = dtheme.shapetextstyles.get(even_textstyle)
|
|
267
|
+
if isinstance(odd_textstyle, str):
|
|
268
|
+
odd_textstyle = dtheme.shapetextstyles.get(odd_textstyle)
|
|
269
|
+
|
|
270
|
+
self._cell_style_orders.append(
|
|
271
|
+
_CellStyleOrder(
|
|
272
|
+
"even_odd",
|
|
273
|
+
background_color1=even_color,
|
|
274
|
+
background_color2=odd_color,
|
|
275
|
+
textstyle1=even_textstyle,
|
|
276
|
+
textstyle2=odd_textstyle,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
@error_handler
|
|
281
|
+
def set_style_cell(
|
|
282
|
+
self,
|
|
283
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
284
|
+
textstyle: Union[str, ShapeTextStyle],
|
|
285
|
+
rows: Optional[List[int]] = None,
|
|
286
|
+
columns: Optional[List[int]] = None,
|
|
287
|
+
) -> None:
|
|
288
|
+
"""
|
|
289
|
+
Sets the style for specific cells.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
background_color (Union[Tuple[int, int, int], Tuple[int, int, int, float]]):
|
|
293
|
+
The background color of the cells.
|
|
294
|
+
textstyle (Union[str, ShapeTextStyle]):
|
|
295
|
+
The text style of the cells.
|
|
296
|
+
Can be a string key for predefined styles or a ShapeTextStyle object.
|
|
297
|
+
rows (Optional[List[int]]):
|
|
298
|
+
A list of row indices to apply the style to. If None, applies to all rows.
|
|
299
|
+
columns (Optional[List[int]]):
|
|
300
|
+
A list of column indices to apply the style to. If None, applies to all columns.
|
|
301
|
+
"""
|
|
302
|
+
if isinstance(textstyle, str):
|
|
303
|
+
textstyle = dtheme.shapetextstyles.get(textstyle)
|
|
304
|
+
|
|
305
|
+
self._cell_style_orders.append(
|
|
306
|
+
_CellStyleOrder(
|
|
307
|
+
"range",
|
|
308
|
+
background_color1=background_color,
|
|
309
|
+
textstyle1=textstyle,
|
|
310
|
+
rows=rows,
|
|
311
|
+
columns=columns,
|
|
312
|
+
)
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
# border style
|
|
316
|
+
|
|
317
|
+
@error_handler
|
|
318
|
+
def set_style_border( # noqa: C901
|
|
319
|
+
self,
|
|
320
|
+
top: Union[str, LineStyle, None] = None,
|
|
321
|
+
top2: Union[str, LineStyle, None] = None,
|
|
322
|
+
bottom: Union[str, LineStyle, None] = None,
|
|
323
|
+
left: Union[str, LineStyle, None] = None,
|
|
324
|
+
left2: Union[str, LineStyle, None] = None,
|
|
325
|
+
right: Union[str, LineStyle, None] = None,
|
|
326
|
+
between_columns: Union[str, LineStyle, None] = None,
|
|
327
|
+
between_rows: Union[str, LineStyle, None] = None,
|
|
328
|
+
) -> None:
|
|
329
|
+
"""Sets the style for table borders.
|
|
330
|
+
|
|
331
|
+
Args:
|
|
332
|
+
top (Union[str, LineStyle, None]):
|
|
333
|
+
Style for the top border.
|
|
334
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
335
|
+
top2 (Union[str, LineStyle, None]):
|
|
336
|
+
Style for the secondary top border.
|
|
337
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
338
|
+
bottom (Union[str, LineStyle, None]):
|
|
339
|
+
Style for the bottom border.
|
|
340
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
341
|
+
left (Union[str, LineStyle, None]):
|
|
342
|
+
Style for the left border.
|
|
343
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
344
|
+
left2 (Union[str, LineStyle, None]):
|
|
345
|
+
Style for the secondary left border.
|
|
346
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
347
|
+
right (Union[str, LineStyle, None]):
|
|
348
|
+
Style for the right border.
|
|
349
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
350
|
+
between_columns (Union[str, LineStyle, None]):
|
|
351
|
+
Style for borders between columns.
|
|
352
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
353
|
+
between_rows (Union[str, LineStyle, None]):
|
|
354
|
+
Style for borders between rows.
|
|
355
|
+
Can be a string key for predefined styles or a LineStyle object.
|
|
356
|
+
"""
|
|
357
|
+
if isinstance(top, str):
|
|
358
|
+
self._bs_top = dtheme.linestyles.get(top)
|
|
359
|
+
elif isinstance(top, LineStyle):
|
|
360
|
+
self._bs_top = top.copy()
|
|
361
|
+
|
|
362
|
+
if isinstance(top2, str):
|
|
363
|
+
self._bs_top2 = dtheme.linestyles.get(top2)
|
|
364
|
+
elif isinstance(top2, LineStyle):
|
|
365
|
+
self._bs_top2 = top2.copy()
|
|
366
|
+
|
|
367
|
+
if isinstance(bottom, str):
|
|
368
|
+
self._bs_bottom = dtheme.linestyles.get(bottom)
|
|
369
|
+
elif isinstance(bottom, LineStyle):
|
|
370
|
+
self._bs_bottom = bottom.copy()
|
|
371
|
+
|
|
372
|
+
if isinstance(left, str):
|
|
373
|
+
self._bs_left = dtheme.linestyles.get(left)
|
|
374
|
+
elif isinstance(left, LineStyle):
|
|
375
|
+
self._bs_left = left.copy()
|
|
376
|
+
|
|
377
|
+
if isinstance(left2, str):
|
|
378
|
+
self._bs_left2 = dtheme.linestyles.get(left2)
|
|
379
|
+
elif isinstance(left2, LineStyle):
|
|
380
|
+
self._bs_left2 = left2.copy()
|
|
381
|
+
|
|
382
|
+
if isinstance(right, str):
|
|
383
|
+
self._bs_right = dtheme.linestyles.get(right)
|
|
384
|
+
elif isinstance(right, LineStyle):
|
|
385
|
+
self._bs_right = right.copy()
|
|
386
|
+
|
|
387
|
+
if isinstance(between_columns, str):
|
|
388
|
+
self._bs_between_columns = dtheme.linestyles.get(between_columns)
|
|
389
|
+
elif isinstance(between_columns, LineStyle):
|
|
390
|
+
self._bs_between_columns = between_columns.copy()
|
|
391
|
+
|
|
392
|
+
if isinstance(between_rows, str):
|
|
393
|
+
self._bs_between_rows = dtheme.linestyles.get(between_rows)
|
|
394
|
+
elif isinstance(between_rows, LineStyle):
|
|
395
|
+
self._bs_between_rows = between_rows.copy()
|
|
396
|
+
|
|
397
|
+
# draw
|
|
398
|
+
|
|
399
|
+
@error_handler
|
|
400
|
+
def draw(
|
|
401
|
+
self,
|
|
402
|
+
xy: Tuple[float, float],
|
|
403
|
+
width: float,
|
|
404
|
+
height: float,
|
|
405
|
+
data: List[List[Any]],
|
|
406
|
+
) -> None:
|
|
407
|
+
"""Draws the table with equal-sized cells.
|
|
408
|
+
|
|
409
|
+
Args:
|
|
410
|
+
xy (Tuple[float, float]): The coordinates where the table should be drawn.
|
|
411
|
+
width (float): The total width of the table.
|
|
412
|
+
height (float): The total height of the table.
|
|
413
|
+
data (List[List[Any]]): The data to be displayed in the table.
|
|
414
|
+
"""
|
|
415
|
+
num_rows = len(data)
|
|
416
|
+
num_cols = len(data[0])
|
|
417
|
+
|
|
418
|
+
column_widths = [width / num_cols] * num_cols
|
|
419
|
+
row_heights = [height / num_rows] * num_rows
|
|
420
|
+
self.draw_flexible(
|
|
421
|
+
xy=xy,
|
|
422
|
+
column_widths=column_widths,
|
|
423
|
+
row_heights=row_heights,
|
|
424
|
+
data=data,
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
@error_handler
|
|
428
|
+
def draw_flexible(
|
|
429
|
+
self,
|
|
430
|
+
xy: Tuple[float, float],
|
|
431
|
+
column_widths: List[float],
|
|
432
|
+
row_heights: List[float],
|
|
433
|
+
data: List[List[Any]],
|
|
434
|
+
) -> None:
|
|
435
|
+
"""Draws the table with flexible cell sizes.
|
|
436
|
+
|
|
437
|
+
Args:
|
|
438
|
+
xy (Tuple[float, float]): The coordinates where the table should be drawn.
|
|
439
|
+
column_widths (List[float]): A list of widths for each column.
|
|
440
|
+
row_heights (List[float]): A list of heights for each row.
|
|
441
|
+
data (List[List[Any]]): The data to be displayed in the table.
|
|
442
|
+
"""
|
|
443
|
+
# create blank matrix
|
|
444
|
+
default_textstyle = dtheme.shapetextstyles.get()
|
|
445
|
+
matrix: List[List[_CellInfo]] = []
|
|
446
|
+
for row_data in data:
|
|
447
|
+
row: List[_CellInfo] = []
|
|
448
|
+
for column in row_data:
|
|
449
|
+
cell = _CellInfo(
|
|
450
|
+
xy=(0, 0),
|
|
451
|
+
width=0,
|
|
452
|
+
height=0,
|
|
453
|
+
background_color=Colors.White,
|
|
454
|
+
textstyle=default_textstyle,
|
|
455
|
+
text=str(column),
|
|
456
|
+
)
|
|
457
|
+
row.append(cell)
|
|
458
|
+
matrix.append(row)
|
|
459
|
+
|
|
460
|
+
# update matrix
|
|
461
|
+
self._update_cell_xy_size(
|
|
462
|
+
xy,
|
|
463
|
+
column_widths=column_widths,
|
|
464
|
+
row_heights=row_heights,
|
|
465
|
+
matrix=matrix,
|
|
466
|
+
)
|
|
467
|
+
self._update_cell_style(matrix)
|
|
468
|
+
|
|
469
|
+
# draw matrix
|
|
470
|
+
self._draw_cells(matrix=matrix)
|
|
471
|
+
|
|
472
|
+
# draw border line
|
|
473
|
+
self._draw_border_lines(
|
|
474
|
+
xy=xy,
|
|
475
|
+
column_widths=column_widths,
|
|
476
|
+
row_heights=row_heights,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
# private
|
|
480
|
+
|
|
481
|
+
@staticmethod
|
|
482
|
+
def _update_cell_xy_size(
|
|
483
|
+
xy: Tuple[float, float],
|
|
484
|
+
column_widths: List[float],
|
|
485
|
+
row_heights: List[float],
|
|
486
|
+
matrix: List[List[_CellInfo]],
|
|
487
|
+
) -> None:
|
|
488
|
+
x = xy[0]
|
|
489
|
+
y = xy[1]
|
|
490
|
+
for i, row_hight in enumerate(row_heights):
|
|
491
|
+
for j, column_width in enumerate(column_widths):
|
|
492
|
+
cell = matrix[i][j]
|
|
493
|
+
cell.xy = (x + column_width / 2, y - row_hight / 2)
|
|
494
|
+
cell.width = column_width
|
|
495
|
+
cell.height = row_hight
|
|
496
|
+
x += column_width
|
|
497
|
+
x = xy[0]
|
|
498
|
+
y -= row_hight
|
|
499
|
+
|
|
500
|
+
def _update_cell_style( # noqa: C901
|
|
501
|
+
self,
|
|
502
|
+
matrix: List[List[_CellInfo]],
|
|
503
|
+
) -> None:
|
|
504
|
+
def style_even_odd(
|
|
505
|
+
even_background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
506
|
+
even_textstyle: ShapeTextStyle,
|
|
507
|
+
odd_background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
508
|
+
odd_textstyle: ShapeTextStyle,
|
|
509
|
+
) -> None:
|
|
510
|
+
for i, row in enumerate(matrix):
|
|
511
|
+
if i % 2 == 0:
|
|
512
|
+
for c in row:
|
|
513
|
+
c.background_color = even_background_color
|
|
514
|
+
c.textstyle = even_textstyle
|
|
515
|
+
else:
|
|
516
|
+
for c in row:
|
|
517
|
+
c.background_color = odd_background_color
|
|
518
|
+
c.textstyle = odd_textstyle
|
|
519
|
+
|
|
520
|
+
def style_range(
|
|
521
|
+
background_color: Union[Tuple[int, int, int], Tuple[int, int, int, float]],
|
|
522
|
+
textstyle: ShapeTextStyle,
|
|
523
|
+
rows: Optional[List[int]],
|
|
524
|
+
columns: Optional[List[int]],
|
|
525
|
+
) -> None:
|
|
526
|
+
if rows is None:
|
|
527
|
+
rows = list(range(len(matrix)))
|
|
528
|
+
if columns is None:
|
|
529
|
+
columns = list(range(len(matrix[0])))
|
|
530
|
+
|
|
531
|
+
for i, row in enumerate(matrix):
|
|
532
|
+
for j, col in enumerate(row):
|
|
533
|
+
if i not in rows:
|
|
534
|
+
continue
|
|
535
|
+
if j not in columns:
|
|
536
|
+
continue
|
|
537
|
+
col.background_color = background_color
|
|
538
|
+
col.textstyle = textstyle
|
|
539
|
+
|
|
540
|
+
for cso in self._cell_style_orders:
|
|
541
|
+
if cso.order == "even_odd":
|
|
542
|
+
if cso.background_color2 is None:
|
|
543
|
+
raise ValueError("Drawlib Internal error.")
|
|
544
|
+
if cso.textstyle2 is None:
|
|
545
|
+
raise ValueError("Drawlib Internal error.")
|
|
546
|
+
|
|
547
|
+
style_even_odd(
|
|
548
|
+
cso.background_color1,
|
|
549
|
+
cso.textstyle1,
|
|
550
|
+
cso.background_color2,
|
|
551
|
+
cso.textstyle2,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
else:
|
|
555
|
+
style_range(
|
|
556
|
+
cso.background_color1,
|
|
557
|
+
cso.textstyle1,
|
|
558
|
+
cso.rows,
|
|
559
|
+
cso.columns,
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
@staticmethod
|
|
563
|
+
def _draw_cells(
|
|
564
|
+
matrix: List[List[_CellInfo]],
|
|
565
|
+
) -> None:
|
|
566
|
+
for row in matrix:
|
|
567
|
+
for col in row:
|
|
568
|
+
cell_xy = col.xy
|
|
569
|
+
width = col.width
|
|
570
|
+
height = col.height
|
|
571
|
+
bg_color = col.background_color
|
|
572
|
+
textstyle = col.textstyle
|
|
573
|
+
text = col.text
|
|
574
|
+
|
|
575
|
+
rectangle(
|
|
576
|
+
xy=cell_xy,
|
|
577
|
+
width=width,
|
|
578
|
+
height=height,
|
|
579
|
+
style=ShapeStyle(
|
|
580
|
+
lwidth=0,
|
|
581
|
+
lcolor=Colors.Transparent,
|
|
582
|
+
fcolor=bg_color,
|
|
583
|
+
),
|
|
584
|
+
text=text,
|
|
585
|
+
textstyle=textstyle,
|
|
586
|
+
)
|
|
587
|
+
|
|
588
|
+
def _draw_border_lines( # noqa: C901
|
|
589
|
+
self,
|
|
590
|
+
xy: Tuple[float, float],
|
|
591
|
+
column_widths: List[float],
|
|
592
|
+
row_heights: List[float],
|
|
593
|
+
) -> None:
|
|
594
|
+
bs_top1: Optional[LineStyle] = None
|
|
595
|
+
if self._bs_top is not None:
|
|
596
|
+
bs_top1 = self._bs_top
|
|
597
|
+
elif self._bs_between_columns is not None:
|
|
598
|
+
bs_top1 = self._bs_between_columns
|
|
599
|
+
|
|
600
|
+
bs_top2: Optional[LineStyle] = None
|
|
601
|
+
if self._bs_top2 is not None:
|
|
602
|
+
bs_top2 = self._bs_top2
|
|
603
|
+
elif self._bs_between_columns is not None:
|
|
604
|
+
bs_top2 = self._bs_between_columns
|
|
605
|
+
|
|
606
|
+
bs_bottom: Optional[LineStyle] = None
|
|
607
|
+
if self._bs_bottom is not None:
|
|
608
|
+
bs_bottom = self._bs_bottom
|
|
609
|
+
elif self._bs_between_columns is not None:
|
|
610
|
+
bs_bottom = self._bs_between_columns
|
|
611
|
+
|
|
612
|
+
bs_left1: Optional[LineStyle] = None
|
|
613
|
+
if self._bs_left is not None:
|
|
614
|
+
bs_left1 = self._bs_left
|
|
615
|
+
elif self._bs_between_rows is not None:
|
|
616
|
+
bs_left1 = self._bs_between_rows
|
|
617
|
+
|
|
618
|
+
bs_left2: Optional[LineStyle] = None
|
|
619
|
+
if self._bs_left2 is not None:
|
|
620
|
+
bs_left2 = self._bs_left2
|
|
621
|
+
elif self._bs_between_rows is not None:
|
|
622
|
+
bs_left2 = self._bs_between_rows
|
|
623
|
+
|
|
624
|
+
bs_right: Optional[LineStyle] = None
|
|
625
|
+
if self._bs_right is not None:
|
|
626
|
+
bs_right = self._bs_right
|
|
627
|
+
elif self._bs_between_rows is not None:
|
|
628
|
+
bs_right = self._bs_between_rows
|
|
629
|
+
|
|
630
|
+
# draw rows
|
|
631
|
+
x = xy[0]
|
|
632
|
+
y1 = xy[1]
|
|
633
|
+
y2 = xy[1] - sum(row_heights)
|
|
634
|
+
for i, col_width in enumerate(column_widths):
|
|
635
|
+
if i == 0:
|
|
636
|
+
if bs_left1 is not None:
|
|
637
|
+
line((x, y1), (x, y2), style=bs_left1)
|
|
638
|
+
elif i == 1:
|
|
639
|
+
if bs_left2 is not None:
|
|
640
|
+
line((x, y1), (x, y2), style=bs_left2)
|
|
641
|
+
elif i == len(column_widths) - 1:
|
|
642
|
+
# right -1
|
|
643
|
+
if self._bs_between_columns:
|
|
644
|
+
line((x, y1), (x, y2), style=self._bs_between_columns)
|
|
645
|
+
|
|
646
|
+
# right. It is last
|
|
647
|
+
x += col_width
|
|
648
|
+
if bs_right is not None:
|
|
649
|
+
line((x, y1), (x, y2), style=bs_right)
|
|
650
|
+
elif self._bs_between_columns:
|
|
651
|
+
line((x, y1), (x, y2), style=self._bs_between_columns)
|
|
652
|
+
|
|
653
|
+
elif self._bs_between_columns:
|
|
654
|
+
line((x, y1), (x, y2), style=self._bs_between_columns)
|
|
655
|
+
|
|
656
|
+
x += col_width
|
|
657
|
+
|
|
658
|
+
y = xy[1]
|
|
659
|
+
x1 = xy[0]
|
|
660
|
+
x2 = xy[0] + sum(column_widths)
|
|
661
|
+
for i, row_height in enumerate(row_heights):
|
|
662
|
+
if i == 0:
|
|
663
|
+
if bs_top1 is not None:
|
|
664
|
+
line((x1, y), (x2, y), style=bs_top1)
|
|
665
|
+
elif i == 1:
|
|
666
|
+
if bs_top2 is not None:
|
|
667
|
+
line((x1, y), (x2, y), style=bs_top2)
|
|
668
|
+
elif i == len(row_heights) - 1:
|
|
669
|
+
# bottom -1
|
|
670
|
+
if self._bs_between_rows:
|
|
671
|
+
line((x1, y), (x2, y), style=self._bs_between_rows)
|
|
672
|
+
|
|
673
|
+
# right. It is last
|
|
674
|
+
y -= row_height
|
|
675
|
+
if bs_bottom is not None:
|
|
676
|
+
line((x1, y), (x2, y), style=bs_bottom)
|
|
677
|
+
elif self._bs_between_rows:
|
|
678
|
+
line((x1, y), (x2, y), style=self._bs_between_rows)
|
|
679
|
+
|
|
680
|
+
elif self._bs_between_rows:
|
|
681
|
+
line((x1, y), (x2, y), style=self._bs_between_rows)
|
|
682
|
+
|
|
683
|
+
y -= row_height
|